From c6f3e9d79cf849623e6c4f25e02e17cdfab07b7c Mon Sep 17 00:00:00 2001 From: mlugg Date: Mon, 25 Mar 2024 19:02:21 +0000 Subject: [PATCH 01/14] Zcu.Decl: remove `ty` field `Decl` can no longer store un-interned values, so this field is now unnecessary. The type can instead be fetched with the new `typeOf` helper method, which just gets the type of the Decl's `Value`. --- src/InternPool.zig | 4 --- src/Module.zig | 51 ++++++++++++++++++------------------ src/Sema.zig | 33 +++++++++++------------ src/TypedValue.zig | 2 +- src/Value.zig | 2 +- src/arch/aarch64/CodeGen.zig | 2 +- src/arch/arm/CodeGen.zig | 2 +- src/arch/riscv64/CodeGen.zig | 2 +- src/arch/sparc64/CodeGen.zig | 2 +- src/arch/wasm/CodeGen.zig | 21 ++++++++------- src/arch/x86_64/CodeGen.zig | 2 +- src/codegen.zig | 6 ++--- src/codegen/c.zig | 27 ++++++++++--------- src/codegen/llvm.zig | 27 ++++++++++--------- src/codegen/spirv.zig | 20 +++++++------- src/link/C.zig | 2 +- src/link/Coff.zig | 6 ++--- src/link/Dwarf.zig | 6 ++--- src/link/Elf/ZigObject.zig | 6 ++--- src/link/MachO/ZigObject.zig | 4 +-- src/link/Plan9.zig | 6 ++--- src/link/SpirV.zig | 2 +- src/link/Wasm/ZigObject.zig | 8 +++--- 23 files changed, 120 insertions(+), 123 deletions(-) diff --git a/src/InternPool.zig b/src/InternPool.zig index daec1f5c0db4..e4132e577ee7 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -6581,7 +6581,6 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey) generic_owner, func_index, func_extra_index, - func_ty, arg.alignment, arg.section, ); @@ -6711,7 +6710,6 @@ pub fn getFuncInstanceIes( generic_owner, func_index, func_extra_index, - func_ty, arg.alignment, arg.section, ); @@ -6723,7 +6721,6 @@ fn finishFuncInstance( generic_owner: Index, func_index: Index, func_extra_index: u32, - func_ty: Index, alignment: Alignment, section: OptionalNullTerminatedString, ) Allocator.Error!Index { @@ -6735,7 +6732,6 @@ fn finishFuncInstance( .src_line = fn_owner_decl.src_line, .has_tv = true, .owns_tv = true, - .ty = @import("type.zig").Type.fromInterned(func_ty), .val = @import("Value.zig").fromInterned(func_index), .alignment = alignment, .@"linksection" = section, diff --git a/src/Module.zig b/src/Module.zig index 7d91ceb7d1c4..9cbb2cc89af8 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -330,9 +330,6 @@ const ValueArena = struct { pub const Decl = struct { name: InternPool.NullTerminatedString, - /// The most recent Type of the Decl after a successful semantic analysis. - /// Populated when `has_tv`. - ty: Type, /// The most recent Value of the Decl after a successful semantic analysis. /// Populated when `has_tv`. val: Value, @@ -487,20 +484,28 @@ pub const Decl = struct { zcu.namespacePtr(decl.src_namespace).fullyQualifiedName(zcu, decl.name); } - pub fn typedValue(decl: Decl) error{AnalysisFail}!TypedValue { + pub fn typeOf(decl: Decl, zcu: *const Zcu) Type { + assert(decl.has_tv); + return Type.fromInterned(zcu.intern_pool.typeOf(decl.val.toIntern())); + } + + pub fn typedValue(decl: Decl, zcu: *const Zcu) error{AnalysisFail}!TypedValue { if (!decl.has_tv) return error.AnalysisFail; - return TypedValue{ .ty = decl.ty, .val = decl.val }; + return .{ + .ty = decl.typeOf(zcu), + .val = decl.val, + }; } pub fn internValue(decl: *Decl, zcu: *Zcu) Allocator.Error!InternPool.Index { assert(decl.has_tv); - const ip_index = try decl.val.intern(decl.ty, zcu); + const ip_index = try decl.val.intern(decl.typeOf(zcu), zcu); decl.val = Value.fromInterned(ip_index); return ip_index; } pub fn isFunction(decl: Decl, zcu: *const Zcu) !bool { - const tv = try decl.typedValue(); + const tv = try decl.typedValue(zcu); return tv.ty.zigTypeTag(zcu) == .Fn; } @@ -590,7 +595,7 @@ pub const Decl = struct { @tagName(decl.analysis), }); if (decl.has_tv) { - std.debug.print(" ty={} val={}", .{ decl.ty, decl.val }); + std.debug.print(" val={}", .{decl.val}); } std.debug.print("\n", .{}); } @@ -615,7 +620,7 @@ pub const Decl = struct { pub fn getAlignment(decl: Decl, zcu: *Zcu) Alignment { assert(decl.has_tv); if (decl.alignment != .none) return decl.alignment; - return decl.ty.abiAlignment(zcu); + return decl.typeOf(zcu).abiAlignment(zcu); } /// Upgrade a `LazySrcLoc` to a `SrcLoc` based on the `Decl` provided. @@ -3525,7 +3530,6 @@ fn semaFile(mod: *Module, file: *File) SemaError!void { new_decl.src_line = 0; new_decl.is_pub = true; new_decl.is_exported = false; - new_decl.ty = Type.type; new_decl.alignment = .none; new_decl.@"linksection" = .none; new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive. @@ -3594,7 +3598,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { const old_has_tv = decl.has_tv; // The following values are ignored if `!old_has_tv` - const old_ty = decl.ty; + const old_ty = decl.typeOf(mod); const old_val = decl.val; const old_align = decl.alignment; const old_linksection = decl.@"linksection"; @@ -3716,7 +3720,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { return sema.fail(&block_scope, ty_src, "type {} has no namespace", .{ty.fmt(mod)}); } - decl.ty = Type.fromInterned(InternPool.Index.type_type); decl.val = ty.toValue(); decl.alignment = .none; decl.@"linksection" = .none; @@ -3760,7 +3763,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { }, } - decl.ty = decl_tv.ty; decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod))); // Function linksection, align, and addrspace were already set by Sema if (!is_func) { @@ -3806,10 +3808,10 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { decl.analysis = .complete; const result: SemaDeclResult = if (old_has_tv) .{ - .invalidate_decl_val = !decl.ty.eql(old_ty, mod) or - !decl.val.eql(old_val, decl.ty, mod) or + .invalidate_decl_val = !decl_tv.ty.eql(old_ty, mod) or + !decl.val.eql(old_val, decl_tv.ty, mod) or is_inline != old_is_inline, - .invalidate_decl_ref = !decl.ty.eql(old_ty, mod) or + .invalidate_decl_ref = !decl_tv.ty.eql(old_ty, mod) or decl.alignment != old_align or decl.@"linksection" != old_linksection or decl.@"addrspace" != old_addrspace or @@ -3819,11 +3821,11 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { .invalidate_decl_ref = true, }; - const has_runtime_bits = queue_linker_work and (is_func or try sema.typeHasRuntimeBits(decl.ty)); + const has_runtime_bits = queue_linker_work and (is_func or try sema.typeHasRuntimeBits(decl_tv.ty)); if (has_runtime_bits) { // Needed for codegen_decl which will call updateDecl and then the // codegen backend wants full access to the Decl Type. - try sema.resolveTypeFully(decl.ty); + try sema.resolveTypeFully(decl_tv.ty); try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index }); @@ -3850,7 +3852,7 @@ fn semaAnonOwnerDecl(zcu: *Zcu, decl_index: Decl.Index) !SemaDeclResult { log.debug("semaAnonOwnerDecl '{d}'", .{@intFromEnum(decl_index)}); - switch (decl.ty.zigTypeTag(zcu)) { + switch (decl.typeOf(zcu).zigTypeTag(zcu)) { .Fn => @panic("TODO: update fn instance"), .Type => {}, else => unreachable, @@ -4479,7 +4481,7 @@ pub fn finalizeAnonDecl(mod: *Module, decl_index: Decl.Index) Allocator.Error!vo // if the Decl is referenced by an instruction or another constant. Otherwise, // the Decl will be garbage collected by the `codegen_decl` task instead of sent // to the linker. - if (mod.declPtr(decl_index).ty.isFnOrHasRuntimeBits(mod)) { + if (mod.declPtr(decl_index).typeOf(mod).isFnOrHasRuntimeBits(mod)) { try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = decl_index }); } } @@ -4563,7 +4565,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato // the runtime-known parameters only, not to be confused with the // generic_owner function type, which potentially has more parameters, // including comptime parameters. - const fn_ty = decl.ty; + const fn_ty = decl.typeOf(mod); const fn_ty_info = mod.typeToFunc(fn_ty).?; var sema: Sema = .{ @@ -4812,7 +4814,6 @@ pub fn allocateNewDecl( .src_line = undefined, .has_tv = false, .owns_tv = false, - .ty = undefined, .val = undefined, .alignment = undefined, .@"linksection" = .none, @@ -4889,7 +4890,6 @@ pub fn initNewAnonDecl( new_decl.name = name; new_decl.src_line = src_line; - new_decl.ty = typed_value.ty; new_decl.val = typed_value.val; new_decl.alignment = .none; new_decl.@"linksection" = .none; @@ -5419,7 +5419,7 @@ pub fn populateTestFunctions( try mod.ensureDeclAnalyzed(decl_index); } const decl = mod.declPtr(decl_index); - const test_fn_ty = decl.ty.slicePtrFieldType(mod).childType(mod); + const test_fn_ty = decl.typeOf(mod).slicePtrFieldType(mod).childType(mod); const array_decl_index = d: { // Add mod.test_functions to an array decl then make the test_functions @@ -5463,7 +5463,7 @@ pub fn populateTestFunctions( // func try mod.intern(.{ .ptr = .{ .ty = try mod.intern(.{ .ptr_type = .{ - .child = test_decl.ty.toIntern(), + .child = test_decl.typeOf(mod).toIntern(), .flags = .{ .is_const = true, }, @@ -5515,7 +5515,6 @@ pub fn populateTestFunctions( // Since we are replacing the Decl's value we must perform cleanup on the // previous value. - decl.ty = new_ty; decl.val = new_val; decl.has_tv = true; } diff --git a/src/Sema.zig b/src/Sema.zig index a14a0a0e0835..826988ee3491 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -6425,16 +6425,17 @@ pub fn analyzeExport( try mod.ensureDeclAnalyzed(exported_decl_index); const exported_decl = mod.declPtr(exported_decl_index); + const export_ty = exported_decl.typeOf(mod); - if (!try sema.validateExternType(exported_decl.ty, .other)) { + if (!try sema.validateExternType(export_ty, .other)) { const msg = msg: { - const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(mod)}); + const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{export_ty.fmt(mod)}); errdefer msg.destroy(gpa); const src_decl = mod.declPtr(block.src_decl); - try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), exported_decl.ty, .other); + try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), export_ty, .other); - try sema.addDeclaredHereNote(msg, exported_decl.ty); + try sema.addDeclaredHereNote(msg, export_ty); break :msg msg; }; return sema.failWithOwnedErrorMsg(block, msg); @@ -6503,7 +6504,7 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst } const fn_owner_decl = mod.funcOwnerDeclPtr(sema.func_index); - switch (fn_owner_decl.ty.fnCallingConvention(mod)) { + switch (fn_owner_decl.typeOf(mod).fnCallingConvention(mod)) { .Naked => return sema.fail(block, src, "@setAlignStack in naked function", .{}), .Inline => return sema.fail(block, src, "@setAlignStack in inline function", .{}), else => if (block.inlining != null) { @@ -7692,7 +7693,7 @@ fn analyzeCall( // comptime memory is mutated. const memoized_arg_values = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len); - const owner_info = mod.typeToFunc(fn_owner_decl.ty).?; + const owner_info = mod.typeToFunc(fn_owner_decl.typeOf(mod)).?; const new_param_types = try sema.arena.alloc(InternPool.Index, owner_info.param_types.len); var new_fn_info: InternPool.GetFuncTypeKey = .{ .param_types = new_param_types, @@ -7960,9 +7961,9 @@ fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Typ }); } const func_decl = mod.funcOwnerDeclPtr(sema.owner_func_index); - if (!func_ty.eql(func_decl.ty, mod)) { + if (!func_ty.eql(func_decl.typeOf(mod), mod)) { return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{ - func_ty.fmt(mod), func_decl.ty.fmt(mod), + func_ty.fmt(mod), func_decl.typeOf(mod).fmt(mod), }); } _ = try block.addUnOp(.ret, result); @@ -26641,7 +26642,7 @@ fn prepareSimplePanic(sema: *Sema, block: *Block) !void { // decl_index may be an alias; we must find the decl that actually // owns the function. try sema.ensureDeclAnalyzed(decl_index); - const tv = try mod.declPtr(decl_index).typedValue(); + const tv = try mod.declPtr(decl_index).typedValue(mod); try sema.declareDependency(.{ .decl_val = decl_index }); assert(tv.ty.zigTypeTag(mod) == .Fn); assert(try sema.fnHasRuntimeBits(tv.ty)); @@ -31374,16 +31375,16 @@ fn beginComptimePtrLoad( .ptr => |ptr| switch (ptr.addr) { .decl => |decl_index| blk: { const decl = mod.declPtr(decl_index); - const decl_tv = try decl.typedValue(); + const decl_tv = try decl.typedValue(mod); try sema.declareDependency(.{ .decl_val = decl_index }); if (decl.val.getVariable(mod) != null) return error.RuntimeLoad; - const layout_defined = decl.ty.hasWellDefinedLayout(mod); + const layout_defined = decl.typeOf(mod).hasWellDefinedLayout(mod); break :blk ComptimePtrLoadKit{ .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, .pointee = decl_tv, .is_mutable = false, - .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, + .ty_without_well_defined_layout = if (!layout_defined) decl.typeOf(mod) else null, }; }, .comptime_alloc => |alloc_index| kit: { @@ -32668,7 +32669,7 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn const mod = sema.mod; try sema.ensureDeclAnalyzed(decl_index); - const decl_tv = try mod.declPtr(decl_index).typedValue(); + const decl_tv = try mod.declPtr(decl_index).typedValue(mod); const owner_decl = mod.declPtr(switch (mod.intern_pool.indexToKey(decl_tv.val.toIntern())) { .variable => |variable| variable.decl, .extern_func => |extern_func| extern_func.decl, @@ -32697,7 +32698,7 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn fn maybeQueueFuncBodyAnalysis(sema: *Sema, decl_index: InternPool.DeclIndex) !void { const mod = sema.mod; const decl = mod.declPtr(decl_index); - const tv = try decl.typedValue(); + const tv = try decl.typedValue(mod); if (tv.ty.zigTypeTag(mod) != .Fn) return; if (!try sema.fnHasRuntimeBits(tv.ty)) return; const func_index = tv.val.toIntern(); @@ -36611,7 +36612,7 @@ fn resolveInferredErrorSet( // inferred error sets, each call gets an adhoc InferredErrorSet object, which // has no corresponding function body. const ies_func_owner_decl = mod.declPtr(func.owner_decl); - const ies_func_info = mod.typeToFunc(ies_func_owner_decl.ty).?; + const ies_func_info = mod.typeToFunc(ies_func_owner_decl.typeOf(mod)).?; // if ies declared by a inline function with generic return type, the return_type should be generic_poison, // because inline function does not create a new declaration, and the ies has been filled with analyzeCall, // so here we can simply skip this case. @@ -37629,7 +37630,6 @@ fn generateUnionTagTypeNumbered( .tag_mode = .explicit, }); - new_decl.ty = Type.type; new_decl.val = Value.fromInterned(enum_ty); try mod.finalizeAnonDecl(new_decl_index); @@ -37675,7 +37675,6 @@ fn generateUnionTagTypeSimple( const new_decl = mod.declPtr(new_decl_index); new_decl.owns_tv = true; - new_decl.ty = Type.type; new_decl.val = Value.fromInterned(enum_ty); try mod.finalizeAnonDecl(new_decl_index); diff --git a/src/TypedValue.zig b/src/TypedValue.zig index a502ed306c94..5d9c06241743 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -315,7 +315,7 @@ pub fn print( const decl = mod.declPtr(decl_index); if (level == 0) return writer.print("(decl '{}')", .{decl.name.fmt(ip)}); return print(.{ - .ty = decl.ty, + .ty = decl.typeOf(mod), .val = decl.val, }, writer, level - 1, mod); }, diff --git a/src/Value.zig b/src/Value.zig index 3707c33d46c9..c220f6d0d9c4 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -1585,7 +1585,7 @@ pub fn sliceLen(val: Value, mod: *Module) u64 { const ip = &mod.intern_pool; return switch (ip.indexToKey(val.toIntern())) { .ptr => |ptr| switch (ip.indexToKey(switch (ptr.addr) { - .decl => |decl| mod.declPtr(decl).ty.toIntern(), + .decl => |decl| mod.declPtr(decl).typeOf(mod).toIntern(), .comptime_alloc => @panic("TODO"), .anon_decl => |anon_decl| ip.typeOf(anon_decl.val), .comptime_field => |comptime_field| ip.typeOf(comptime_field), diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 59a9fb31aa11..9926f3ef7b9e 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -342,7 +342,7 @@ pub fn generate( const func = zcu.funcInfo(func_index); const fn_owner_decl = zcu.declPtr(func.owner_decl); assert(fn_owner_decl.has_tv); - const fn_type = fn_owner_decl.ty; + const fn_type = fn_owner_decl.typeOf(zcu); const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace); const target = &namespace.file_scope.mod.resolved_target.result; diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 43ffd1109726..ab1b41a25e80 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -349,7 +349,7 @@ pub fn generate( const func = zcu.funcInfo(func_index); const fn_owner_decl = zcu.declPtr(func.owner_decl); assert(fn_owner_decl.has_tv); - const fn_type = fn_owner_decl.ty; + const fn_type = fn_owner_decl.typeOf(zcu); const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace); const target = &namespace.file_scope.mod.resolved_target.result; diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 9e4870222d27..e7a872d616ab 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -230,7 +230,7 @@ pub fn generate( const func = zcu.funcInfo(func_index); const fn_owner_decl = zcu.declPtr(func.owner_decl); assert(fn_owner_decl.has_tv); - const fn_type = fn_owner_decl.ty; + const fn_type = fn_owner_decl.typeOf(zcu); const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace); const target = &namespace.file_scope.mod.resolved_target.result; diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index b6b3f30879d8..d3417fd6decb 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -273,7 +273,7 @@ pub fn generate( const func = zcu.funcInfo(func_index); const fn_owner_decl = zcu.declPtr(func.owner_decl); assert(fn_owner_decl.has_tv); - const fn_type = fn_owner_decl.ty; + const fn_type = fn_owner_decl.typeOf(zcu); const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace); const target = &namespace.file_scope.mod.resolved_target.result; diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 6d12382d8b0f..e90a68bea542 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1243,12 +1243,12 @@ pub fn generate( fn genFunc(func: *CodeGen) InnerError!void { const mod = func.bin_file.base.comp.module.?; const ip = &mod.intern_pool; - const fn_info = mod.typeToFunc(func.decl.ty).?; + const fn_info = mod.typeToFunc(func.decl.typeOf(mod)).?; var func_type = try genFunctype(func.gpa, fn_info.cc, fn_info.param_types.get(ip), Type.fromInterned(fn_info.return_type), mod); defer func_type.deinit(func.gpa); _ = try func.bin_file.storeDeclType(func.decl_index, func_type); - var cc_result = try func.resolveCallingConventionValues(func.decl.ty); + var cc_result = try func.resolveCallingConventionValues(func.decl.typeOf(mod)); defer cc_result.deinit(func.gpa); func.args = cc_result.args; @@ -2087,7 +2087,7 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const mod = func.bin_file.base.comp.module.?; const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const operand = try func.resolveInst(un_op); - const fn_info = mod.typeToFunc(func.decl.ty).?; + const fn_info = mod.typeToFunc(func.decl.typeOf(mod)).?; const ret_ty = Type.fromInterned(fn_info.return_type); // result must be stored in the stack and we return a pointer @@ -2135,7 +2135,7 @@ fn airRetPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { break :result try func.allocStack(Type.usize); // create pointer to void } - const fn_info = mod.typeToFunc(func.decl.ty).?; + const fn_info = mod.typeToFunc(func.decl.typeOf(mod)).?; if (firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), mod)) { break :result func.return_value; } @@ -2152,7 +2152,7 @@ fn airRetLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const operand = try func.resolveInst(un_op); const ret_ty = func.typeOf(un_op).childType(mod); - const fn_info = mod.typeToFunc(func.decl.ty).?; + const fn_info = mod.typeToFunc(func.decl.typeOf(mod)).?; if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { if (ret_ty.isError(mod)) { try func.addImm32(0); @@ -2193,7 +2193,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif break :blk function.owner_decl; } else if (func_val.getExternFunc(mod)) |extern_func| { const ext_decl = mod.declPtr(extern_func.decl); - const ext_info = mod.typeToFunc(ext_decl.ty).?; + const ext_info = mod.typeToFunc(ext_decl.typeOf(mod)).?; var func_type = try genFunctype(func.gpa, ext_info.cc, ext_info.param_types.get(ip), Type.fromInterned(ext_info.return_type), mod); defer func_type.deinit(func.gpa); const atom_index = try func.bin_file.getOrCreateAtomForDecl(extern_func.decl); @@ -2530,7 +2530,7 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const mod = func.bin_file.base.comp.module.?; const arg_index = func.arg_index; const arg = func.args[arg_index]; - const cc = mod.typeToFunc(func.decl.ty).?.cc; + const cc = mod.typeToFunc(func.decl.typeOf(mod)).?.cc; const arg_ty = func.typeOfIndex(inst); if (cc == .C) { const arg_classes = abi.classifyType(arg_ty, mod); @@ -3122,7 +3122,7 @@ fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: InternPool.Dec const mod = func.bin_file.base.comp.module.?; const decl = mod.declPtr(decl_index); try mod.markDeclAlive(decl); - const ptr_ty = try mod.singleMutPtrType(decl.ty); + const ptr_ty = try mod.singleMutPtrType(decl.typeOf(mod)); return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset); } @@ -3173,7 +3173,8 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: InternPool.Decl return func.lowerDeclRefValue(tv, func_val.decl, offset); } } - if (decl.ty.zigTypeTag(mod) != .Fn and !decl.ty.hasRuntimeBitsIgnoreComptime(mod)) { + const decl_ty = decl.typeOf(mod); + if (decl_ty.zigTypeTag(mod) != .Fn and !decl_ty.hasRuntimeBitsIgnoreComptime(mod)) { return WValue{ .imm32 = 0xaaaaaaaa }; } @@ -3182,7 +3183,7 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: InternPool.Decl const atom = func.bin_file.getAtom(atom_index); const target_sym_index = @intFromEnum(atom.sym_index); - if (decl.ty.zigTypeTag(mod) == .Fn) { + if (decl_ty.zigTypeTag(mod) == .Fn) { return WValue{ .function_index = target_sym_index }; } else if (offset == 0) { return WValue{ .memory = target_sym_index }; diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 7db294a37b5c..273358a6d247 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -808,7 +808,7 @@ pub fn generate( const func = zcu.funcInfo(func_index); const fn_owner_decl = zcu.declPtr(func.owner_decl); assert(fn_owner_decl.has_tv); - const fn_type = fn_owner_decl.ty; + const fn_type = fn_owner_decl.typeOf(zcu); const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace); const mod = namespace.file_scope.mod; diff --git a/src/codegen.zig b/src/codegen.zig index 60152707397f..5bc0d1a81f47 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -829,8 +829,8 @@ fn lowerDeclRef( const target = namespace.file_scope.mod.resolved_target.result; const ptr_width = target.ptrBitWidth(); - const is_fn_body = decl.ty.zigTypeTag(zcu) == .Fn; - if (!is_fn_body and !decl.ty.hasRuntimeBits(zcu)) { + const is_fn_body = decl.typeOf(zcu).zigTypeTag(zcu) == .Fn; + if (!is_fn_body and !decl.typeOf(zcu).hasRuntimeBits(zcu)) { try code.appendNTimes(0xaa, @divExact(ptr_width, 8)); return Result.ok; } @@ -932,7 +932,7 @@ fn genDeclRef( }; const decl = zcu.declPtr(decl_index); - if (!decl.ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { + if (!decl.typeOf(zcu).isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { const imm: u64 = switch (ptr_bytes) { 1 => 0xaa, 2 => 0xaaaa, diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 9b856de111f6..32ad38cd4d71 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -657,7 +657,7 @@ pub const DeclGen = struct { assert(decl.has_tv); // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. - if (ty.isPtrAtRuntime(mod) and !decl.ty.isFnOrHasRuntimeBits(mod)) { + if (ty.isPtrAtRuntime(mod) and !decl.typeOf(mod).isFnOrHasRuntimeBits(mod)) { return dg.writeCValue(writer, .{ .undef = ty }); } @@ -673,7 +673,7 @@ pub const DeclGen = struct { // them). The analysis until now should ensure that the C function // pointers are compatible. If they are not, then there is a bug // somewhere and we should let the C compiler tell us about it. - const need_typecast = if (ty.castPtrToFn(mod)) |_| false else !ty.childType(mod).eql(decl.ty, mod); + const need_typecast = if (ty.castPtrToFn(mod)) |_| false else !ty.childType(mod).eql(decl.typeOf(mod), mod); if (need_typecast) { try writer.writeAll("(("); try dg.renderType(writer, ty); @@ -1588,9 +1588,10 @@ pub const DeclGen = struct { const ip = &mod.intern_pool; const fn_decl = mod.declPtr(fn_decl_index); - const fn_cty_idx = try dg.typeToIndex(fn_decl.ty, kind); + const fn_ty = fn_decl.typeOf(mod); + const fn_cty_idx = try dg.typeToIndex(fn_ty, kind); - const fn_info = mod.typeToFunc(fn_decl.ty).?; + const fn_info = mod.typeToFunc(fn_ty).?; if (fn_info.cc == .Naked) { switch (kind) { .forward => try w.writeAll("zig_naked_decl "), @@ -1971,7 +1972,7 @@ pub const DeclGen = struct { ) !void { const decl = dg.module.declPtr(decl_index); const fwd = dg.fwdDeclWriter(); - const is_global = variable.is_extern or dg.declIsGlobal(.{ .ty = decl.ty, .val = decl.val }); + const is_global = variable.is_extern or dg.declIsGlobal(.{ .ty = decl.typeOf(dg.module), .val = decl.val }); try fwd.writeAll(if (is_global) "zig_extern " else "static "); const maybe_exports = dg.module.decl_exports.get(decl_index); const export_weak_linkage = if (maybe_exports) |exports| @@ -1982,7 +1983,7 @@ pub const DeclGen = struct { if (variable.is_threadlocal) try fwd.writeAll("zig_threadlocal "); try dg.renderTypeAndName( fwd, - decl.ty, + decl.typeOf(dg.module), .{ .decl = decl_index }, CQualifiers.init(.{ .@"const" = variable.is_const }), decl.alignment, @@ -2656,7 +2657,7 @@ fn genExports(o: *Object) !void { .anon, .flush => return, }; const decl = mod.declPtr(decl_index); - const tv: TypedValue = .{ .ty = decl.ty, .val = Value.fromInterned((try decl.internValue(mod))) }; + const tv: TypedValue = .{ .ty = decl.typeOf(mod), .val = Value.fromInterned((try decl.internValue(mod))) }; const fwd = o.dg.fwdDeclWriter(); const exports = mod.decl_exports.get(decl_index) orelse return; @@ -2687,7 +2688,7 @@ fn genExports(o: *Object) !void { const export_name = ip.stringToSlice(@"export".opts.name); try o.dg.renderTypeAndName( fwd, - decl.ty, + decl.typeOf(mod), .{ .identifier = export_name }, CQualifiers.init(.{ .@"const" = is_variable_const }), decl.alignment, @@ -2769,7 +2770,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { }, .never_tail, .never_inline => |fn_decl_index| { const fn_decl = mod.declPtr(fn_decl_index); - const fn_cty = try o.dg.typeToCType(fn_decl.ty, .complete); + const fn_cty = try o.dg.typeToCType(fn_decl.typeOf(mod), .complete); const fn_info = fn_cty.cast(CType.Payload.Function).?.data; const fwd_decl_writer = o.dg.fwdDeclWriter(); @@ -2806,7 +2807,7 @@ pub fn genFunc(f: *Function) !void { const decl_index = o.dg.pass.decl; const decl = mod.declPtr(decl_index); const tv: TypedValue = .{ - .ty = decl.ty, + .ty = decl.typeOf(mod), .val = decl.val, }; @@ -2893,7 +2894,7 @@ pub fn genDecl(o: *Object) !void { const mod = o.dg.module; const decl_index = o.dg.pass.decl; const decl = mod.declPtr(decl_index); - const tv: TypedValue = .{ .ty = decl.ty, .val = Value.fromInterned((try decl.internValue(mod))) }; + const tv: TypedValue = .{ .ty = decl.typeOf(mod), .val = Value.fromInterned((try decl.internValue(mod))) }; if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return; if (tv.val.getExternFunc(mod)) |_| { @@ -2979,7 +2980,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { const decl_index = dg.pass.decl; const decl = mod.declPtr(decl_index); const tv: TypedValue = .{ - .ty = decl.ty, + .ty = decl.typeOf(mod), .val = decl.val, }; const writer = dg.fwdDeclWriter(); @@ -7392,7 +7393,7 @@ fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue { const inst_ty = f.typeOfIndex(inst); const decl_index = f.object.dg.pass.decl; const decl = mod.declPtr(decl_index); - const fn_cty = try f.typeToCType(decl.ty, .complete); + const fn_cty = try f.typeToCType(decl.typeOf(mod), .complete); const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len; const writer = f.object.writer(); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 7c198a77330c..cef6a9f7f357 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1384,7 +1384,7 @@ pub const Object = struct { const decl = zcu.declPtr(decl_index); const namespace = zcu.namespacePtr(decl.src_namespace); const owner_mod = namespace.file_scope.mod; - const fn_info = zcu.typeToFunc(decl.ty).?; + const fn_info = zcu.typeToFunc(decl.typeOf(zcu)).?; const target = zcu.getTarget(); const ip = &zcu.intern_pool; @@ -1659,7 +1659,7 @@ pub const Object = struct { const line_number = decl.src_line + 1; const is_internal_linkage = decl.val.getExternFunc(zcu) == null and !zcu.decl_exports.contains(decl_index); - const debug_decl_type = try o.lowerDebugType(decl.ty); + const debug_decl_type = try o.lowerDebugType(decl.typeOf(zcu)); const subprogram = try o.builder.debugSubprogram( file, @@ -2881,7 +2881,7 @@ pub const Object = struct { const decl = zcu.declPtr(decl_index); const namespace = zcu.namespacePtr(decl.src_namespace); const owner_mod = namespace.file_scope.mod; - const zig_fn_type = decl.ty; + const zig_fn_type = decl.typeOf(zcu); const gop = try o.decl_map.getOrPut(gpa, decl_index); if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.function; @@ -3112,7 +3112,7 @@ pub const Object = struct { try o.builder.strtabString(mod.intern_pool.stringToSlice( if (is_extern) decl.name else try decl.fullyQualifiedName(mod), )), - try o.lowerType(decl.ty), + try o.lowerType(decl.typeOf(mod)), toLlvmGlobalAddressSpace(decl.@"addrspace", mod.getTarget()), ); gop.value_ptr.* = variable_index.ptrConst(&o.builder).global; @@ -4263,7 +4263,7 @@ pub const Object = struct { const mod = o.module; const decl = mod.declPtr(decl_index); try mod.markDeclAlive(decl); - const ptr_ty = try mod.singleMutPtrType(decl.ty); + const ptr_ty = try mod.singleMutPtrType(decl.typeOf(mod)); return o.lowerDeclRefValue(ptr_ty, decl_index); } @@ -4450,9 +4450,10 @@ pub const Object = struct { } } - const is_fn_body = decl.ty.zigTypeTag(mod) == .Fn; - if ((!is_fn_body and !decl.ty.hasRuntimeBits(mod)) or - (is_fn_body and mod.typeToFunc(decl.ty).?.is_generic)) return o.lowerPtrToVoid(ty); + const decl_ty = decl.typeOf(mod); + const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn; + if ((!is_fn_body and !decl_ty.hasRuntimeBits(mod)) or + (is_fn_body and mod.typeToFunc(decl_ty).?.is_generic)) return o.lowerPtrToVoid(ty); try mod.markDeclAlive(decl); @@ -4740,7 +4741,7 @@ pub const DeclGen = struct { debug_file, // File debug_file, // Scope line_number, - try o.lowerDebugType(decl.ty), + try o.lowerDebugType(decl.typeOf(zcu)), variable_index, .{ .local = is_internal_linkage }, ); @@ -5530,7 +5531,7 @@ pub const FuncGen = struct { const mod = o.module; const msg_decl_index = mod.panic_messages[@intFromEnum(panic_id)].unwrap().?; const msg_decl = mod.declPtr(msg_decl_index); - const msg_len = msg_decl.ty.childType(mod).arrayLen(mod); + const msg_len = msg_decl.typeOf(mod).childType(mod).arrayLen(mod); const msg_ptr = try o.lowerValue(try msg_decl.internValue(mod)); const null_opt_addr_global = try fg.resolveNullOptUsize(); const target = mod.getTarget(); @@ -5544,7 +5545,7 @@ pub const FuncGen = struct { // ) const panic_func = mod.funcInfo(mod.panic_func_index); const panic_decl = mod.declPtr(panic_func.owner_decl); - const fn_info = mod.typeToFunc(panic_decl.ty).?; + const fn_info = mod.typeToFunc(panic_decl.typeOf(mod)).?; const panic_global = try o.resolveLlvmFunction(panic_func.owner_decl); _ = try fg.wip.call( .normal, @@ -5612,7 +5613,7 @@ pub const FuncGen = struct { _ = try self.wip.retVoid(); return .none; } - const fn_info = mod.typeToFunc(self.dg.decl.ty).?; + const fn_info = mod.typeToFunc(self.dg.decl.typeOf(mod)).?; if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { if (Type.fromInterned(fn_info.return_type).isError(mod)) { // Functions with an empty error set are emitted with an error code @@ -5674,7 +5675,7 @@ pub const FuncGen = struct { const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const ptr_ty = self.typeOf(un_op); const ret_ty = ptr_ty.childType(mod); - const fn_info = mod.typeToFunc(self.dg.decl.ty).?; + const fn_info = mod.typeToFunc(self.dg.decl.typeOf(mod)).?; if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { if (Type.fromInterned(fn_info.return_type).isError(mod)) { // Functions with an empty error set are emitted with an error code diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 10bbe2204d1d..17b44806e20f 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1221,7 +1221,7 @@ const DeclGen = struct { else => {}, } - if (!decl.ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) { + if (!decl.typeOf(mod).isFnOrHasRuntimeBitsIgnoreComptime(mod)) { // Pointer to nothing - return undefined. return self.spv.constUndef(ty_ref); } @@ -1237,7 +1237,7 @@ const DeclGen = struct { const final_storage_class = self.spvStorageClass(decl.@"addrspace"); try self.addFunctionDep(spv_decl_index, final_storage_class); - const decl_ptr_ty_ref = try self.ptrType(decl.ty, final_storage_class); + const decl_ptr_ty_ref = try self.ptrType(decl.typeOf(mod), final_storage_class); const ptr_id = switch (final_storage_class) { .Generic => try self.castToGeneric(self.typeId(decl_ptr_ty_ref), decl_id), @@ -2044,11 +2044,11 @@ const DeclGen = struct { switch (self.spv.declPtr(spv_decl_index).kind) { .func => { - assert(decl.ty.zigTypeTag(mod) == .Fn); - const fn_info = mod.typeToFunc(decl.ty).?; + assert(decl.typeOf(mod).zigTypeTag(mod) == .Fn); + const fn_info = mod.typeToFunc(decl.typeOf(mod)).?; const return_ty_ref = try self.resolveFnReturnType(Type.fromInterned(fn_info.return_type)); - const prototype_ty_ref = try self.resolveType(decl.ty, .direct); + const prototype_ty_ref = try self.resolveType(decl.typeOf(mod), .direct); try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{ .id_result_type = self.typeId(return_ty_ref), .id_result = result_id, @@ -2121,7 +2121,7 @@ const DeclGen = struct { const final_storage_class = self.spvStorageClass(decl.@"addrspace"); assert(final_storage_class != .Generic); // These should be instance globals - const ptr_ty_ref = try self.ptrType(decl.ty, final_storage_class); + const ptr_ty_ref = try self.ptrType(decl.typeOf(mod), final_storage_class); try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpVariable, .{ .id_result_type = self.typeId(ptr_ty_ref), @@ -2144,7 +2144,7 @@ const DeclGen = struct { try self.spv.declareDeclDeps(spv_decl_index, &.{}); - const ptr_ty_ref = try self.ptrType(decl.ty, .Function); + const ptr_ty_ref = try self.ptrType(decl.typeOf(mod), .Function); if (maybe_init_val) |init_val| { // TODO: Combine with resolveAnonDecl? @@ -2168,7 +2168,7 @@ const DeclGen = struct { }); self.current_block_label = root_block_id; - const val_id = try self.constant(decl.ty, init_val, .indirect); + const val_id = try self.constant(decl.typeOf(mod), init_val, .indirect); try self.func.body.emit(self.spv.gpa, .OpStore, .{ .pointer = result_id, .object = val_id, @@ -4785,7 +4785,7 @@ const DeclGen = struct { const mod = self.module; if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { const decl = mod.declPtr(self.decl_index); - const fn_info = mod.typeToFunc(decl.ty).?; + const fn_info = mod.typeToFunc(decl.typeOf(mod)).?; if (Type.fromInterned(fn_info.return_type).isError(mod)) { // Functions with an empty error set are emitted with an error code // return type and return zero so they can be function pointers coerced @@ -4810,7 +4810,7 @@ const DeclGen = struct { if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { const decl = mod.declPtr(self.decl_index); - const fn_info = mod.typeToFunc(decl.ty).?; + const fn_info = mod.typeToFunc(decl.typeOf(mod)).?; if (Type.fromInterned(fn_info.return_type).isError(mod)) { // Functions with an empty error set are emitted with an error code // return type and return zero so they can be function pointers coerced diff --git a/src/link/C.zig b/src/link/C.zig index 59ebed800b77..1bfe55c70a89 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -209,7 +209,7 @@ pub fn updateFunc( .module = module, .error_msg = null, .pass = .{ .decl = decl_index }, - .is_naked_fn = decl.ty.fnCallingConvention(module) == .Naked, + .is_naked_fn = decl.typeOf(module).fnCallingConvention(module) == .Naked, .fwd_decl = fwd_decl.toManaged(gpa), .ctypes = ctypes.*, .anon_decl_deps = self.anon_decls, diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 206cf7348c7a..01fa6cac6716 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1272,7 +1272,7 @@ pub fn updateDecl( const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val; const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ - .ty = decl.ty, + .ty = decl.typeOf(mod), .val = decl_val, }, &code_buffer, .none, .{ .parent_atom_index = atom.getSymbolIndex().?, @@ -1399,8 +1399,8 @@ pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: InternPool.DeclIndex) !At fn getDeclOutputSection(self: *Coff, decl_index: InternPool.DeclIndex) u16 { const decl = self.base.comp.module.?.declPtr(decl_index); - const ty = decl.ty; const mod = self.base.comp.module.?; + const ty = decl.typeOf(mod); const zig_ty = ty.zigTypeTag(mod); const val = decl.val; const index: u16 = blk: { @@ -1535,7 +1535,7 @@ pub fn updateExports( .x86 => std.builtin.CallingConvention.Stdcall, else => std.builtin.CallingConvention.C, }; - const decl_cc = exported_decl.ty.fnCallingConvention(mod); + const decl_cc = exported_decl.typeOf(mod).fnCallingConvention(mod); if (decl_cc == .C and ip.stringEqlSlice(exp.opts.name, "main") and comp.config.link_libc) { diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 26eb536c0814..e2d4669156a6 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -1109,7 +1109,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: InternPool.DeclInde assert(decl.has_tv); - switch (decl.ty.zigTypeTag(mod)) { + switch (decl.typeOf(mod).zigTypeTag(mod)) { .Fn => { _ = try self.getOrCreateAtomForDecl(.src_fn, decl_index); @@ -1162,7 +1162,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: InternPool.DeclInde try dbg_info_buffer.ensureUnusedCapacity(1 + ptr_width_bytes + 4 + 4 + (decl_name_slice.len + 1) + (decl_linkage_name_slice.len + 1)); - const fn_ret_type = decl.ty.fnReturnType(mod); + const fn_ret_type = decl.typeOf(mod).fnReturnType(mod); const fn_ret_has_bits = fn_ret_type.hasRuntimeBits(mod); dbg_info_buffer.appendAssumeCapacity(@intFromEnum( @as(AbbrevCode, if (fn_ret_has_bits) .subprogram else .subprogram_retvoid), @@ -1215,7 +1215,7 @@ pub fn commitDeclState( var dbg_info_buffer = &decl_state.dbg_info; assert(decl.has_tv); - switch (decl.ty.zigTypeTag(zcu)) { + switch (decl.typeOf(zcu).zigTypeTag(zcu)) { .Fn => { try decl_state.setInlineFunc(decl.val.toIntern()); diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 4c86bb3a894d..3bf6f1246c66 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -846,7 +846,7 @@ fn getDeclShdrIndex( _ = self; const mod = elf_file.base.comp.module.?; const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded; - const shdr_index = switch (decl.ty.zigTypeTag(mod)) { + const shdr_index = switch (decl.typeOf(mod).zigTypeTag(mod)) { .Fn => elf_file.zig_text_section_index.?, else => blk: { if (decl.getOwnedVariable(mod)) |variable| { @@ -1158,7 +1158,7 @@ pub fn updateDecl( const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val; const res = if (decl_state) |*ds| try codegen.generateSymbol(&elf_file.base, decl.srcLoc(mod), .{ - .ty = decl.ty, + .ty = decl.typeOf(mod), .val = decl_val, }, &code_buffer, .{ .dwarf = ds, @@ -1167,7 +1167,7 @@ pub fn updateDecl( }) else try codegen.generateSymbol(&elf_file.base, decl.srcLoc(mod), .{ - .ty = decl.ty, + .ty = decl.typeOf(mod), .val = decl_val, }, &code_buffer, .none, .{ .parent_atom_index = sym_index, diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index bfd02fbd78ba..42f186d96133 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -740,7 +740,7 @@ pub fn updateDecl( const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none; const res = try codegen.generateSymbol(&macho_file.base, decl.srcLoc(mod), .{ - .ty = decl.ty, + .ty = decl.typeOf(mod), .val = decl_val, }, &code_buffer, dio, .{ .parent_atom_index = sym_index, @@ -1021,7 +1021,7 @@ fn getDeclOutputSection( _ = self; const mod = macho_file.base.comp.module.?; const any_non_single_threaded = macho_file.base.comp.config.any_non_single_threaded; - const sect_id: u8 = switch (decl.ty.zigTypeTag(mod)) { + const sect_id: u8 = switch (decl.typeOf(mod).zigTypeTag(mod)) { .Fn => macho_file.zig_text_sect_index.?, else => blk: { if (decl.getOwnedVariable(mod)) |variable| { diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index e14fc18a55d0..d092351c471a 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -177,7 +177,7 @@ pub const Atom = struct { return if (self.code_ptr) |p| p[0..self.other.code_len] else blk: { const decl_index = self.other.decl_index; const decl = mod.declPtr(decl_index); - if (decl.ty.zigTypeTag(mod) == .Fn) { + if (decl.typeOf(mod).zigTypeTag(mod) == .Fn) { const table = plan9.fn_decl_table.get(decl.getFileScope(mod)).?.functions; const output = table.get(decl_index).?; break :blk output.code; @@ -540,7 +540,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: InternPool.DeclIndex) const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val; // TODO we need the symbol index for symbol in the table of locals for the containing atom const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ - .ty = decl.ty, + .ty = decl.typeOf(mod), .val = decl_val, }, &code_buffer, .{ .none = {} }, .{ .parent_atom_index = @as(Atom.Index, @intCast(atom_idx)), @@ -566,7 +566,7 @@ fn updateFinish(self: *Plan9, decl_index: InternPool.DeclIndex) !void { const gpa = self.base.comp.gpa; const mod = self.base.comp.module.?; const decl = mod.declPtr(decl_index); - const is_fn = (decl.ty.zigTypeTag(mod) == .Fn); + const is_fn = (decl.typeOf(mod).zigTypeTag(mod) == .Fn); const sym_t: aout.Sym.Type = if (is_fn) .t else .d; const atom = self.getAtomPtr(self.decls.get(decl_index).?.index); diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index 27172c3fd30c..dc25ac510579 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -163,7 +163,7 @@ pub fn updateExports( if (decl.val.isFuncBody(mod)) { const target = mod.getTarget(); const spv_decl_index = try self.object.resolveDecl(mod, decl_index); - const execution_model = switch (decl.ty.fnCallingConvention(mod)) { + const execution_model = switch (decl.typeOf(mod).fnCallingConvention(mod)) { .Vertex => spec.ExecutionModel.Vertex, .Fragment => spec.ExecutionModel.Fragment, .Kernel => spec.ExecutionModel.Kernel, diff --git a/src/link/Wasm/ZigObject.zig b/src/link/Wasm/ZigObject.zig index 30aab49cb12d..293c088c669c 100644 --- a/src/link/Wasm/ZigObject.zig +++ b/src/link/Wasm/ZigObject.zig @@ -270,7 +270,7 @@ pub fn updateDecl( const res = try codegen.generateSymbol( &wasm_file.base, decl.srcLoc(mod), - .{ .ty = decl.ty, .val = val }, + .{ .ty = decl.typeOf(mod), .val = val }, &code_writer, .none, .{ .parent_atom_index = @intFromEnum(atom.sym_index) }, @@ -346,7 +346,7 @@ fn finishUpdateDecl( try atom.code.appendSlice(gpa, code); atom.size = @intCast(code.len); - switch (decl.ty.zigTypeTag(mod)) { + switch (decl.typeOf(mod).zigTypeTag(mod)) { .Fn => { sym.index = try zig_object.appendFunction(gpa, .{ .type_index = zig_object.atom_types.get(atom_index).? }); sym.tag = .function; @@ -764,7 +764,7 @@ pub fn getDeclVAddr( const atom_index = wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = @enumFromInt(reloc_info.parent_atom_index) }).?; const atom = wasm_file.getAtomPtr(atom_index); const is_wasm32 = target.cpu.arch == .wasm32; - if (decl.ty.zigTypeTag(mod) == .Fn) { + if (decl.typeOf(mod).zigTypeTag(mod) == .Fn) { std.debug.assert(reloc_info.addend == 0); // addend not allowed for function relocations try atom.relocs.append(gpa, .{ .index = target_symbol_index, @@ -964,7 +964,7 @@ pub fn freeDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_index: InternPool if (sym.isGlobal()) { std.debug.assert(zig_object.global_syms.remove(atom.sym_index)); } - switch (decl.ty.zigTypeTag(mod)) { + switch (decl.typeOf(mod).zigTypeTag(mod)) { .Fn => { zig_object.functions_free_list.append(gpa, sym.index) catch {}; std.debug.assert(zig_object.atom_types.remove(atom_index)); From 5ec6e3036b2772e6efc08726b22c560dedd556bc Mon Sep 17 00:00:00 2001 From: mlugg Date: Mon, 25 Mar 2024 23:08:59 +0000 Subject: [PATCH 02/14] Sema: introduce separate `MutableValue` representation for comptime-mutable memory Perhaps someday, we will make Sema operate on mutable values more generally. For now, it makes sense to split out this representation, since it is only used in comptime pointer accesses. There are some currently unused methods on `MutableValue` which will be used once I rewrite the comptime pointer access logic to be less terrible. The commit following this one will - at long last - delete the legacy Value representation --- src/Module.zig | 2 +- src/Sema.zig | 657 ++++++++++++++---------------------------- src/Value.zig | 8 +- src/mutable_value.zig | 508 ++++++++++++++++++++++++++++++++ 4 files changed, 734 insertions(+), 441 deletions(-) create mode 100644 src/mutable_value.zig diff --git a/src/Module.zig b/src/Module.zig index 9cbb2cc89af8..a11194c10349 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -3598,7 +3598,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { const old_has_tv = decl.has_tv; // The following values are ignored if `!old_has_tv` - const old_ty = decl.typeOf(mod); + const old_ty = if (old_has_tv) decl.typeOf(mod) else undefined; const old_val = decl.val; const old_align = decl.alignment; const old_linksection = decl.@"linksection"; diff --git a/src/Sema.zig b/src/Sema.zig index 826988ee3491..7db1462787e3 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -139,8 +139,7 @@ const MaybeComptimeAlloc = struct { }; const ComptimeAlloc = struct { - ty: Type, - val: Value, + val: MutableValue, is_const: bool, /// `.none` indicates that the alignment is the natural alignment of `val`. alignment: Alignment, @@ -153,8 +152,7 @@ const ComptimeAlloc = struct { fn newComptimeAlloc(sema: *Sema, block: *Block, ty: Type, alignment: Alignment) !ComptimeAllocIndex { const idx = sema.comptime_allocs.items.len; try sema.comptime_allocs.append(sema.gpa, .{ - .ty = ty, - .val = Value.fromInterned(try sema.mod.intern(.{ .undef = ty.toIntern() })), + .val = .{ .interned = try sema.mod.intern(.{ .undef = ty.toIntern() }) }, .is_const = false, .alignment = alignment, .runtime_index = block.runtime_index, @@ -175,6 +173,7 @@ const log = std.log.scoped(.sema); const Sema = @This(); const Value = @import("Value.zig"); +const MutableValue = @import("mutable_value.zig").MutableValue; const Type = @import("type.zig").Type; const TypedValue = @import("TypedValue.zig"); const Air = @import("Air.zig"); @@ -3762,10 +3761,10 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro if (!sema.isComptimeMutablePtr(ptr_val)) break :already_ct; const alloc_index = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr.comptime_alloc; const ct_alloc = sema.getComptimeAlloc(alloc_index); - const interned = try ct_alloc.val.intern(ct_alloc.ty, mod); + const interned = try ct_alloc.val.intern(mod, sema.arena); if (Value.fromInterned(interned).canMutateComptimeVarState(mod)) { // Preserve the comptime alloc, just make the pointer const. - ct_alloc.val = Value.fromInterned(interned); + ct_alloc.val = .{ .interned = interned }; ct_alloc.is_const = true; return sema.makePtrConst(block, alloc); } else { @@ -4030,7 +4029,7 @@ fn finishResolveComptimeKnownAllocPtr( const alloc_index = existing_comptime_alloc orelse a: { const idx = try sema.newComptimeAlloc(block, alloc_ty.childType(zcu), alloc_ty.ptrAlignment(zcu)); const alloc = sema.getComptimeAlloc(idx); - alloc.val = Value.fromInterned(result_val); + alloc.val = .{ .interned = result_val }; break :a idx; }; sema.getComptimeAlloc(alloc_index).is_const = true; @@ -4193,7 +4192,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com .anon_decl => |a| a.val, .comptime_alloc => |i| val: { const alloc = sema.getComptimeAlloc(i); - break :val try alloc.val.intern(alloc.ty, mod); + break :val try alloc.val.intern(mod, sema.arena); }, else => unreachable, }; @@ -5597,7 +5596,7 @@ fn storeToInferredAllocComptime( } }); } else { const alloc_index = try sema.newComptimeAlloc(block, operand_ty, iac.alignment); - sema.getComptimeAlloc(alloc_index).val = operand_val; + sema.getComptimeAlloc(alloc_index).val = .{ .interned = operand_val.toIntern() }; iac.ptr = try zcu.intern(.{ .ptr = .{ .ty = alloc_ty.toIntern(), .addr = .{ .comptime_alloc = alloc_index }, @@ -30655,21 +30654,22 @@ fn storePtrVal( .opv => {}, .direct => |val_ptr| { if (mut_kit.root == .comptime_field) { - val_ptr.* = Value.fromInterned((try val_ptr.intern(operand_ty, mod))); - if (!operand_val.eql(val_ptr.*, operand_ty, mod)) { + val_ptr.* = .{ .interned = try val_ptr.intern(mod, sema.arena) }; + if (operand_val.toIntern() != val_ptr.interned) { // TODO use failWithInvalidComptimeFieldStore return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{}); } return; } - val_ptr.* = Value.fromInterned((try operand_val.intern(operand_ty, mod))); + val_ptr.* = .{ .interned = operand_val.toIntern() }; }, .reinterpret => |reinterpret| { try sema.resolveTypeLayout(mut_kit.ty); const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(mod)); const buffer = try sema.gpa.alloc(u8, abi_size); defer sema.gpa.free(buffer); - reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, mod, buffer) catch |err| switch (err) { + const interned_old = Value.fromInterned(try reinterpret.val_ptr.intern(mod, sema.arena)); + interned_old.writeToMemory(mut_kit.ty, mod, buffer) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.ReinterpretDeclRef => unreachable, error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already @@ -30693,7 +30693,7 @@ fn storePtrVal( error.IllDefinedMemoryLayout => unreachable, error.Unimplemented => return sema.fail(block, src, "TODO: implement readFromMemory for type '{}'", .{mut_kit.ty.fmt(mod)}), }; - reinterpret.val_ptr.* = Value.fromInterned((try val.intern(mut_kit.ty, mod))); + reinterpret.val_ptr.* = .{ .interned = val.toIntern() }; }, .bad_decl_ty, .bad_ptr_ty => { // TODO show the decl declaration site in a note and explain whether the decl @@ -30718,11 +30718,11 @@ const ComptimePtrMutationKit = struct { opv, /// The pointer type matches the actual comptime Value so a direct /// modification is possible. - direct: *Value, + direct: *MutableValue, /// The largest parent Value containing pointee and having a well-defined memory layout. /// This is used for bitcasting, if direct dereferencing failed. reinterpret: struct { - val_ptr: *Value, + val_ptr: *MutableValue, byte_offset: usize, /// If set, write the operand to packed memory write_packed: bool = false, @@ -30754,15 +30754,15 @@ fn beginComptimePtrMutation( .decl, .anon_decl, .int => unreachable, // isComptimeMutablePtr has been checked already .comptime_alloc => |alloc_index| { const alloc = sema.getComptimeAlloc(alloc_index); - return sema.beginComptimePtrMutationInner(block, src, alloc.ty, &alloc.val, ptr_elem_ty, .{ .alloc = alloc_index }); + return sema.beginComptimePtrMutationInner(block, src, alloc.val.typeOf(mod), &alloc.val, ptr_elem_ty, .{ .alloc = alloc_index }); }, .comptime_field => |comptime_field| { - const duped = try sema.arena.create(Value); - duped.* = Value.fromInterned(comptime_field); + const duped = try sema.arena.create(MutableValue); + duped.* = .{ .interned = comptime_field }; return sema.beginComptimePtrMutationInner( block, src, - Type.fromInterned(mod.intern_pool.typeOf(comptime_field)), + duped.typeOf(mod), duped, ptr_elem_ty, .comptime_field, @@ -30775,36 +30775,28 @@ fn beginComptimePtrMutation( .opv => unreachable, .direct => |val_ptr| { const payload_ty = parent.ty.errorUnionPayload(mod); - if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) { - return ComptimePtrMutationKit{ - .root = parent.root, - .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data }, - .ty = payload_ty, - }; - } else { + try val_ptr.unintern(mod, sema.arena, false, false); + if (val_ptr.* == .interned) { // 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 payload = try sema.arena.create(Value.Payload.SubValue); - payload.* = .{ - .base = .{ .tag = .eu_payload }, - .data = Value.fromInterned((try mod.intern(.{ .undef = payload_ty.toIntern() }))), - }; - - val_ptr.* = Value.initPayload(&payload.base); - - return ComptimePtrMutationKit{ - .root = parent.root, - .pointee = .{ .direct = &payload.data }, - .ty = payload_ty, - }; + // representation of the error union to `eu_payload`. + const child = try sema.arena.create(MutableValue); + child.* = .{ .interned = try mod.intern(.{ .undef = payload_ty.toIntern() }) }; + val_ptr.* = .{ .eu_payload = .{ + .ty = parent.ty.toIntern(), + .child = child, + } }; } + return .{ + .root = parent.root, + .pointee = .{ .direct = val_ptr.eu_payload.child }, + .ty = payload_ty, + }; }, .bad_decl_ty, .bad_ptr_ty => return parent, // Even though the parent value type has well-defined memory layout, our // pointer type does not. - .reinterpret => return ComptimePtrMutationKit{ + .reinterpret => return .{ .root = parent.root, .pointee = .bad_ptr_ty, .ty = eu_ty, @@ -30818,46 +30810,28 @@ fn beginComptimePtrMutation( .opv => unreachable, .direct => |val_ptr| { const payload_ty = parent.ty.optionalChild(mod); - switch (val_ptr.ip_index) { - .none => return ComptimePtrMutationKit{ - .root = parent.root, - .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data }, - .ty = payload_ty, - }, - else => { - const payload_val = switch (mod.intern_pool.indexToKey(val_ptr.ip_index)) { - .undef => try mod.intern(.{ .undef = payload_ty.toIntern() }), - .opt => |opt| switch (opt.val) { - .none => try mod.intern(.{ .undef = payload_ty.toIntern() }), - else => |payload| payload, - }, - else => unreachable, - }; - - // An optional 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 optional from `undef` to `opt_payload`. - - const payload = try sema.arena.create(Value.Payload.SubValue); - payload.* = .{ - .base = .{ .tag = .opt_payload }, - .data = Value.fromInterned(payload_val), - }; - - val_ptr.* = Value.initPayload(&payload.base); - - return ComptimePtrMutationKit{ - .root = parent.root, - .pointee = .{ .direct = &payload.data }, - .ty = payload_ty, - }; - }, + try val_ptr.unintern(mod, sema.arena, false, false); + if (val_ptr.* == .interned) { + // An optional 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 optional to `opt_payload`. + const child = try sema.arena.create(MutableValue); + child.* = .{ .interned = try mod.intern(.{ .undef = payload_ty.toIntern() }) }; + val_ptr.* = .{ .opt_payload = .{ + .ty = parent.ty.toIntern(), + .child = child, + } }; } + return .{ + .root = parent.root, + .pointee = .{ .direct = val_ptr.opt_payload.child }, + .ty = payload_ty, + }; }, .bad_decl_ty, .bad_ptr_ty => return parent, // Even though the parent value type has well-defined memory layout, our // pointer type does not. - .reinterpret => return ComptimePtrMutationKit{ + .reinterpret => return .{ .root = parent.root, .pointee = .bad_ptr_ty, .ty = opt_ty, @@ -30916,106 +30890,28 @@ fn beginComptimePtrMutation( }; } - switch (val_ptr.ip_index) { - .none => switch (val_ptr.tag()) { - .bytes => { - // An array is memory-optimized to store a slice of bytes, but we are about - // to modify an individual field and the representation has to change. - // If we wanted to avoid this, there would need to be special detection - // elsewhere to identify when writing a value to an array element that is stored - // using the `bytes` tag, and handle it without making a call to this function. - const arena = sema.arena; - - const bytes = val_ptr.castTag(.bytes).?.data; - const dest_len = parent.ty.arrayLenIncludingSentinel(mod); - // bytes.len may be one greater than dest_len because of the case when - // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted. - assert(bytes.len >= dest_len); - const elems = try arena.alloc(Value, @intCast(dest_len)); - for (elems, 0..) |*elem, i| { - elem.* = try mod.intValue(elem_ty, bytes[i]); - } - - val_ptr.* = try Value.Tag.aggregate.create(arena, elems); - - return beginComptimePtrMutationInner( - sema, - block, - src, - elem_ty, - &elems[@intCast(elem_ptr.index)], - ptr_elem_ty, - parent.root, - ); - }, - .repeated => { - // An array is memory-optimized to store only a single element value, and - // that value is understood to be the same for the entire length of the array. - // However, now we want to modify an individual field and so the - // representation has to change. If we wanted to avoid this, there would - // need to be special detection elsewhere to identify when writing a value to an - // array element that is stored using the `repeated` tag, and handle it - // without making a call to this function. - const arena = sema.arena; - - const repeated_val = try val_ptr.castTag(.repeated).?.data.intern(parent.ty.childType(mod), mod); - const array_len_including_sentinel = - try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod)); - const elems = try arena.alloc(Value, array_len_including_sentinel); - @memset(elems, Value.fromInterned(repeated_val)); - - val_ptr.* = try Value.Tag.aggregate.create(arena, elems); - - return beginComptimePtrMutationInner( - sema, - block, - src, - elem_ty, - &elems[@intCast(elem_ptr.index)], - ptr_elem_ty, - parent.root, - ); - }, - - .aggregate => return beginComptimePtrMutationInner( - sema, - block, - src, - elem_ty, - &val_ptr.castTag(.aggregate).?.data[@intCast(elem_ptr.index)], - ptr_elem_ty, - parent.root, - ), + try val_ptr.unintern(mod, sema.arena, false, false); + + const aggregate = switch (val_ptr.*) { + .interned, + .bytes, + .repeated, + .eu_payload, + .opt_payload, + .slice, + .un, + => unreachable, + .aggregate => |*a| a, + }; - else => unreachable, - }, - else => switch (mod.intern_pool.indexToKey(val_ptr.toIntern())) { - .undef => { - // An array has been initialized to undefined at comptime and now we - // are for the first time setting an element. We must change the representation - // of the array from `undef` to `array`. - const arena = sema.arena; - - const array_len_including_sentinel = - try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod)); - const elems = try arena.alloc(Value, array_len_including_sentinel); - @memset(elems, Value.fromInterned((try mod.intern(.{ .undef = elem_ty.toIntern() })))); - - val_ptr.* = try Value.Tag.aggregate.create(arena, elems); - - return beginComptimePtrMutationInner( - sema, - block, - src, - elem_ty, - &elems[@intCast(elem_ptr.index)], - ptr_elem_ty, - parent.root, - ); - }, - else => unreachable, - }, - } + return sema.beginComptimePtrMutationInner( + block, + src, + elem_ty, + &aggregate.elems[@intCast(elem_ptr.index)], + ptr_elem_ty, + parent.root, + ); }, else => { if (elem_ptr.index != 0) { @@ -31039,7 +30935,7 @@ fn beginComptimePtrMutation( if (!base_elem_ty.hasWellDefinedLayout(mod)) { // Even though the parent value type has well-defined memory layout, our // pointer type does not. - return ComptimePtrMutationKit{ + return .{ .root = parent.root, .pointee = .bad_ptr_ty, .ty = base_elem_ty, @@ -31049,7 +30945,7 @@ fn beginComptimePtrMutation( const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty); const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64); const elem_idx = try sema.usizeCast(block, src, elem_ptr.index); - return ComptimePtrMutationKit{ + return .{ .root = parent.root, .pointee = .{ .reinterpret = .{ .val_ptr = reinterpret.val_ptr, @@ -31068,56 +30964,68 @@ fn beginComptimePtrMutation( var parent = try sema.beginComptimePtrMutation(block, src, Value.fromInterned(field_ptr.base), base_child_ty); switch (parent.pointee) { .opv => unreachable, - .direct => |val_ptr| switch (val_ptr.ip_index) { - .empty_struct => { - const duped = try sema.arena.create(Value); - duped.* = val_ptr.*; - return beginComptimePtrMutationInner( - sema, - block, - src, - parent.ty.structFieldType(field_index, mod), - duped, - ptr_elem_ty, - parent.root, - ); - }, - .none => switch (val_ptr.tag()) { - .aggregate => return beginComptimePtrMutationInner( - sema, + .direct => |val_ptr| { + try val_ptr.unintern(mod, sema.arena, false, false); + switch (val_ptr.*) { + .interned, + .eu_payload, + .opt_payload, + .repeated, + .bytes, + => unreachable, + .aggregate => |*a| return sema.beginComptimePtrMutationInner( block, src, parent.ty.structFieldType(field_index, mod), - &val_ptr.castTag(.aggregate).?.data[field_index], + &a.elems[field_index], ptr_elem_ty, parent.root, ), - .repeated => { - const arena = sema.arena; - - const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod)); - @memset(elems, val_ptr.castTag(.repeated).?.data); - val_ptr.* = try Value.Tag.aggregate.create(arena, elems); - - return beginComptimePtrMutationInner( - sema, + .slice => |*s| switch (field_index) { + Value.slice_ptr_index => return sema.beginComptimePtrMutationInner( block, src, - parent.ty.structFieldType(field_index, mod), - &elems[field_index], + parent.ty.slicePtrFieldType(mod), + s.ptr, ptr_elem_ty, parent.root, - ); + ), + Value.slice_len_index => return sema.beginComptimePtrMutationInner( + block, + src, + Type.usize, + s.len, + ptr_elem_ty, + parent.root, + ), + else => unreachable, }, - .@"union" => { - const payload = &val_ptr.castTag(.@"union").?.data; + .un => |*un| { const layout = base_child_ty.containerLayout(mod); const tag_type = base_child_ty.unionTagTypeHypothetical(mod); const hypothetical_tag = try mod.enumValueFieldIndex(tag_type, field_index); - if (layout == .auto or (payload.tag != null and hypothetical_tag.eql(payload.tag.?, tag_type, mod))) { + if (un.tag == .none and un.payload.* == .interned and un.payload.interned == .undef) { + // A union has been initialized to undefined at comptime and now we + // are for the first time setting the payload. We must change the + // tag implicitly. + const payload_ty = parent.ty.structFieldType(field_index, mod); + un.tag = hypothetical_tag.toIntern(); + un.payload.* = .{ .interned = try mod.intern(.{ .undef = payload_ty.toIntern() }) }; + return beginComptimePtrMutationInner( + sema, + block, + src, + payload_ty, + un.payload, + ptr_elem_ty, + parent.root, + ); + } + + if (layout == .auto or hypothetical_tag.toIntern() == un.tag) { // We need to set the active field of the union. - payload.tag = hypothetical_tag; + un.tag = hypothetical_tag.toIntern(); const field_ty = parent.ty.structFieldType(field_index, mod); return beginComptimePtrMutationInner( @@ -31125,7 +31033,7 @@ fn beginComptimePtrMutation( block, src, field_ty, - &payload.val, + un.payload, ptr_elem_ty, parent.root, ); @@ -31133,11 +31041,10 @@ fn beginComptimePtrMutation( // Writing to a different field (a different or unknown tag is active) requires reinterpreting // memory of the entire union, which requires knowing its abiSize. try sema.resolveTypeLayout(parent.ty); - // This union value no longer has a well-defined tag type. // The reinterpretation will read it back out as .none. - payload.val = try payload.val.unintern(sema.arena, mod); - return ComptimePtrMutationKit{ + try un.payload.unintern(mod, sema.arena, false, false); + return .{ .root = parent.root, .pointee = .{ .reinterpret = .{ .val_ptr = val_ptr, @@ -31148,119 +31055,12 @@ fn beginComptimePtrMutation( }; } }, - .slice => switch (field_index) { - Value.slice_ptr_index => return beginComptimePtrMutationInner( - sema, - block, - src, - parent.ty.slicePtrFieldType(mod), - &val_ptr.castTag(.slice).?.data.ptr, - ptr_elem_ty, - parent.root, - ), - - Value.slice_len_index => return beginComptimePtrMutationInner( - sema, - block, - src, - Type.usize, - &val_ptr.castTag(.slice).?.data.len, - ptr_elem_ty, - parent.root, - ), - - else => unreachable, - }, - else => unreachable, - }, - else => switch (mod.intern_pool.indexToKey(val_ptr.toIntern())) { - .undef => { - // A struct or union has been initialized to undefined at comptime and now we - // are for the first time setting a field. We must change the representation - // of the struct/union from `undef` to `struct`/`union`. - const arena = sema.arena; - - switch (parent.ty.zigTypeTag(mod)) { - .Struct => { - const fields = try arena.alloc(Value, parent.ty.structFieldCount(mod)); - for (fields, 0..) |*field, i| field.* = Value.fromInterned((try mod.intern(.{ - .undef = parent.ty.structFieldType(i, mod).toIntern(), - }))); - - val_ptr.* = try Value.Tag.aggregate.create(arena, fields); - - return beginComptimePtrMutationInner( - sema, - block, - src, - parent.ty.structFieldType(field_index, mod), - &fields[field_index], - ptr_elem_ty, - parent.root, - ); - }, - .Union => { - const payload = try arena.create(Value.Payload.Union); - const tag_ty = parent.ty.unionTagTypeHypothetical(mod); - const payload_ty = parent.ty.structFieldType(field_index, mod); - payload.* = .{ .data = .{ - .tag = try mod.enumValueFieldIndex(tag_ty, field_index), - .val = Value.fromInterned((try mod.intern(.{ .undef = payload_ty.toIntern() }))), - } }; - - val_ptr.* = Value.initPayload(&payload.base); - - return beginComptimePtrMutationInner( - sema, - block, - src, - payload_ty, - &payload.data.val, - ptr_elem_ty, - parent.root, - ); - }, - .Pointer => { - assert(parent.ty.isSlice(mod)); - const ptr_ty = parent.ty.slicePtrFieldType(mod); - val_ptr.* = try Value.Tag.slice.create(arena, .{ - .ptr = Value.fromInterned((try mod.intern(.{ .undef = ptr_ty.toIntern() }))), - .len = Value.fromInterned((try mod.intern(.{ .undef = .usize_type }))), - }); - - switch (field_index) { - Value.slice_ptr_index => return beginComptimePtrMutationInner( - sema, - block, - src, - ptr_ty, - &val_ptr.castTag(.slice).?.data.ptr, - ptr_elem_ty, - parent.root, - ), - Value.slice_len_index => return beginComptimePtrMutationInner( - sema, - block, - src, - Type.usize, - &val_ptr.castTag(.slice).?.data.len, - ptr_elem_ty, - parent.root, - ), - - else => unreachable, - } - }, - else => unreachable, - } - }, - else => unreachable, - }, + } }, .reinterpret => |reinterpret| { const field_offset_u64 = base_child_ty.structFieldOffset(field_index, mod); const field_offset = try sema.usizeCast(block, src, field_offset_u64); - return ComptimePtrMutationKit{ + return .{ .root = parent.root, .pointee = .{ .reinterpret = .{ .val_ptr = reinterpret.val_ptr, @@ -31280,7 +31080,7 @@ fn beginComptimePtrMutationInner( block: *Block, src: LazySrcLoc, decl_ty: Type, - decl_val: *Value, + decl_val: *MutableValue, ptr_elem_ty: Type, root: ComptimePtrMutationKit.Root, ) CompileError!ComptimePtrMutationKit { @@ -31288,7 +31088,13 @@ fn beginComptimePtrMutationInner( const target = mod.getTarget(); const coerce_ok = (try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_ty, true, target, src, src)) == .ok; - decl_val.* = try decl_val.unintern(sema.arena, mod); + const old_decl_val = decl_val.*; + try decl_val.unintern(mod, sema.arena, false, false); + if (decl_val.* == .un and decl_val.un.tag == .none and decl_val.un.payload.* == .interned and decl_val.un.payload.interned == .undef) { + // HACKHACK: undefined union - re-intern it for now + // `unintern` probably should just leave these as is, but I'm leaving it until I rewrite comptime pointer access. + decl_val.* = old_decl_val; + } if (coerce_ok) { return ComptimePtrMutationKit{ @@ -31334,21 +31140,16 @@ fn beginComptimePtrMutationInner( }; } -const TypedValueAndOffset = struct { - tv: TypedValue, - byte_offset: usize, -}; - const ComptimePtrLoadKit = struct { /// The Value and Type corresponding to the pointee of the provided pointer. /// If a direct dereference is not possible, this is null. - pointee: ?TypedValue, + pointee: ?MutableValue, /// The largest parent Value containing `pointee` and having a well-defined memory layout. /// This is used for bitcasting, if direct dereferencing failed (i.e. `pointee` is null). - parent: ?TypedValueAndOffset, - /// Whether the `pointee` could be mutated by further - /// semantic analysis and a copy must be performed. - is_mutable: bool, + parent: ?struct { + val: MutableValue, + byte_offset: usize, + }, /// If the root decl could not be used as `parent`, this is the type that /// caused that by not having a well-defined layout ty_without_well_defined_layout: ?Type, @@ -31375,53 +31176,41 @@ fn beginComptimePtrLoad( .ptr => |ptr| switch (ptr.addr) { .decl => |decl_index| blk: { const decl = mod.declPtr(decl_index); - const decl_tv = try decl.typedValue(mod); try sema.declareDependency(.{ .decl_val = decl_index }); if (decl.val.getVariable(mod) != null) return error.RuntimeLoad; - + const decl_val: MutableValue = .{ .interned = decl.val.toIntern() }; const layout_defined = decl.typeOf(mod).hasWellDefinedLayout(mod); break :blk ComptimePtrLoadKit{ - .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, - .pointee = decl_tv, - .is_mutable = false, + .parent = if (layout_defined) .{ .val = decl_val, .byte_offset = 0 } else null, + .pointee = decl_val, .ty_without_well_defined_layout = if (!layout_defined) decl.typeOf(mod) else null, }; }, .comptime_alloc => |alloc_index| kit: { const alloc = sema.getComptimeAlloc(alloc_index); - const alloc_tv: TypedValue = .{ - .ty = alloc.ty, - .val = alloc.val, - }; - const layout_defined = alloc.ty.hasWellDefinedLayout(mod); + const alloc_ty = alloc.val.typeOf(mod); + const layout_defined = alloc_ty.hasWellDefinedLayout(mod); break :kit .{ - .parent = if (layout_defined) .{ .tv = alloc_tv, .byte_offset = 0 } else null, - .pointee = alloc_tv, - .is_mutable = true, - .ty_without_well_defined_layout = if (!layout_defined) alloc.ty else null, + .parent = if (layout_defined) .{ .val = alloc.val, .byte_offset = 0 } else null, + .pointee = alloc.val, + .ty_without_well_defined_layout = if (!layout_defined) alloc_ty else null, }; }, .anon_decl => |anon_decl| blk: { const decl_val = anon_decl.val; if (Value.fromInterned(decl_val).getVariable(mod) != null) return error.RuntimeLoad; const decl_ty = Type.fromInterned(ip.typeOf(decl_val)); - const decl_tv: TypedValue = .{ .ty = decl_ty, .val = Value.fromInterned(decl_val) }; + const decl_mv: MutableValue = .{ .interned = decl_val }; const layout_defined = decl_ty.hasWellDefinedLayout(mod); break :blk ComptimePtrLoadKit{ - .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, - .pointee = decl_tv, - .is_mutable = false, + .parent = if (layout_defined) .{ .val = decl_mv, .byte_offset = 0 } else null, + .pointee = decl_mv, .ty_without_well_defined_layout = if (!layout_defined) decl_ty else null, }; }, .int => return error.RuntimeLoad, .eu_payload, .opt_payload => |container_ptr| blk: { const container_ty = Type.fromInterned(ip.typeOf(container_ptr)).childType(mod); - const payload_ty = switch (ptr.addr) { - .eu_payload => container_ty.errorUnionPayload(mod), - .opt_payload => container_ty.optionalChild(mod), - else => unreachable, - }; var deref = try sema.beginComptimePtrLoad(block, src, Value.fromInterned(container_ptr), container_ty); // eu_payload and opt_payload never have a well-defined layout @@ -31430,15 +31219,14 @@ fn beginComptimePtrLoad( deref.ty_without_well_defined_layout = container_ty; } - if (deref.pointee) |*tv| { + if (deref.pointee) |pointee| { + const pointee_ty = pointee.typeOf(mod); const coerce_in_mem_ok = - (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or - (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok; + (try sema.coerceInMemoryAllowed(block, container_ty, pointee_ty, false, target, src, src)) == .ok or + (try sema.coerceInMemoryAllowed(block, pointee_ty, container_ty, false, target, src, src)) == .ok; if (coerce_in_mem_ok) { - const payload_val = switch (tv.val.ip_index) { - .none => tv.val.cast(Value.Payload.SubValue).?.data, - .null_value => return sema.fail(block, src, "attempt to use null value", .{}), - else => Value.fromInterned(switch (ip.indexToKey(tv.val.toIntern())) { + deref.pointee = switch (pointee) { + .interned => |ip_index| .{ .interned = switch (ip.indexToKey(ip_index)) { .error_union => |error_union| switch (error_union.val) { .err_name => |err_name| return sema.fail( block, @@ -31453,23 +31241,20 @@ fn beginComptimePtrLoad( else => |payload| payload, }, else => unreachable, - }), + } }, + .eu_payload, .opt_payload => |p| p.child.*, + else => unreachable, }; - tv.* = TypedValue{ .ty = payload_ty, .val = payload_val }; break :blk deref; } } deref.pointee = null; break :blk deref; }, - .comptime_field => |comptime_field| blk: { - const field_ty = Type.fromInterned(ip.typeOf(comptime_field)); - break :blk ComptimePtrLoadKit{ - .parent = null, - .pointee = .{ .ty = field_ty, .val = Value.fromInterned(comptime_field) }, - .is_mutable = false, - .ty_without_well_defined_layout = field_ty, - }; + .comptime_field => |field_val| .{ + .parent = null, + .pointee = .{ .interned = field_val }, + .ty_without_well_defined_layout = Type.fromInterned(ip.typeOf(field_val)), }, .elem => |elem_ptr| blk: { const elem_ty = Type.fromInterned(ip.typeOf(elem_ptr.base)).elemType2(mod); @@ -31502,30 +31287,37 @@ fn beginComptimePtrLoad( // If we're loading an elem that was derived from a different type // than the true type of the underlying decl, we cannot deref directly - const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayOrVector(mod)) x: { - const deref_elem_ty = deref.pointee.?.ty.childType(mod); - break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or - (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok; + const ty_matches = if (deref.pointee) |pointee| match: { + const ty = pointee.typeOf(mod); + if (!ty.isArrayOrVector(mod)) break :match false; + const deref_elem_ty = ty.childType(mod); + if ((try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok) break :match true; + if ((try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok) break :match true; + break :match false; } else false; if (!ty_matches) { deref.pointee = null; break :blk deref; } - var array_tv = deref.pointee.?; - const check_len = array_tv.ty.arrayLenIncludingSentinel(mod); + var array_val = deref.pointee.?; + const check_len = array_val.typeOf(mod).arrayLenIncludingSentinel(mod); if (maybe_array_ty) |load_ty| { // It's possible that we're loading a [N]T, in which case we'd like to slice // the pointee array directly from our parent array. if (load_ty.isArrayOrVector(mod) and load_ty.childType(mod).eql(elem_ty, mod)) { const len = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel(mod)); const elem_idx = try sema.usizeCast(block, src, elem_ptr.index); - deref.pointee = if (elem_ptr.index + len <= check_len) TypedValue{ - .ty = try mod.arrayType(.{ - .len = len, - .child = elem_ty.toIntern(), - }), - .val = try array_tv.val.sliceArray(sema, elem_idx, elem_idx + len), + deref.pointee = if (elem_ptr.index + len <= check_len) switch (array_val) { + .aggregate => |a| .{ .aggregate = .{ + .ty = (try mod.arrayType(.{ .len = len, .child = elem_ty.toIntern() })).toIntern(), + .elems = a.elems[elem_idx..][0..len], + } }, + else => .{ + .interned = (try (Value.fromInterned( + try array_val.intern(mod, sema.arena), + ).sliceArray(sema, elem_idx, elem_idx + len))).toIntern(), + }, } else null; break :blk deref; } @@ -31536,18 +31328,12 @@ fn beginComptimePtrLoad( break :blk deref; } if (elem_ptr.index == check_len - 1) { - if (array_tv.ty.sentinel(mod)) |sent| { - deref.pointee = TypedValue{ - .ty = elem_ty, - .val = sent, - }; + if (array_val.typeOf(mod).sentinel(mod)) |sent| { + deref.pointee = .{ .interned = sent.toIntern() }; break :blk deref; } } - deref.pointee = TypedValue{ - .ty = elem_ty, - .val = try array_tv.val.elemValue(mod, @intCast(elem_ptr.index)), - }; + deref.pointee = try array_val.getElem(mod, @intCast(elem_ptr.index)); break :blk deref; }, .field => |field_ptr| blk: { @@ -31571,37 +31357,17 @@ fn beginComptimePtrLoad( deref.ty_without_well_defined_layout = container_ty; } - const tv = deref.pointee orelse { - deref.pointee = null; - break :blk deref; - }; + const pointee = deref.pointee orelse break :blk deref; + const pointee_ty = pointee.typeOf(mod); const coerce_in_mem_ok = - (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or - (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok; + (try sema.coerceInMemoryAllowed(block, container_ty, pointee_ty, false, target, src, src)) == .ok or + (try sema.coerceInMemoryAllowed(block, pointee_ty, container_ty, false, target, src, src)) == .ok; if (!coerce_in_mem_ok) { deref.pointee = null; break :blk deref; } - if (container_ty.isSlice(mod)) { - deref.pointee = switch (field_index) { - Value.slice_ptr_index => TypedValue{ - .ty = container_ty.slicePtrFieldType(mod), - .val = tv.val.slicePtr(mod), - }, - Value.slice_len_index => TypedValue{ - .ty = Type.usize, - .val = Value.fromInterned(ip.indexToKey(try tv.val.intern(tv.ty, mod)).slice.len), - }, - else => unreachable, - }; - } else { - const field_ty = container_ty.structFieldType(field_index, mod); - deref.pointee = TypedValue{ - .ty = field_ty, - .val = try tv.val.fieldValue(mod, field_index), - }; - } + deref.pointee = try pointee.getElem(mod, field_index); break :blk deref; }, }, @@ -31612,9 +31378,9 @@ fn beginComptimePtrLoad( else => unreachable, }; - if (deref.pointee) |tv| { - if (deref.parent == null and tv.ty.hasWellDefinedLayout(mod)) { - deref.parent = .{ .tv = tv, .byte_offset = 0 }; + if (deref.pointee) |val| { + if (deref.parent == null and val.typeOf(mod).hasWellDefinedLayout(mod)) { + deref.parent = .{ .val = val, .byte_offset = 0 }; } } return deref; @@ -38289,17 +38055,18 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value else => |e| return e, }; - if (deref.pointee) |tv| { + if (deref.pointee) |pointee| { + const uncoerced_val = Value.fromInterned(try pointee.intern(mod, sema.arena)); + const ty = Type.fromInterned(mod.intern_pool.typeOf(uncoerced_val.toIntern())); const coerce_in_mem_ok = - (try sema.coerceInMemoryAllowed(block, load_ty, tv.ty, false, target, src, src)) == .ok or - (try sema.coerceInMemoryAllowed(block, tv.ty, load_ty, false, target, src, src)) == .ok; + (try sema.coerceInMemoryAllowed(block, load_ty, ty, false, target, src, src)) == .ok or + (try sema.coerceInMemoryAllowed(block, ty, load_ty, false, target, src, src)) == .ok; if (coerce_in_mem_ok) { // We have a Value that lines up in virtual memory exactly with what we want to load, // and it is in-memory coercible to load_ty. It may be returned without modifications. // Move mutable decl values to the InternPool and assert other decls are already in // the InternPool. - const uncoerced_val = if (deref.is_mutable) try tv.val.intern(tv.ty, mod) else tv.val.toIntern(); - const coerced_val = try mod.getCoerced(Value.fromInterned(uncoerced_val), load_ty); + const coerced_val = try mod.getCoerced(uncoerced_val, load_ty); return .{ .val = coerced_val }; } } @@ -38313,21 +38080,35 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value const load_sz = try sema.typeAbiSize(load_ty); // Try the smaller bit-cast first, since that's more efficient than using the larger `parent` - if (deref.pointee) |tv| if (load_sz <= try sema.typeAbiSize(tv.ty)) - return DerefResult{ .val = (try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0)) orelse return .runtime_load }; + if (deref.pointee) |pointee| { + const val_ip_index = try pointee.intern(mod, sema.arena); + const val = Value.fromInterned(val_ip_index); + const ty = Type.fromInterned(mod.intern_pool.typeOf(val_ip_index)); + if (load_sz <= try sema.typeAbiSize(ty)) { + return .{ .val = (try sema.bitCastVal(block, src, val, ty, load_ty, 0)) orelse return .runtime_load }; + } + } // If that fails, try to bit-cast from the largest parent value with a well-defined layout - if (deref.parent) |parent| if (load_sz + parent.byte_offset <= try sema.typeAbiSize(parent.tv.ty)) - return DerefResult{ .val = (try sema.bitCastVal(block, src, parent.tv.val, parent.tv.ty, load_ty, parent.byte_offset)) orelse return .runtime_load }; + if (deref.parent) |parent| { + const parent_ip_index = try parent.val.intern(mod, sema.arena); + const parent_val = Value.fromInterned(parent_ip_index); + const parent_ty = Type.fromInterned(mod.intern_pool.typeOf(parent_ip_index)); + if (load_sz + parent.byte_offset <= try sema.typeAbiSize(parent_ty)) { + return .{ .val = (try sema.bitCastVal(block, src, parent_val, parent_ty, load_ty, parent.byte_offset)) orelse return .runtime_load }; + } + } if (deref.ty_without_well_defined_layout) |bad_ty| { // We got no parent for bit-casting, or the parent we got was too small. Either way, the problem // is that some type we encountered when de-referencing does not have a well-defined layout. - return DerefResult{ .needed_well_defined = bad_ty }; + return .{ .needed_well_defined = bad_ty }; } else { // If all encountered types had well-defined layouts, the parent is the root decl and it just // wasn't big enough for the load. - return DerefResult{ .out_of_bounds = deref.parent.?.tv.ty }; + const parent_ip_index = try deref.parent.?.val.intern(mod, sema.arena); + const parent_ty = Type.fromInterned(mod.intern_pool.typeOf(parent_ip_index)); + return .{ .out_of_bounds = parent_ty }; } } diff --git a/src/Value.zig b/src/Value.zig index c220f6d0d9c4..af24d68d7cfe 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -1627,7 +1627,9 @@ pub fn maybeElemValueFull(val: Value, sema: ?*Sema, mod: *Module, index: usize) .ptr => |ptr| switch (ptr.addr) { .decl => |decl| mod.declPtr(decl).val.maybeElemValueFull(sema, mod, index), .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).maybeElemValueFull(sema, mod, index), - .comptime_alloc => |idx| if (sema) |s| s.getComptimeAlloc(idx).val.maybeElemValueFull(sema, mod, index) else null, + .comptime_alloc => |idx| if (sema) |s| Value.fromInterned( + try s.getComptimeAlloc(idx).val.intern(mod, s.arena), + ).maybeElemValueFull(sema, mod, index) else null, .int, .eu_payload => null, .opt_payload => |base| Value.fromInterned(base).maybeElemValueFull(sema, mod, index), .comptime_field => |field_val| Value.fromInterned(field_val).maybeElemValueFull(sema, mod, index), @@ -1697,7 +1699,9 @@ pub fn sliceArray( else => switch (mod.intern_pool.indexToKey(val.toIntern())) { .ptr => |ptr| switch (ptr.addr) { .decl => |decl| try mod.declPtr(decl).val.sliceArray(sema, start, end), - .comptime_alloc => |idx| sema.getComptimeAlloc(idx).val.sliceArray(sema, start, end), + .comptime_alloc => |idx| try Value.fromInterned( + try sema.getComptimeAlloc(idx).val.intern(mod, sema.arena), + ).sliceArray(sema, start, end), .comptime_field => |comptime_field| Value.fromInterned(comptime_field) .sliceArray(sema, start, end), .elem => |elem| Value.fromInterned(elem.base) diff --git a/src/mutable_value.zig b/src/mutable_value.zig new file mode 100644 index 000000000000..327c35410823 --- /dev/null +++ b/src/mutable_value.zig @@ -0,0 +1,508 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const Zcu = @import("Module.zig"); +const InternPool = @import("InternPool.zig"); +const Type = @import("type.zig").Type; +const Value = @import("Value.zig"); + +/// We use a tagged union here because while it wastes a few bytes for some tags, having a fixed +/// size for the type makes the common `aggregate` representation more efficient. +/// For aggregates, the sentinel value, if any, *is* stored. +pub const MutableValue = union(enum) { + /// An interned value. + interned: InternPool.Index, + /// An error union value which is a payload (not an error). + eu_payload: SubValue, + /// An optional value which is a payload (not `null`). + opt_payload: SubValue, + /// An aggregate consisting of a single repeated value. + repeated: SubValue, + /// An aggregate of `u8` consisting of "plain" bytes (no lazy or undefined elements). + bytes: Bytes, + /// An aggregate with arbitrary sub-values. + aggregate: Aggregate, + /// A slice, containing a pointer and length. + slice: Slice, + /// An instance of a union. + un: Union, + + pub const SubValue = struct { + ty: InternPool.Index, + child: *MutableValue, + }; + pub const Bytes = struct { + ty: InternPool.Index, + data: []u8, + }; + pub const Aggregate = struct { + ty: InternPool.Index, + elems: []MutableValue, + }; + pub const Slice = struct { + ty: InternPool.Index, + /// Must have the appropriate many-ptr type. + /// TODO: we want this to be an `InternPool.Index`, but `Sema.beginComptimePtrMutation` doesn't support it. + ptr: *MutableValue, + /// Must be of type `usize`. + /// TODO: we want this to be an `InternPool.Index`, but `Sema.beginComptimePtrMutation` doesn't support it. + len: *MutableValue, + }; + pub const Union = struct { + ty: InternPool.Index, + tag: InternPool.Index, + payload: *MutableValue, + }; + + pub fn intern(mv: MutableValue, zcu: *Zcu, arena: Allocator) Allocator.Error!InternPool.Index { + const ip = &zcu.intern_pool; + const gpa = zcu.gpa; + return switch (mv) { + .interned => |ip_index| ip_index, + .eu_payload => |sv| try ip.get(gpa, .{ .error_union = .{ + .ty = sv.ty, + .val = .{ .payload = try sv.child.intern(zcu, arena) }, + } }), + .opt_payload => |sv| try ip.get(gpa, .{ .opt = .{ + .ty = sv.ty, + .val = try sv.child.intern(zcu, arena), + } }), + .repeated => |sv| try ip.get(gpa, .{ .aggregate = .{ + .ty = sv.ty, + .storage = .{ .repeated_elem = try sv.child.intern(zcu, arena) }, + } }), + .bytes => |b| try ip.get(gpa, .{ .aggregate = .{ + .ty = b.ty, + .storage = .{ .bytes = b.data }, + } }), + .aggregate => |a| { + const elems = try arena.alloc(InternPool.Index, a.elems.len); + for (a.elems, elems) |mut_elem, *interned_elem| { + interned_elem.* = try mut_elem.intern(zcu, arena); + } + return ip.get(gpa, .{ .aggregate = .{ + .ty = a.ty, + .storage = .{ .elems = elems }, + } }); + }, + .slice => |s| try ip.get(gpa, .{ .slice = .{ + .ty = s.ty, + .ptr = try s.ptr.intern(zcu, arena), + .len = try s.len.intern(zcu, arena), + } }), + .un => |u| try ip.get(gpa, .{ .un = .{ + .ty = u.ty, + .tag = u.tag, + .val = try u.payload.intern(zcu, arena), + } }), + }; + } + + /// Un-interns the top level of this `MutableValue`, if applicable. + /// * Non-error error unions use `eu_payload` + /// * Non-null optionals use `eu_payload + /// * Slices use `slice` + /// * Unions use `un` + /// * Aggregates use `repeated` or `bytes` or `aggregate` + /// If `!allow_bytes`, the `bytes` representation will not be used. + /// If `!allow_repeated`, the `repeated` representation will not be used. + pub fn unintern( + mv: *MutableValue, + zcu: *Zcu, + arena: Allocator, + allow_bytes: bool, + allow_repeated: bool, + ) Allocator.Error!void { + const ip = &zcu.intern_pool; + const gpa = zcu.gpa; + switch (mv.*) { + .interned => |ip_index| switch (ip.indexToKey(ip_index)) { + .opt => |opt| if (opt.val != .none) { + const mut_payload = try arena.create(MutableValue); + mut_payload.* = .{ .interned = opt.val }; + mv.* = .{ .opt_payload = .{ + .ty = opt.ty, + .child = mut_payload, + } }; + }, + .error_union => |eu| switch (eu.val) { + .err_name => {}, + .payload => |payload| { + const mut_payload = try arena.create(MutableValue); + mut_payload.* = .{ .interned = payload }; + mv.* = .{ .eu_payload = .{ + .ty = eu.ty, + .child = mut_payload, + } }; + }, + }, + .slice => |slice| { + const ptr = try arena.create(MutableValue); + const len = try arena.create(MutableValue); + ptr.* = .{ .interned = slice.ptr }; + len.* = .{ .interned = slice.len }; + mv.* = .{ .slice = .{ + .ty = slice.ty, + .ptr = ptr, + .len = len, + } }; + }, + .un => |un| { + const payload = try arena.create(MutableValue); + payload.* = .{ .interned = un.val }; + mv.* = .{ .un = .{ + .ty = un.ty, + .tag = un.tag, + .payload = payload, + } }; + }, + .aggregate => |agg| switch (agg.storage) { + .bytes => |bytes| { + assert(bytes.len == ip.aggregateTypeLenIncludingSentinel(agg.ty)); + assert(ip.childType(agg.ty) == .u8_type); + if (allow_bytes) { + const arena_bytes = try arena.alloc(u8, bytes.len); + @memcpy(arena_bytes, bytes); + mv.* = .{ .bytes = .{ + .ty = agg.ty, + .data = arena_bytes, + } }; + } else { + const mut_elems = try arena.alloc(MutableValue, bytes.len); + for (bytes, mut_elems) |b, *mut_elem| { + mut_elem.* = .{ .interned = try ip.get(gpa, .{ .int = .{ + .ty = .u8_type, + .storage = .{ .u64 = b }, + } }) }; + } + mv.* = .{ .aggregate = .{ + .ty = agg.ty, + .elems = mut_elems, + } }; + } + }, + .elems => |elems| { + assert(elems.len == ip.aggregateTypeLenIncludingSentinel(agg.ty)); + const mut_elems = try arena.alloc(MutableValue, elems.len); + for (elems, mut_elems) |interned_elem, *mut_elem| { + mut_elem.* = .{ .interned = interned_elem }; + } + mv.* = .{ .aggregate = .{ + .ty = agg.ty, + .elems = mut_elems, + } }; + }, + .repeated_elem => |val| { + if (allow_repeated) { + const repeated_val = try arena.create(MutableValue); + repeated_val.* = .{ .interned = val }; + mv.* = .{ .repeated = .{ + .ty = agg.ty, + .child = repeated_val, + } }; + } else { + const len = ip.aggregateTypeLenIncludingSentinel(agg.ty); + const mut_elems = try arena.alloc(MutableValue, @intCast(len)); + @memset(mut_elems, .{ .interned = val }); + mv.* = .{ .aggregate = .{ + .ty = agg.ty, + .elems = mut_elems, + } }; + } + }, + }, + .undef => |ty_ip| switch (Type.fromInterned(ty_ip).zigTypeTag(zcu)) { + .Struct, .Array, .Vector => |type_tag| { + const ty = Type.fromInterned(ty_ip); + const opt_sent = ty.sentinel(zcu); + if (type_tag == .Struct or opt_sent != null or !allow_repeated) { + const len_no_sent = ip.aggregateTypeLen(ty_ip); + const elems = try arena.alloc(MutableValue, @intCast(len_no_sent + @intFromBool(opt_sent != null))); + switch (type_tag) { + .Array, .Vector => { + const elem_ty = ip.childType(ty_ip); + const undef_elem = try ip.get(gpa, .{ .undef = elem_ty }); + @memset(elems[0..@intCast(len_no_sent)], .{ .interned = undef_elem }); + }, + .Struct => for (elems[0..@intCast(len_no_sent)], 0..) |*mut_elem, i| { + const field_ty = ty.structFieldType(i, zcu).toIntern(); + mut_elem.* = .{ .interned = try ip.get(gpa, .{ .undef = field_ty }) }; + }, + else => unreachable, + } + if (opt_sent) |s| elems[@intCast(len_no_sent)] = .{ .interned = s.toIntern() }; + mv.* = .{ .aggregate = .{ + .ty = ty_ip, + .elems = elems, + } }; + } else { + const repeated_val = try arena.create(MutableValue); + repeated_val.* = .{ + .interned = try ip.get(gpa, .{ .undef = ip.childType(ty_ip) }), + }; + mv.* = .{ .repeated = .{ + .ty = ty_ip, + .child = repeated_val, + } }; + } + }, + .Union => { + const payload = try arena.create(MutableValue); + // HACKHACK: this logic is silly, but Sema detects it and reverts the change where needed. + // See comment at the top of `Sema.beginComptimePtrMutationInner`. + payload.* = .{ .interned = .undef }; + mv.* = .{ .un = .{ + .ty = ty_ip, + .tag = .none, + .payload = payload, + } }; + }, + .Pointer => { + const ptr_ty = ip.indexToKey(ty_ip).ptr_type; + if (ptr_ty.flags.size != .Slice) return; + const ptr = try arena.create(MutableValue); + const len = try arena.create(MutableValue); + ptr.* = .{ .interned = try ip.get(gpa, .{ .undef = ip.slicePtrType(ty_ip) }) }; + len.* = .{ .interned = try ip.get(gpa, .{ .undef = .usize_type }) }; + mv.* = .{ .slice = .{ + .ty = ty_ip, + .ptr = ptr, + .len = len, + } }; + }, + else => {}, + }, + else => {}, + }, + .bytes => |bytes| if (!allow_bytes) { + const elems = try arena.alloc(MutableValue, bytes.data.len); + for (bytes.data, elems) |byte, *interned_byte| { + interned_byte.* = .{ .interned = try ip.get(gpa, .{ .int = .{ + .ty = .u8_type, + .storage = .{ .u64 = byte }, + } }) }; + } + mv.* = .{ .aggregate = .{ + .ty = bytes.ty, + .elems = elems, + } }; + }, + else => {}, + } + } + + /// Get a pointer to the `MutableValue` associated with a field/element. + /// The returned pointer can be safety mutated through to modify the field value. + /// The returned pointer is valid until the representation of `mv` changes. + /// This function does *not* support accessing the ptr/len field of slices. + pub fn elem( + mv: *MutableValue, + zcu: *Zcu, + arena: Allocator, + field_idx: usize, + ) Allocator.Error!*MutableValue { + const ip = &zcu.intern_pool; + const gpa = zcu.gpa; + // Convert to the `aggregate` representation. + switch (mv) { + .eu_payload, .opt_payload, .slice, .un => unreachable, + .interned => { + try mv.unintern(zcu, arena, false, false); + }, + .bytes => |bytes| { + const elems = try arena.alloc(MutableValue, bytes.data.len); + for (bytes.data, elems) |byte, interned_byte| { + interned_byte.* = try ip.get(gpa, .{ .int = .{ + .ty = .u8_type, + .storage = .{ .u64 = byte }, + } }); + } + mv.* = .{ .aggregate = .{ + .ty = bytes.ty, + .elems = elems, + } }; + }, + .repeated => |repeated| { + const len = ip.aggregateTypeLenIncludingSentinel(repeated.ty); + const elems = try arena.alloc(MutableValue, @intCast(len)); + @memset(elems, repeated.child.*); + mv.* = .{ .aggregate = .{ + .ty = repeated.ty, + .elems = elems, + } }; + }, + .aggregate => {}, + } + return &mv.aggregate.elems[field_idx]; + } + + /// Modify a single field of a `MutableValue` which represents an aggregate or slice, leaving others + /// untouched. When an entire field must be modified, this should be used in preference to `elemPtr` + /// to allow for an optimal representation. + /// For slices, uses `Value.slice_ptr_index` and `Value.slice_len_index`. + pub fn setElem( + mv: *MutableValue, + zcu: *Zcu, + arena: Allocator, + field_idx: usize, + field_val: MutableValue, + ) Allocator.Error!void { + const ip = &zcu.intern_pool; + const is_trivial_int = field_val.isTrivialInt(zcu); + try mv.unintern(arena, is_trivial_int, true); + switch (mv) { + .interned, + .eu_payload, + .opt_payload, + .un, + => unreachable, + .slice => |*s| switch (field_idx) { + Value.slice_ptr_index => s.ptr = field_val, + Value.slice_len_index => s.len = field_val, + }, + .bytes => |b| { + assert(is_trivial_int); + assert(field_val.typeOf() == Type.u8); + b.data[field_idx] = Value.fromInterned(field_val.interned).toUnsignedInt(zcu); + }, + .repeated => |r| { + if (field_val.eqlTrivial(r.child.*)) return; + // We must switch to either the `aggregate` or the `bytes` representation. + const len_inc_sent = ip.aggregateTypeLenIncludingSentinel(r.ty); + if (ip.zigTypeTag(r.ty) != .Struct and + is_trivial_int and + Type.fromInterned(r.ty).childType(zcu) == .u8_type and + r.child.isTrivialInt(zcu)) + { + // We can use the `bytes` representation. + const bytes = try arena.alloc(u8, @intCast(len_inc_sent)); + const repeated_byte = Value.fromInterned(r.child.interned).getUnsignedInt(zcu); + @memset(bytes, repeated_byte); + bytes[field_idx] = Value.fromInterned(field_val.interned).getUnsignedInt(zcu); + mv.* = .{ .bytes = .{ + .ty = r.ty, + .data = bytes, + } }; + } else { + // We must use the `aggregate` representation. + const mut_elems = try arena.alloc(u8, @intCast(len_inc_sent)); + @memset(mut_elems, r.child.*); + mut_elems[field_idx] = field_val; + mv.* = .{ .aggregate = .{ + .ty = r.ty, + .elems = mut_elems, + } }; + } + }, + .aggregate => |a| { + a.elems[field_idx] = field_val; + const is_struct = ip.zigTypeTag(a.ty) == .Struct; + // Attempt to switch to a more efficient representation. + const is_repeated = for (a.elems) |e| { + if (!e.eqlTrivial(field_val)) break false; + } else true; + if (is_repeated) { + // Switch to `repeated` repr + const mut_repeated = try arena.create(MutableValue); + mut_repeated.* = field_val; + mv.* = .{ .repeated = .{ + .ty = a.ty, + .child = mut_repeated, + } }; + } else if (!is_struct and is_trivial_int and Type.fromInterned(a.ty).childType(zcu).toIntern() == .u8_type) { + // See if we can switch to `bytes` repr + for (a.elems) |e| { + switch (e) { + else => break, + .interned => |ip_index| switch (ip.indexToKey(ip_index)) { + else => break, + .int => |int| switch (int.storage) { + .u64, .i64, .big_int => {}, + .lazy_align, .lazy_size => break, + }, + }, + } + } else { + const bytes = try arena.alloc(u8, a.elems.len); + for (a.elems, bytes) |elem_val, *b| { + b.* = Value.fromInterned(elem_val.interned).toUnsignedInt(zcu); + } + mv.* = .{ .bytes = .{ + .ty = a.ty, + .data = bytes, + } }; + } + } + }, + } + } + + /// Get the value of a single field of a `MutableValue` which represents an aggregate or slice. + /// For slices, uses `Value.slice_ptr_index` and `Value.slice_len_index`. + pub fn getElem( + mv: MutableValue, + zcu: *Zcu, + field_idx: usize, + ) Allocator.Error!MutableValue { + return switch (mv) { + .eu_payload, + .opt_payload, + => unreachable, + .interned => |ip_index| { + const ty = Type.fromInterned(zcu.intern_pool.typeOf(ip_index)); + switch (ty.zigTypeTag(zcu)) { + .Array, .Vector => return .{ .interned = (try Value.fromInterned(ip_index).elemValue(zcu, field_idx)).toIntern() }, + .Struct, .Union => return .{ .interned = (try Value.fromInterned(ip_index).fieldValue(zcu, field_idx)).toIntern() }, + .Pointer => { + assert(ty.isSlice(zcu)); + return switch (field_idx) { + Value.slice_ptr_index => .{ .interned = Value.fromInterned(ip_index).slicePtr(zcu).toIntern() }, + Value.slice_len_index => .{ .interned = switch (zcu.intern_pool.indexToKey(ip_index)) { + .undef => try zcu.intern(.{ .undef = .usize_type }), + .slice => |s| s.len, + else => unreachable, + } }, + else => unreachable, + }; + }, + else => unreachable, + } + }, + .un => |un| { + // TODO assert the tag is correct + return un.payload.*; + }, + .slice => |s| switch (field_idx) { + Value.slice_ptr_index => s.ptr.*, + Value.slice_len_index => s.len.*, + else => unreachable, + }, + .bytes => |b| .{ .interned = try zcu.intern(.{ .int = .{ + .ty = .u8_type, + .storage = .{ .u64 = b.data[field_idx] }, + } }) }, + .repeated => |r| r.child.*, + .aggregate => |a| a.elems[field_idx], + }; + } + + fn isTrivialInt(mv: MutableValue, zcu: *Zcu) bool { + return switch (mv) { + else => false, + .interned => |ip_index| switch (zcu.intern_pool.indexToKey(ip_index)) { + else => false, + .int => |int| switch (int.storage) { + .u64, .i64, .big_int => true, + .lazy_align, .lazy_size => false, + }, + }, + }; + } + + pub fn typeOf(mv: MutableValue, zcu: *Zcu) Type { + return switch (mv) { + .interned => |ip_index| Type.fromInterned(zcu.intern_pool.typeOf(ip_index)), + inline else => |x| Type.fromInterned(x.ty), + }; + } +}; From 884d957b6c291961536c10401f60264da26cba30 Mon Sep 17 00:00:00 2001 From: mlugg Date: Tue, 26 Mar 2024 00:05:08 +0000 Subject: [PATCH 03/14] compiler: eliminate legacy Value representation Good riddance! Most of these changes are trivial. There's a fix for a minor bug this exposed in `Value.readFromPackedMemory`, but aside from that, it's all just things like changing `intern` calls to `toIntern`. --- src/Module.zig | 11 +- src/Sema.zig | 116 ++---- src/TypedValue.zig | 609 ++++++++++++---------------- src/Value.zig | 783 ++++++++---------------------------- src/arch/wasm/CodeGen.zig | 2 +- src/arch/x86_64/CodeGen.zig | 2 +- src/codegen.zig | 2 +- src/codegen/c.zig | 4 +- src/codegen/llvm.zig | 2 +- src/type.zig | 2 +- 10 files changed, 476 insertions(+), 1057 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index a11194c10349..4391472fa530 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -497,13 +497,6 @@ pub const Decl = struct { }; } - pub fn internValue(decl: *Decl, zcu: *Zcu) Allocator.Error!InternPool.Index { - assert(decl.has_tv); - const ip_index = try decl.val.intern(decl.typeOf(zcu), zcu); - decl.val = Value.fromInterned(ip_index); - return ip_index; - } - pub fn isFunction(decl: Decl, zcu: *const Zcu) !bool { const tv = try decl.typedValue(zcu); return tv.ty.zigTypeTag(zcu) == .Fn; @@ -3763,7 +3756,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { }, } - decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod))); + decl.val = decl_tv.val; // Function linksection, align, and addrspace were already set by Sema if (!is_func) { decl.alignment = blk: { @@ -5624,8 +5617,6 @@ pub fn markDeclAlive(mod: *Module, decl: *Decl) Allocator.Error!void { if (decl.alive) return; decl.alive = true; - _ = try decl.internValue(mod); - // This is the first time we are marking this Decl alive. We must // therefore recurse into its value and mark any Decl it references // as also alive, so that any Decl referenced does not get garbage collected. diff --git a/src/Sema.zig b/src/Sema.zig index 7db1462787e3..0d387faacf5e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -7835,7 +7835,7 @@ fn analyzeCall( if (is_comptime_call) { const result_val = try sema.resolveConstValue(block, .unneeded, result, undefined); - const result_interned = try result_val.intern2(sema.fn_ret_ty, mod); + const result_interned = result_val.toIntern(); // Transform ad-hoc inferred error set types into concrete error sets. const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_interned); @@ -7856,8 +7856,7 @@ fn analyzeCall( } if (try sema.resolveValue(result)) |result_val| { - const result_interned = try result_val.intern2(sema.fn_ret_ty, mod); - const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_interned); + const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_val.toIntern()); break :res2 Air.internedToRef(result_transformed); } @@ -8042,7 +8041,7 @@ fn analyzeInlineCallArg( // when the hash function is called. const resolved_arg_val = try ics.caller().resolveLazyValue(arg_val); should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(mod); - memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(Type.fromInterned(param_ty), mod); + memoized_arg_values[arg_i.*] = resolved_arg_val.toIntern(); } else { ics.callee().inst_map.putAssumeCapacityNoClobber(inst, casted_arg); } @@ -8081,7 +8080,7 @@ fn analyzeInlineCallArg( // when the hash function is called. const resolved_arg_val = try ics.caller().resolveLazyValue(arg_val); should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(mod); - memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(ics.caller().typeOf(uncasted_arg), mod); + memoized_arg_values[arg_i.*] = resolved_arg_val.toIntern(); } else { if (zir_tags[@intFromEnum(inst)] == .param_anytype_comptime) { _ = try ics.caller().resolveConstValue(arg_block, arg_src, uncasted_arg, .{ @@ -14270,7 +14269,7 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. const elems = try sema.arena.alloc(InternPool.Index, vec_len); for (elems, 0..) |*elem, i| { const elem_val = try val.elemValue(mod, i); - elem.* = try (try elem_val.bitwiseNot(scalar_type, sema.arena, mod)).intern(scalar_type, mod); + elem.* = (try elem_val.bitwiseNot(scalar_type, sema.arena, mod)).toIntern(); } return Air.internedToRef((try mod.intern(.{ .aggregate = .{ .ty = operand_type.toIntern(), @@ -14521,7 +14520,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }; const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, operand_src); const coerced_elem_val = try sema.resolveConstValue(block, operand_src, coerced_elem_val_inst, undefined); - element_vals[elem_i] = try coerced_elem_val.intern(resolved_elem_ty, mod); + element_vals[elem_i] = coerced_elem_val.toIntern(); } while (elem_i < result_len) : (elem_i += 1) { const rhs_elem_i = elem_i - lhs_len; @@ -14534,7 +14533,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }; const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, operand_src); const coerced_elem_val = try sema.resolveConstValue(block, operand_src, coerced_elem_val_inst, undefined); - element_vals[elem_i] = try coerced_elem_val.intern(resolved_elem_ty, mod); + element_vals[elem_i] = coerced_elem_val.toIntern(); } return sema.addConstantMaybeRef(try mod.intern(.{ .aggregate = .{ .ty = result_ty.toIntern(), @@ -15813,7 +15812,7 @@ fn intRem( for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try sema.intRemScalar(lhs_elem, rhs_elem, scalar_ty)).intern(scalar_ty, mod); + scalar.* = (try sema.intRemScalar(lhs_elem, rhs_elem, scalar_ty)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -17753,7 +17752,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const info = ty.intInfo(mod); const field_values = .{ // signedness: Signedness, - try (try mod.enumValueFieldIndex(signedness_ty, @intFromEnum(info.signedness))).intern(signedness_ty, mod), + (try mod.enumValueFieldIndex(signedness_ty, @intFromEnum(info.signedness))).toIntern(), // bits: u16, (try mod.intValue(Type.u16, info.bits)).toIntern(), }; @@ -17823,7 +17822,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const field_values = .{ // size: Size, - try (try mod.enumValueFieldIndex(ptr_size_ty, @intFromEnum(info.flags.size))).intern(ptr_size_ty, mod), + (try mod.enumValueFieldIndex(ptr_size_ty, @intFromEnum(info.flags.size))).toIntern(), // is_const: bool, Value.makeBool(info.flags.is_const).toIntern(), // is_volatile: bool, @@ -17831,7 +17830,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // alignment: comptime_int, alignment.toIntern(), // address_space: AddressSpace - try (try mod.enumValueFieldIndex(addrspace_ty, @intFromEnum(info.flags.address_space))).intern(addrspace_ty, mod), + (try mod.enumValueFieldIndex(addrspace_ty, @intFromEnum(info.flags.address_space))).toIntern(), // child: type, info.child, // is_allowzero: bool, @@ -19975,8 +19974,8 @@ fn unionInit( const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index); return Air.internedToRef((try mod.intern(.{ .un = .{ .ty = union_ty.toIntern(), - .tag = try tag_val.intern(tag_ty, mod), - .val = try init_val.intern(field_ty, mod), + .tag = tag_val.toIntern(), + .val = init_val.toIntern(), } }))); } @@ -20099,8 +20098,8 @@ fn zirStructInit( if (try sema.resolveValue(init_inst)) |val| { const struct_val = Value.fromInterned((try mod.intern(.{ .un = .{ .ty = resolved_ty.toIntern(), - .tag = try tag_val.intern(tag_ty, mod), - .val = try val.intern(field_ty, mod), + .tag = tag_val.toIntern(), + .val = val.toIntern(), } }))); const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val.toIntern()), src); const final_val = (try sema.resolveValue(final_val_inst)).?; @@ -20400,7 +20399,7 @@ fn structInitAnon( return sema.failWithOwnedErrorMsg(block, msg); } if (try sema.resolveValue(init)) |init_val| { - field_val.* = try init_val.intern(Type.fromInterned(field_ty.*), mod); + field_val.* = init_val.toIntern(); } else { field_val.* = .none; runtime_index = @intCast(i_usize); @@ -20577,13 +20576,9 @@ fn zirArrayInit( const runtime_index = opt_runtime_index orelse { const elem_vals = try sema.arena.alloc(InternPool.Index, resolved_args.len); - for (elem_vals, resolved_args, 0..) |*val, arg, i| { - const elem_ty = if (is_tuple) - array_ty.structFieldType(i, mod) - else - array_ty.elemType2(mod); + for (elem_vals, resolved_args) |*val, arg| { // We checked that all args are comptime above. - val.* = try ((sema.resolveValue(arg) catch unreachable).?).intern(elem_ty, mod); + val.* = (sema.resolveValue(arg) catch unreachable).?.toIntern(); } const arr_val = try mod.intern(.{ .aggregate = .{ .ty = array_ty.toIntern(), @@ -20998,7 +20993,7 @@ fn maybeConstantUnaryMath( const elems = try sema.arena.alloc(InternPool.Index, vec_len); for (elems, 0..) |*elem, i| { const elem_val = try val.elemValue(sema.mod, i); - elem.* = try (try eval(elem_val, scalar_ty, sema.arena, sema.mod)).intern(scalar_ty, mod); + elem.* = (try eval(elem_val, scalar_ty, sema.arena, sema.mod)).toIntern(); } return Air.internedToRef((try mod.intern(.{ .aggregate = .{ .ty = result_ty.toIntern(), @@ -23216,7 +23211,8 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const elems = try sema.arena.alloc(InternPool.Index, operand_ty.vectorLen(mod)); for (elems, 0..) |*elem, i| { const elem_val = try val.elemValue(mod, i); - elem.* = try (try elem_val.intTrunc(operand_scalar_ty, sema.arena, dest_info.signedness, dest_info.bits, mod)).intern(dest_scalar_ty, mod); + const uncoerced_elem = try elem_val.intTrunc(operand_scalar_ty, sema.arena, dest_info.signedness, dest_info.bits, mod); + elem.* = (try mod.getCoerced(uncoerced_elem, dest_scalar_ty)).toIntern(); } return Air.internedToRef((try mod.intern(.{ .aggregate = .{ .ty = dest_ty.toIntern(), @@ -23330,7 +23326,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const elems = try sema.arena.alloc(InternPool.Index, vec_len); for (elems, 0..) |*elem, i| { const elem_val = try val.elemValue(mod, i); - elem.* = try (try elem_val.byteSwap(scalar_ty, mod, sema.arena)).intern(scalar_ty, mod); + elem.* = (try elem_val.byteSwap(scalar_ty, mod, sema.arena)).toIntern(); } return Air.internedToRef((try mod.intern(.{ .aggregate = .{ .ty = operand_ty.toIntern(), @@ -23378,7 +23374,7 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! const elems = try sema.arena.alloc(InternPool.Index, vec_len); for (elems, 0..) |*elem, i| { const elem_val = try val.elemValue(mod, i); - elem.* = try (try elem_val.bitReverse(scalar_ty, mod, sema.arena)).intern(scalar_ty, mod); + elem.* = (try elem_val.bitReverse(scalar_ty, mod, sema.arena)).toIntern(); } return Air.internedToRef((try mod.intern(.{ .aggregate = .{ .ty = operand_ty.toIntern(), @@ -24311,7 +24307,7 @@ fn analyzeShuffle( } const int = mask_elem_val.toSignedInt(mod); const unsigned: u32 = @intCast(if (int >= 0) int else ~int); - values[i] = try (try (if (int >= 0) a_val else b_val).elemValue(mod, unsigned)).intern(elem_ty, mod); + values[i] = (try (if (int >= 0) a_val else b_val).elemValue(mod, unsigned)).toIntern(); } return Air.internedToRef((try mod.intern(.{ .aggregate = .{ .ty = res_ty.toIntern(), @@ -24417,7 +24413,7 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C for (elems, 0..) |*elem, i| { const pred_elem_val = try pred_val.elemValue(mod, i); const should_choose_a = pred_elem_val.toBool(); - elem.* = try (try (if (should_choose_a) a_val else b_val).elemValue(mod, i)).intern(elem_ty, mod); + elem.* = (try (if (should_choose_a) a_val else b_val).elemValue(mod, i)).toIntern(); } return Air.internedToRef((try mod.intern(.{ .aggregate = .{ @@ -27789,7 +27785,7 @@ fn structFieldPtrByIndex( const val = try mod.intern(.{ .ptr = .{ .ty = ptr_field_ty.toIntern(), .addr = .{ .field = .{ - .base = try struct_ptr_val.intern(struct_ptr_ty, mod), + .base = struct_ptr_val.toIntern(), .index = field_index, } }, } }); @@ -31611,7 +31607,7 @@ fn coerceCompatiblePtrs( } // The comptime Value representation is compatible with both types. return Air.internedToRef( - (try mod.getCoerced(Value.fromInterned((try val.intern(inst_ty, mod))), dest_ty)).toIntern(), + (try mod.getCoerced(val, dest_ty)).toIntern(), ); } try sema.requireRuntimeBlock(block, inst_src, null); @@ -31948,7 +31944,7 @@ fn coerceArrayLike( ref.* = coerced; if (runtime_src == null) { if (try sema.resolveValue(coerced)) |elem_val| { - val.* = try elem_val.intern(dest_elem_ty, mod); + val.* = elem_val.toIntern(); } else { runtime_src = elem_src; } @@ -32013,7 +32009,7 @@ fn coerceTupleToArray( ref.* = coerced; if (runtime_src == null) { if (try sema.resolveValue(coerced)) |elem_val| { - val.* = try elem_val.intern(dest_elem_ty, mod); + val.* = elem_val.toIntern(); } else { runtime_src = elem_src; } @@ -33250,10 +33246,7 @@ fn analyzeSlice( }; if (!new_ptr_val.isUndef(mod)) { - return Air.internedToRef((try mod.getCoerced( - Value.fromInterned((try new_ptr_val.intern(new_ptr_ty, mod))), - return_ty, - )).toIntern()); + return Air.internedToRef((try mod.getCoerced(new_ptr_val, return_ty)).toIntern()); } // Special case: @as([]i32, undefined)[x..x] @@ -33765,7 +33758,7 @@ fn wrapErrorUnionPayload( if (try sema.resolveValue(coerced)) |val| { return Air.internedToRef((try mod.intern(.{ .error_union = .{ .ty = dest_ty.toIntern(), - .val = .{ .payload = try val.intern(dest_payload_ty, mod) }, + .val = .{ .payload = val.toIntern() }, } }))); } try sema.requireRuntimeBlock(block, inst_src, null); @@ -36941,15 +36934,14 @@ fn semaStructFieldInits( }); }; - const field_init = try default_val.intern(field_ty, mod); - if (Value.fromInterned(field_init).canMutateComptimeVarState(mod)) { + if (Value.fromInterned(default_val.toIntern()).canMutateComptimeVarState(mod)) { const init_src = mod.fieldSrcLoc(decl_index, .{ .index = field_i, .range = .value, }).lazy; return sema.fail(&block_scope, init_src, "field default value contains reference to comptime-mutable memory", .{}); } - struct_type.field_inits.get(ip)[field_i] = field_init; + struct_type.field_inits.get(ip)[field_i] = default_val.toIntern(); } } } @@ -37756,7 +37748,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { return sema.failWithOwnedErrorMsg(null, msg); } if (try sema.typeHasOnePossibleValue(field_ty)) |field_opv| { - field_val.* = try field_opv.intern(field_ty, mod); + field_val.* = field_opv.toIntern(); } else return null; } @@ -38310,7 +38302,7 @@ fn intAddInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type, overflow_idx: *usi }, else => |e| return e, }; - scalar.* = try val.intern(scalar_ty, mod); + scalar.* = val.toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -38400,7 +38392,7 @@ fn intSubInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type, overflow_idx: *usi }, else => |e| return e, }; - scalar.* = try val.intern(scalar_ty, mod); + scalar.* = val.toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -38470,8 +38462,8 @@ fn intSubWithOverflow( const lhs_elem = try lhs.elemValue(sema.mod, i); const rhs_elem = try rhs.elemValue(sema.mod, i); const of_math_result = try sema.intSubWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty); - of.* = try of_math_result.overflow_bit.intern(Type.u1, mod); - scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod); + of.* = of_math_result.overflow_bit.toIntern(); + scalar.* = of_math_result.wrapped_result.toIntern(); } return Value.OverflowArithmeticResult{ .overflow_bit = Value.fromInterned((try mod.intern(.{ .aggregate = .{ @@ -38528,10 +38520,9 @@ fn intFromFloat( if (float_ty.zigTypeTag(mod) == .Vector) { const elem_ty = float_ty.scalarType(mod); const result_data = try sema.arena.alloc(InternPool.Index, float_ty.vectorLen(mod)); - const scalar_ty = int_ty.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(sema.mod, i); - scalar.* = try (try sema.intFromFloatScalar(block, src, elem_val, elem_ty, int_ty.scalarType(mod), mode)).intern(scalar_ty, mod); + scalar.* = (try sema.intFromFloatScalar(block, src, elem_val, elem_ty, int_ty.scalarType(mod), mode)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = int_ty.toIntern(), @@ -38724,8 +38715,8 @@ fn intAddWithOverflow( const lhs_elem = try lhs.elemValue(sema.mod, i); const rhs_elem = try rhs.elemValue(sema.mod, i); const of_math_result = try sema.intAddWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty); - of.* = try of_math_result.overflow_bit.intern(Type.u1, mod); - scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod); + of.* = of_math_result.overflow_bit.toIntern(); + scalar.* = of_math_result.wrapped_result.toIntern(); } return Value.OverflowArithmeticResult{ .overflow_bit = Value.fromInterned((try mod.intern(.{ .aggregate = .{ @@ -38835,7 +38826,7 @@ fn compareVector( const lhs_elem = try lhs.elemValue(sema.mod, i); const rhs_elem = try rhs.elemValue(sema.mod, i); const res_bool = try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType(mod)); - scalar.* = try Value.makeBool(res_bool).intern(Type.bool, mod); + scalar.* = Value.makeBool(res_bool).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = (try mod.vectorType(.{ .len = ty.vectorLen(mod), .child = .bool_type })).toIntern(), @@ -39014,29 +39005,6 @@ fn validateRuntimeValue(sema: *Sema, block: *Block, val_src: LazySrcLoc, val: Ai /// Returns true if any value contained in `val` is undefined. fn anyUndef(sema: *Sema, val: Value) !bool { const mod = sema.mod; - if (val.ip_index == .none) return switch (val.tag()) { - .eu_payload => try sema.anyUndef(val.castTag(.eu_payload).?.data), - .opt_payload => try sema.anyUndef(val.castTag(.opt_payload).?.data), - .repeated => try sema.anyUndef(val.castTag(.repeated).?.data), - .slice => { - const slice = val.castTag(.slice).?.data; - for (0..@intCast(slice.len.toUnsignedInt(mod))) |idx| { - if (try sema.anyUndef((try slice.ptr.maybeElemValueFull(sema, mod, idx)).?)) return true; - } - return false; - }, - .bytes => false, - .aggregate => for (val.castTag(.aggregate).?.data) |elem| { - if (try sema.anyUndef(elem)) break true; - } else false, - .@"union" => { - const un = val.castTag(.@"union").?.data; - if (un.tag) |t| { - if (try sema.anyUndef(t)) return true; - } - return sema.anyUndef(un.val); - }, - }; return switch (val.toIntern()) { .undef => true, else => switch (mod.intern_pool.indexToKey(val.toIntern())) { diff --git a/src/TypedValue.zig b/src/TypedValue.zig index 5d9c06241743..4679ce20ee49 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -77,386 +77,275 @@ pub fn print( var val = tv.val; var ty = tv.ty; const ip = &mod.intern_pool; - while (true) switch (val.ip_index) { - .none => switch (val.tag()) { - .aggregate => return printAggregate(ty, val, writer, level, mod), - .@"union" => { - if (level == 0) { - return writer.writeAll(".{ ... }"); - } - const payload = val.castTag(.@"union").?.data; - try writer.writeAll(".{ "); - - if (payload.tag) |tag| { - try print(.{ - .ty = Type.fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_ty), - .val = tag, - }, writer, level - 1, mod); - try writer.writeAll(" = "); - const field_ty = ty.unionFieldType(tag, mod).?; - try print(.{ - .ty = field_ty, - .val = payload.val, - }, writer, level - 1, mod); - } else { - try writer.writeAll("(unknown tag) = "); - const backing_ty = try ty.unionBackingType(mod); - try print(.{ - .ty = backing_ty, - .val = payload.val, - }, writer, level - 1, mod); - } - - return writer.writeAll(" }"); - }, - .bytes => return writer.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}), - .repeated => { - if (level == 0) { - return writer.writeAll(".{ ... }"); - } - var i: u32 = 0; - try writer.writeAll(".{ "); - const elem_tv = TypedValue{ - .ty = ty.elemType2(mod), - .val = val.castTag(.repeated).?.data, - }; - const len = ty.arrayLen(mod); - const max_len = @min(len, max_aggregate_items); - while (i < max_len) : (i += 1) { - if (i != 0) try writer.writeAll(", "); - try print(elem_tv, writer, level - 1, mod); - } - if (len > max_aggregate_items) { - try writer.writeAll(", ..."); - } - return writer.writeAll(" }"); - }, - .slice => { - if (level == 0) { - return writer.writeAll(".{ ... }"); - } - const payload = val.castTag(.slice).?.data; - const elem_ty = ty.elemType2(mod); - const len = payload.len.toUnsignedInt(mod); - - if (elem_ty.eql(Type.u8, mod)) str: { - const max_len: usize = @min(len, max_string_len); - var buf: [max_string_len]u8 = undefined; - - var i: u32 = 0; - while (i < max_len) : (i += 1) { - const maybe_elem_val = payload.ptr.maybeElemValue(mod, i) catch |err| switch (err) { - error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic - }; - const elem_val = maybe_elem_val orelse return writer.writeAll(".{ (reinterpreted data) }"); - if (elem_val.isUndef(mod)) break :str; - buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(mod)) orelse break :str; - } - - // TODO would be nice if this had a bit of unicode awareness. - const truncated = if (len > max_string_len) " (truncated)" else ""; - return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); - } - - try writer.writeAll(".{ "); - - const max_len = @min(len, max_aggregate_items); - var i: u32 = 0; - while (i < max_len) : (i += 1) { - if (i != 0) try writer.writeAll(", "); - const maybe_elem_val = payload.ptr.maybeElemValue(mod, i) catch |err| switch (err) { - error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic - }; - const elem_val = maybe_elem_val orelse return writer.writeAll("(reinterpreted data) }"); - try print(.{ - .ty = elem_ty, - .val = elem_val, - }, writer, level - 1, mod); - } - if (len > max_aggregate_items) { - try writer.writeAll(", ..."); - } - return writer.writeAll(" }"); - }, - .eu_payload => { - val = val.castTag(.eu_payload).?.data; - ty = ty.errorUnionPayload(mod); - }, - .opt_payload => { - val = val.castTag(.opt_payload).?.data; - ty = ty.optionalChild(mod); - }, + while (true) switch (ip.indexToKey(val.toIntern())) { + .int_type, + .ptr_type, + .array_type, + .vector_type, + .opt_type, + .anyframe_type, + .error_union_type, + .simple_type, + .struct_type, + .anon_struct_type, + .union_type, + .opaque_type, + .enum_type, + .func_type, + .error_set_type, + .inferred_error_set_type, + => return Type.print(val.toType(), writer, mod), + .undef => return writer.writeAll("undefined"), + .simple_value => |simple_value| switch (simple_value) { + .void => return writer.writeAll("{}"), + .empty_struct => return printAggregate(ty, val, writer, level, mod), + .generic_poison => return writer.writeAll("(generic poison)"), + else => return writer.writeAll(@tagName(simple_value)), }, - else => switch (ip.indexToKey(val.toIntern())) { - .int_type, - .ptr_type, - .array_type, - .vector_type, - .opt_type, - .anyframe_type, - .error_union_type, - .simple_type, - .struct_type, - .anon_struct_type, - .union_type, - .opaque_type, - .enum_type, - .func_type, - .error_set_type, - .inferred_error_set_type, - => return Type.print(val.toType(), writer, mod), - .undef => return writer.writeAll("undefined"), - .simple_value => |simple_value| switch (simple_value) { - .void => return writer.writeAll("{}"), - .empty_struct => return printAggregate(ty, val, writer, level, mod), - .generic_poison => return writer.writeAll("(generic poison)"), - else => return writer.writeAll(@tagName(simple_value)), - }, - .variable => return writer.writeAll("(variable)"), - .extern_func => |extern_func| return writer.print("(extern function '{}')", .{ - mod.declPtr(extern_func.decl).name.fmt(ip), + .variable => return writer.writeAll("(variable)"), + .extern_func => |extern_func| return writer.print("(extern function '{}')", .{ + mod.declPtr(extern_func.decl).name.fmt(ip), + }), + .func => |func| return writer.print("(function '{}')", .{ + mod.declPtr(func.owner_decl).name.fmt(ip), + }), + .int => |int| switch (int.storage) { + inline .u64, .i64, .big_int => |x| return writer.print("{}", .{x}), + .lazy_align => |lazy_ty| return writer.print("{d}", .{ + Type.fromInterned(lazy_ty).abiAlignment(mod), }), - .func => |func| return writer.print("(function '{}')", .{ - mod.declPtr(func.owner_decl).name.fmt(ip), + .lazy_size => |lazy_ty| return writer.print("{d}", .{ + Type.fromInterned(lazy_ty).abiSize(mod), }), - .int => |int| switch (int.storage) { - inline .u64, .i64, .big_int => |x| return writer.print("{}", .{x}), - .lazy_align => |lazy_ty| return writer.print("{d}", .{ - Type.fromInterned(lazy_ty).abiAlignment(mod), - }), - .lazy_size => |lazy_ty| return writer.print("{d}", .{ - Type.fromInterned(lazy_ty).abiSize(mod), - }), - }, - .err => |err| return writer.print("error.{}", .{ - err.name.fmt(ip), + }, + .err => |err| return writer.print("error.{}", .{ + err.name.fmt(ip), + }), + .error_union => |error_union| switch (error_union.val) { + .err_name => |err_name| return writer.print("error.{}", .{ + err_name.fmt(ip), }), - .error_union => |error_union| switch (error_union.val) { - .err_name => |err_name| return writer.print("error.{}", .{ - err_name.fmt(ip), - }), - .payload => |payload| { - val = Value.fromInterned(payload); - ty = ty.errorUnionPayload(mod); - }, + .payload => |payload| { + val = Value.fromInterned(payload); + ty = ty.errorUnionPayload(mod); }, - .enum_literal => |enum_literal| return writer.print(".{}", .{ - enum_literal.fmt(ip), - }), - .enum_tag => |enum_tag| { - if (level == 0) { - return writer.writeAll("(enum)"); - } - const enum_type = ip.loadEnumType(ty.toIntern()); - if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| { - try writer.print(".{i}", .{enum_type.names.get(ip)[tag_index].fmt(ip)}); - return; + }, + .enum_literal => |enum_literal| return writer.print(".{}", .{ + enum_literal.fmt(ip), + }), + .enum_tag => |enum_tag| { + if (level == 0) { + return writer.writeAll("(enum)"); + } + const enum_type = ip.loadEnumType(ty.toIntern()); + if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| { + try writer.print(".{i}", .{enum_type.names.get(ip)[tag_index].fmt(ip)}); + return; + } + try writer.writeAll("@enumFromInt("); + try print(.{ + .ty = Type.fromInterned(ip.typeOf(enum_tag.int)), + .val = Value.fromInterned(enum_tag.int), + }, writer, level - 1, mod); + try writer.writeAll(")"); + return; + }, + .empty_enum_value => return writer.writeAll("(empty enum value)"), + .float => |float| switch (float.storage) { + inline else => |x| return writer.print("{d}", .{@as(f64, @floatCast(x))}), + }, + .slice => |slice| { + const ptr_ty = switch (ip.indexToKey(slice.ptr)) { + .ptr => |ptr| ty: { + if (ptr.addr == .int) return print(.{ + .ty = Type.fromInterned(ptr.ty), + .val = Value.fromInterned(slice.ptr), + }, writer, level - 1, mod); + break :ty ip.indexToKey(ptr.ty).ptr_type; + }, + .undef => |ptr_ty| ip.indexToKey(ptr_ty).ptr_type, + else => unreachable, + }; + if (level == 0) { + return writer.writeAll(".{ ... }"); + } + const elem_ty = Type.fromInterned(ptr_ty.child); + const len = Value.fromInterned(slice.len).toUnsignedInt(mod); + if (elem_ty.eql(Type.u8, mod)) str: { + const max_len = @min(len, max_string_len); + var buf: [max_string_len]u8 = undefined; + for (buf[0..max_len], 0..) |*c, i| { + const maybe_elem = try val.maybeElemValue(mod, i); + const elem = maybe_elem orelse return writer.writeAll(".{ (reinterpreted data) }"); + if (elem.isUndef(mod)) break :str; + c.* = @as(u8, @intCast(elem.toUnsignedInt(mod))); } - try writer.writeAll("@enumFromInt("); + const truncated = if (len > max_string_len) " (truncated)" else ""; + return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); + } + try writer.writeAll(".{ "); + const max_len = @min(len, max_aggregate_items); + for (0..max_len) |i| { + if (i != 0) try writer.writeAll(", "); + const maybe_elem = try val.maybeElemValue(mod, i); + const elem = maybe_elem orelse return writer.writeAll("(reinterpreted data) }"); try print(.{ - .ty = Type.fromInterned(ip.typeOf(enum_tag.int)), - .val = Value.fromInterned(enum_tag.int), + .ty = elem_ty, + .val = elem, }, writer, level - 1, mod); - try writer.writeAll(")"); - return; - }, - .empty_enum_value => return writer.writeAll("(empty enum value)"), - .float => |float| switch (float.storage) { - inline else => |x| return writer.print("{d}", .{@as(f64, @floatCast(x))}), - }, - .slice => |slice| { - const ptr_ty = switch (ip.indexToKey(slice.ptr)) { - .ptr => |ptr| ty: { - if (ptr.addr == .int) return print(.{ - .ty = Type.fromInterned(ptr.ty), - .val = Value.fromInterned(slice.ptr), - }, writer, level - 1, mod); - break :ty ip.indexToKey(ptr.ty).ptr_type; - }, - .undef => |ptr_ty| ip.indexToKey(ptr_ty).ptr_type, - else => unreachable, - }; - if (level == 0) { - return writer.writeAll(".{ ... }"); - } - const elem_ty = Type.fromInterned(ptr_ty.child); - const len = Value.fromInterned(slice.len).toUnsignedInt(mod); - if (elem_ty.eql(Type.u8, mod)) str: { - const max_len = @min(len, max_string_len); - var buf: [max_string_len]u8 = undefined; - for (buf[0..max_len], 0..) |*c, i| { - const maybe_elem = try val.maybeElemValue(mod, i); - const elem = maybe_elem orelse return writer.writeAll(".{ (reinterpreted data) }"); - if (elem.isUndef(mod)) break :str; - c.* = @as(u8, @intCast(elem.toUnsignedInt(mod))); - } - const truncated = if (len > max_string_len) " (truncated)" else ""; - return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); - } - try writer.writeAll(".{ "); - const max_len = @min(len, max_aggregate_items); - for (0..max_len) |i| { - if (i != 0) try writer.writeAll(", "); - const maybe_elem = try val.maybeElemValue(mod, i); - const elem = maybe_elem orelse return writer.writeAll("(reinterpreted data) }"); + } + if (len > max_aggregate_items) { + try writer.writeAll(", ..."); + } + return writer.writeAll(" }"); + }, + .ptr => |ptr| { + switch (ptr.addr) { + .decl => |decl_index| { + const decl = mod.declPtr(decl_index); + if (level == 0) return writer.print("(decl '{}')", .{decl.name.fmt(ip)}); + return print(.{ + .ty = decl.typeOf(mod), + .val = decl.val, + }, writer, level - 1, mod); + }, + .anon_decl => |anon_decl| { + const decl_val = anon_decl.val; + if (level == 0) return writer.print("(anon decl '{d}')", .{ + @intFromEnum(decl_val), + }); + return print(.{ + .ty = Type.fromInterned(ip.typeOf(decl_val)), + .val = Value.fromInterned(decl_val), + }, writer, level - 1, mod); + }, + .comptime_alloc => { + // TODO: we need a Sema to print this! + return writer.writeAll("(comptime alloc)"); + }, + .comptime_field => |field_val_ip| { + return print(.{ + .ty = Type.fromInterned(ip.typeOf(field_val_ip)), + .val = Value.fromInterned(field_val_ip), + }, writer, level - 1, mod); + }, + .int => |int_ip| { + try writer.writeAll("@ptrFromInt("); try print(.{ - .ty = elem_ty, - .val = elem, + .ty = Type.usize, + .val = Value.fromInterned(int_ip), }, writer, level - 1, mod); - } - if (len > max_aggregate_items) { - try writer.writeAll(", ..."); - } - return writer.writeAll(" }"); - }, - .ptr => |ptr| { - switch (ptr.addr) { - .decl => |decl_index| { - const decl = mod.declPtr(decl_index); - if (level == 0) return writer.print("(decl '{}')", .{decl.name.fmt(ip)}); - return print(.{ - .ty = decl.typeOf(mod), - .val = decl.val, - }, writer, level - 1, mod); - }, - .anon_decl => |anon_decl| { - const decl_val = anon_decl.val; - if (level == 0) return writer.print("(anon decl '{d}')", .{ - @intFromEnum(decl_val), - }); - return print(.{ - .ty = Type.fromInterned(ip.typeOf(decl_val)), - .val = Value.fromInterned(decl_val), - }, writer, level - 1, mod); - }, - .comptime_alloc => { - // TODO: we need a Sema to print this! - return writer.writeAll("(comptime alloc)"); - }, - .comptime_field => |field_val_ip| { - return print(.{ - .ty = Type.fromInterned(ip.typeOf(field_val_ip)), - .val = Value.fromInterned(field_val_ip), - }, writer, level - 1, mod); - }, - .int => |int_ip| { - try writer.writeAll("@ptrFromInt("); - try print(.{ - .ty = Type.usize, - .val = Value.fromInterned(int_ip), - }, writer, level - 1, mod); - try writer.writeByte(')'); - }, - .eu_payload => |eu_ip| { - try writer.writeAll("(payload of "); - try print(.{ - .ty = Type.fromInterned(ip.typeOf(eu_ip)), - .val = Value.fromInterned(eu_ip), - }, writer, level - 1, mod); - try writer.writeAll(")"); - }, - .opt_payload => |opt_ip| { - try print(.{ - .ty = Type.fromInterned(ip.typeOf(opt_ip)), - .val = Value.fromInterned(opt_ip), - }, writer, level - 1, mod); - try writer.writeAll(".?"); - }, - .elem => |elem| { - if (level == 0) { - try writer.writeAll("(...)"); - } else { - try print(.{ - .ty = Type.fromInterned(ip.typeOf(elem.base)), - .val = Value.fromInterned(elem.base), - }, writer, level - 1, mod); - } - try writer.print("[{}]", .{elem.index}); - }, - .field => |field| { - const ptr_container_ty = Type.fromInterned(ip.typeOf(field.base)); - if (level == 0) { - try writer.writeAll("(...)"); - } else { - try print(.{ - .ty = ptr_container_ty, - .val = Value.fromInterned(field.base), - }, writer, level - 1, mod); - } - - const container_ty = ptr_container_ty.childType(mod); - switch (container_ty.zigTypeTag(mod)) { - .Struct => { - if (container_ty.structFieldName(@intCast(field.index), mod).unwrap()) |field_name| { - try writer.print(".{i}", .{field_name.fmt(ip)}); - } else { - try writer.print("[{d}]", .{field.index}); - } - }, - .Union => { - const field_name = mod.typeToUnion(container_ty).?.loadTagType(ip).names.get(ip)[@intCast(field.index)]; - try writer.print(".{i}", .{field_name.fmt(ip)}); - }, - .Pointer => { - std.debug.assert(container_ty.isSlice(mod)); - try writer.writeAll(switch (field.index) { - Value.slice_ptr_index => ".ptr", - Value.slice_len_index => ".len", - else => unreachable, - }); - }, - else => unreachable, - } - }, - } - return; - }, - .opt => |opt| switch (opt.val) { - .none => return writer.writeAll("null"), - else => |payload| { - val = Value.fromInterned(payload); - ty = ty.optionalChild(mod); + try writer.writeByte(')'); }, - }, - .aggregate => |aggregate| switch (aggregate.storage) { - .bytes => |bytes| { - // Strip the 0 sentinel off of strings before printing - const zero_sent = blk: { - const sent = ty.sentinel(mod) orelse break :blk false; - break :blk sent.eql(Value.zero_u8, Type.u8, mod); - }; - const str = if (zero_sent) bytes[0 .. bytes.len - 1] else bytes; - return writer.print("\"{}\"", .{std.zig.fmtEscapes(str)}); + .eu_payload => |eu_ip| { + try writer.writeAll("(payload of "); + try print(.{ + .ty = Type.fromInterned(ip.typeOf(eu_ip)), + .val = Value.fromInterned(eu_ip), + }, writer, level - 1, mod); + try writer.writeAll(")"); }, - .elems, .repeated_elem => return printAggregate(ty, val, writer, level, mod), - }, - .un => |un| { - try writer.writeAll(".{ "); - if (level > 0) { - if (un.tag != .none) { - try print(.{ - .ty = ty.unionTagTypeHypothetical(mod), - .val = Value.fromInterned(un.tag), - }, writer, level - 1, mod); - try writer.writeAll(" = "); - const field_ty = ty.unionFieldType(Value.fromInterned(un.tag), mod).?; + .opt_payload => |opt_ip| { + try print(.{ + .ty = Type.fromInterned(ip.typeOf(opt_ip)), + .val = Value.fromInterned(opt_ip), + }, writer, level - 1, mod); + try writer.writeAll(".?"); + }, + .elem => |elem| { + if (level == 0) { + try writer.writeAll("(...)"); + } else { try print(.{ - .ty = field_ty, - .val = Value.fromInterned(un.val), + .ty = Type.fromInterned(ip.typeOf(elem.base)), + .val = Value.fromInterned(elem.base), }, writer, level - 1, mod); + } + try writer.print("[{}]", .{elem.index}); + }, + .field => |field| { + const ptr_container_ty = Type.fromInterned(ip.typeOf(field.base)); + if (level == 0) { + try writer.writeAll("(...)"); } else { - try writer.writeAll("(unknown tag) = "); - const backing_ty = try ty.unionBackingType(mod); try print(.{ - .ty = backing_ty, - .val = Value.fromInterned(un.val), + .ty = ptr_container_ty, + .val = Value.fromInterned(field.base), }, writer, level - 1, mod); } - } else try writer.writeAll("..."); - return writer.writeAll(" }"); + + const container_ty = ptr_container_ty.childType(mod); + switch (container_ty.zigTypeTag(mod)) { + .Struct => { + if (container_ty.structFieldName(@intCast(field.index), mod).unwrap()) |field_name| { + try writer.print(".{i}", .{field_name.fmt(ip)}); + } else { + try writer.print("[{d}]", .{field.index}); + } + }, + .Union => { + const field_name = mod.typeToUnion(container_ty).?.loadTagType(ip).names.get(ip)[@intCast(field.index)]; + try writer.print(".{i}", .{field_name.fmt(ip)}); + }, + .Pointer => { + std.debug.assert(container_ty.isSlice(mod)); + try writer.writeAll(switch (field.index) { + Value.slice_ptr_index => ".ptr", + Value.slice_len_index => ".len", + else => unreachable, + }); + }, + else => unreachable, + } + }, + } + return; + }, + .opt => |opt| switch (opt.val) { + .none => return writer.writeAll("null"), + else => |payload| { + val = Value.fromInterned(payload); + ty = ty.optionalChild(mod); + }, + }, + .aggregate => |aggregate| switch (aggregate.storage) { + .bytes => |bytes| { + // Strip the 0 sentinel off of strings before printing + const zero_sent = blk: { + const sent = ty.sentinel(mod) orelse break :blk false; + break :blk sent.eql(Value.zero_u8, Type.u8, mod); + }; + const str = if (zero_sent) bytes[0 .. bytes.len - 1] else bytes; + return writer.print("\"{}\"", .{std.zig.fmtEscapes(str)}); }, - .memoized_call => unreachable, + .elems, .repeated_elem => return printAggregate(ty, val, writer, level, mod), + }, + .un => |un| { + try writer.writeAll(".{ "); + if (level > 0) { + if (un.tag != .none) { + try print(.{ + .ty = ty.unionTagTypeHypothetical(mod), + .val = Value.fromInterned(un.tag), + }, writer, level - 1, mod); + try writer.writeAll(" = "); + const field_ty = ty.unionFieldType(Value.fromInterned(un.tag), mod).?; + try print(.{ + .ty = field_ty, + .val = Value.fromInterned(un.val), + }, writer, level - 1, mod); + } else { + try writer.writeAll("(unknown tag) = "); + const backing_ty = try ty.unionBackingType(mod); + try print(.{ + .ty = backing_ty, + .val = Value.fromInterned(un.val), + }, writer, level - 1, mod); + } + } else try writer.writeAll("..."); + return writer.writeAll(" }"); }, + .memoized_call => unreachable, }; } diff --git a/src/Value.zig b/src/Value.zig index af24d68d7cfe..040961fa385a 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -13,124 +13,8 @@ const Sema = @import("Sema.zig"); const InternPool = @import("InternPool.zig"); const Value = @This(); -/// We are migrating towards using this for every Value object. However, many -/// values are still represented the legacy way. This is indicated by using -/// InternPool.Index.none. ip_index: InternPool.Index, -/// This is the raw data, with no bookkeeping, no memory awareness, -/// no de-duplication, and no type system awareness. -/// This union takes advantage of the fact that the first page of memory -/// is unmapped, giving us 4096 possible enum tags that have no payload. -legacy: extern union { - ptr_otherwise: *Payload, -}, - -// Keep in sync with tools/stage2_pretty_printers_common.py -pub const Tag = enum(usize) { - // The first section of this enum are tags that require no payload. - // After this, the tag requires a payload. - - /// When the type is error union: - /// * If the tag is `.@"error"`, the error union is an error. - /// * If the tag is `.eu_payload`, the error union is a payload. - /// * A nested error such as `anyerror!(anyerror!T)` in which the the outer error union - /// is non-error, but the inner error union is an error, is represented as - /// a tag of `.eu_payload`, with a sub-tag of `.@"error"`. - eu_payload, - /// When the type is optional: - /// * If the tag is `.null_value`, the optional is null. - /// * If the tag is `.opt_payload`, the optional is a payload. - /// * A nested optional such as `??T` in which the the outer optional - /// is non-null, but the inner optional is null, is represented as - /// a tag of `.opt_payload`, with a sub-tag of `.null_value`. - opt_payload, - /// Pointer and length as sub `Value` objects. - slice, - /// A slice of u8 whose memory is managed externally. - bytes, - /// This value is repeated some number of times. The amount of times to repeat - /// is stored externally. - repeated, - /// An instance of a struct, array, or vector. - /// Each element/field stored as a `Value`. - /// In the case of sentinel-terminated arrays, the sentinel value *is* stored, - /// so the slice length will be one more than the type's array length. - aggregate, - /// An instance of a union. - @"union", - - pub fn Type(comptime t: Tag) type { - return switch (t) { - .eu_payload, - .opt_payload, - .repeated, - => Payload.SubValue, - .slice => Payload.Slice, - .bytes => Payload.Bytes, - .aggregate => Payload.Aggregate, - .@"union" => Payload.Union, - }; - } - - pub fn create(comptime t: Tag, ally: Allocator, data: Data(t)) error{OutOfMemory}!Value { - const ptr = try ally.create(t.Type()); - ptr.* = .{ - .base = .{ .tag = t }, - .data = data, - }; - return Value{ - .ip_index = .none, - .legacy = .{ .ptr_otherwise = &ptr.base }, - }; - } - - pub fn Data(comptime t: Tag) type { - return std.meta.fieldInfo(t.Type(), .data).type; - } -}; - -pub fn initPayload(payload: *Payload) Value { - return Value{ - .ip_index = .none, - .legacy = .{ .ptr_otherwise = payload }, - }; -} - -pub fn tag(self: Value) Tag { - assert(self.ip_index == .none); - return self.legacy.ptr_otherwise.tag; -} - -/// Prefer `castTag` to this. -pub fn cast(self: Value, comptime T: type) ?*T { - if (self.ip_index != .none) { - return null; - } - if (@hasField(T, "base_tag")) { - return self.castTag(T.base_tag); - } - inline for (@typeInfo(Tag).Enum.fields) |field| { - const t = @as(Tag, @enumFromInt(field.value)); - if (self.legacy.ptr_otherwise.tag == t) { - if (T == t.Type()) { - return @fieldParentPtr(T, "base", self.legacy.ptr_otherwise); - } - return null; - } - } - unreachable; -} - -pub fn castTag(self: Value, comptime t: Tag) ?*t.Type() { - if (self.ip_index != .none) return null; - - if (self.legacy.ptr_otherwise.tag == t) - return @fieldParentPtr(t.Type(), "base", self.legacy.ptr_otherwise); - - return null; -} - pub fn format(val: Value, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { _ = val; _ = fmt; @@ -148,33 +32,7 @@ pub fn dump( out_stream: anytype, ) !void { comptime assert(fmt.len == 0); - if (start_val.ip_index != .none) { - try out_stream.print("(interned: {})", .{start_val.toIntern()}); - return; - } - var val = start_val; - while (true) switch (val.tag()) { - .aggregate => { - return out_stream.writeAll("(aggregate)"); - }, - .@"union" => { - return out_stream.writeAll("(union value)"); - }, - .bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}), - .repeated => { - try out_stream.writeAll("(repeated) "); - val = val.castTag(.repeated).?.data; - }, - .eu_payload => { - try out_stream.writeAll("(eu_payload) "); - val = val.castTag(.repeated).?.data; - }, - .opt_payload => { - try out_stream.writeAll("(opt_payload) "); - val = val.castTag(.repeated).?.data; - }, - .slice => return out_stream.writeAll("(slice)"), - }; + try out_stream.print("(interned: {})", .{start_val.toIntern()}); } pub fn fmtDebug(val: Value) std.fmt.Formatter(dump) { @@ -252,162 +110,9 @@ fn arrayToIpString(val: Value, len_u64: u64, mod: *Module) !InternPool.NullTermi return ip.getOrPutTrailingString(gpa, len); } -pub fn intern2(val: Value, ty: Type, mod: *Module) Allocator.Error!InternPool.Index { - if (val.ip_index != .none) return val.ip_index; - return intern(val, ty, mod); -} - -pub fn intern(val: Value, ty: Type, mod: *Module) Allocator.Error!InternPool.Index { - if (val.ip_index != .none) return (try mod.getCoerced(val, ty)).toIntern(); - const ip = &mod.intern_pool; - switch (val.tag()) { - .eu_payload => { - const pl = val.castTag(.eu_payload).?.data; - return mod.intern(.{ .error_union = .{ - .ty = ty.toIntern(), - .val = .{ .payload = try pl.intern(ty.errorUnionPayload(mod), mod) }, - } }); - }, - .opt_payload => { - const pl = val.castTag(.opt_payload).?.data; - return mod.intern(.{ .opt = .{ - .ty = ty.toIntern(), - .val = try pl.intern(ty.optionalChild(mod), mod), - } }); - }, - .slice => { - const pl = val.castTag(.slice).?.data; - return mod.intern(.{ .slice = .{ - .ty = ty.toIntern(), - .len = try pl.len.intern(Type.usize, mod), - .ptr = try pl.ptr.intern(ty.slicePtrFieldType(mod), mod), - } }); - }, - .bytes => { - const pl = val.castTag(.bytes).?.data; - return mod.intern(.{ .aggregate = .{ - .ty = ty.toIntern(), - .storage = .{ .bytes = pl }, - } }); - }, - .repeated => { - const pl = val.castTag(.repeated).?.data; - return mod.intern(.{ .aggregate = .{ - .ty = ty.toIntern(), - .storage = .{ .repeated_elem = try pl.intern(ty.childType(mod), mod) }, - } }); - }, - .aggregate => { - const len = @as(usize, @intCast(ty.arrayLen(mod))); - const old_elems = val.castTag(.aggregate).?.data[0..len]; - const new_elems = try mod.gpa.alloc(InternPool.Index, old_elems.len); - defer mod.gpa.free(new_elems); - const ty_key = ip.indexToKey(ty.toIntern()); - for (new_elems, old_elems, 0..) |*new_elem, old_elem, field_i| - new_elem.* = try old_elem.intern(switch (ty_key) { - .struct_type => ty.structFieldType(field_i, mod), - .anon_struct_type => |info| Type.fromInterned(info.types.get(ip)[field_i]), - inline .array_type, .vector_type => |info| Type.fromInterned(info.child), - else => unreachable, - }, mod); - return mod.intern(.{ .aggregate = .{ - .ty = ty.toIntern(), - .storage = .{ .elems = new_elems }, - } }); - }, - .@"union" => { - const pl = val.castTag(.@"union").?.data; - if (pl.tag) |pl_tag| { - return mod.intern(.{ .un = .{ - .ty = ty.toIntern(), - .tag = try pl_tag.intern(ty.unionTagTypeHypothetical(mod), mod), - .val = try pl.val.intern(ty.unionFieldType(pl_tag, mod).?, mod), - } }); - } else { - return mod.intern(.{ .un = .{ - .ty = ty.toIntern(), - .tag = .none, - .val = try pl.val.intern(try ty.unionBackingType(mod), mod), - } }); - } - }, - } -} - -pub fn unintern(val: Value, arena: Allocator, mod: *Module) Allocator.Error!Value { - return if (val.ip_index == .none) val else switch (mod.intern_pool.indexToKey(val.toIntern())) { - .int_type, - .ptr_type, - .array_type, - .vector_type, - .opt_type, - .anyframe_type, - .error_union_type, - .simple_type, - .struct_type, - .anon_struct_type, - .union_type, - .opaque_type, - .enum_type, - .func_type, - .error_set_type, - .inferred_error_set_type, - - .undef, - .simple_value, - .variable, - .extern_func, - .func, - .int, - .err, - .enum_literal, - .enum_tag, - .empty_enum_value, - .float, - .ptr, - => val, - - .error_union => |error_union| switch (error_union.val) { - .err_name => val, - .payload => |payload| Tag.eu_payload.create(arena, Value.fromInterned(payload)), - }, - - .slice => |slice| Tag.slice.create(arena, .{ - .ptr = Value.fromInterned(slice.ptr), - .len = Value.fromInterned(slice.len), - }), - - .opt => |opt| switch (opt.val) { - .none => val, - else => |payload| Tag.opt_payload.create(arena, Value.fromInterned(payload)), - }, - - .aggregate => |aggregate| switch (aggregate.storage) { - .bytes => |bytes| Tag.bytes.create(arena, try arena.dupe(u8, bytes)), - .elems => |old_elems| { - const new_elems = try arena.alloc(Value, old_elems.len); - for (new_elems, old_elems) |*new_elem, old_elem| new_elem.* = Value.fromInterned(old_elem); - return Tag.aggregate.create(arena, new_elems); - }, - .repeated_elem => |elem| Tag.repeated.create(arena, Value.fromInterned(elem)), - }, - - .un => |un| Tag.@"union".create(arena, .{ - // toValue asserts that the value cannot be .none which is valid on unions. - .tag = if (un.tag == .none) null else Value.fromInterned(un.tag), - .val = Value.fromInterned(un.val), - }), - - .memoized_call => unreachable, - }; -} - pub fn fromInterned(i: InternPool.Index) Value { assert(i != .none); - return .{ - .ip_index = i, - .legacy = undefined, - }; + return .{ .ip_index = i }; } pub fn toIntern(val: Value) InternPool.Index { @@ -492,24 +197,24 @@ pub fn isFuncBody(val: Value, mod: *Module) bool { } pub fn getFunction(val: Value, mod: *Module) ?InternPool.Key.Func { - return if (val.ip_index != .none) switch (mod.intern_pool.indexToKey(val.toIntern())) { + return switch (mod.intern_pool.indexToKey(val.toIntern())) { .func => |x| x, else => null, - } else null; + }; } pub fn getExternFunc(val: Value, mod: *Module) ?InternPool.Key.ExternFunc { - return if (val.ip_index != .none) switch (mod.intern_pool.indexToKey(val.toIntern())) { + return switch (mod.intern_pool.indexToKey(val.toIntern())) { .extern_func => |extern_func| extern_func, else => null, - } else null; + }; } pub fn getVariable(val: Value, mod: *Module) ?InternPool.Key.Variable { - return if (val.ip_index != .none) switch (mod.intern_pool.indexToKey(val.toIntern())) { + return switch (mod.intern_pool.indexToKey(val.toIntern())) { .variable => |variable| variable, else => null, - } else null; + }; } /// If the value fits in a u64, return it, otherwise null. @@ -677,25 +382,14 @@ pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) error{ .auto => return error.IllDefinedMemoryLayout, .@"extern" => for (0..struct_type.field_types.len) |i| { const off: usize = @intCast(ty.structFieldOffset(i, mod)); - const field_val = switch (val.ip_index) { - .none => switch (val.tag()) { - .bytes => { - buffer[off] = val.castTag(.bytes).?.data[i]; - continue; - }, - .aggregate => val.castTag(.aggregate).?.data[i], - .repeated => val.castTag(.repeated).?.data, - else => unreachable, + const field_val = Value.fromInterned(switch (ip.indexToKey(val.toIntern()).aggregate.storage) { + .bytes => |bytes| { + buffer[off] = bytes[i]; + continue; }, - else => Value.fromInterned(switch (ip.indexToKey(val.toIntern()).aggregate.storage) { - .bytes => |bytes| { - buffer[off] = bytes[i]; - continue; - }, - .elems => |elems| elems[i], - .repeated_elem => |elem| elem, - }), - }; + .elems => |elems| elems[i], + .repeated_elem => |elem| elem, + }); const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); try writeToMemory(field_val, field_ty, mod, buffer[off..]); }, @@ -842,19 +536,11 @@ pub fn writeToPackedMemory( assert(struct_type.layout == .@"packed"); var bits: u16 = 0; for (0..struct_type.field_types.len) |i| { - const field_val = switch (val.ip_index) { - .none => switch (val.tag()) { - .bytes => unreachable, - .aggregate => val.castTag(.aggregate).?.data[i], - .repeated => val.castTag(.repeated).?.data, - else => unreachable, - }, - else => Value.fromInterned(switch (ip.indexToKey(val.toIntern()).aggregate.storage) { - .bytes => unreachable, - .elems => |elems| elems[i], - .repeated_elem => |elem| elem, - }), - }; + const field_val = Value.fromInterned(switch (ip.indexToKey(val.toIntern()).aggregate.storage) { + .bytes => unreachable, + .elems => |elems| elems[i], + .repeated_elem => |elem| elem, + }); const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); const field_bits: u16 = @intCast(field_ty.bitSize(mod)); try field_val.writeToPackedMemory(field_ty, mod, buffer, bit_offset + bits); @@ -972,7 +658,7 @@ pub fn readFromMemory( const elems = try arena.alloc(InternPool.Index, @as(usize, @intCast(ty.arrayLen(mod)))); var offset: usize = 0; for (elems) |*elem| { - elem.* = try (try readFromMemory(elem_ty, mod, buffer[offset..], arena)).intern(elem_ty, mod); + elem.* = (try readFromMemory(elem_ty, mod, buffer[offset..], arena)).toIntern(); offset += @as(usize, @intCast(elem_size)); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ @@ -997,7 +683,7 @@ pub fn readFromMemory( const field_ty = Type.fromInterned(field_types.get(ip)[i]); const off: usize = @intCast(ty.structFieldOffset(i, mod)); const sz: usize = @intCast(field_ty.abiSize(mod)); - field_val.* = try (try readFromMemory(field_ty, mod, buffer[off..(off + sz)], arena)).intern(field_ty, mod); + field_val.* = (try readFromMemory(field_ty, mod, buffer[off..(off + sz)], arena)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -1027,7 +713,7 @@ pub fn readFromMemory( .@"extern" => { const union_size = ty.abiSize(mod); const array_ty = try mod.arrayType(.{ .len = union_size, .child = .u8_type }); - const val = try (try readFromMemory(array_ty, mod, buffer, arena)).intern(array_ty, mod); + const val = (try readFromMemory(array_ty, mod, buffer, arena)).toIntern(); return Value.fromInterned((try mod.intern(.{ .un = .{ .ty = ty.toIntern(), .tag = .none, @@ -1094,7 +780,7 @@ pub fn readFromPackedMemory( return Value.true; } }, - .Int, .Enum => |ty_tag| { + .Int => { if (buffer.len == 0) return mod.intValue(ty, 0); const int_info = ty.intInfo(mod); const bits = int_info.bits; @@ -1102,21 +788,10 @@ pub fn readFromPackedMemory( // Fast path for integers <= u64 if (bits <= 64) { - const int_ty = switch (ty_tag) { - .Int => ty, - .Enum => ty.intTagType(mod), - else => unreachable, - }; - return mod.getCoerced(switch (int_info.signedness) { - .signed => return mod.intValue( - int_ty, - std.mem.readVarPackedInt(i64, buffer, bit_offset, bits, endian, .signed), - ), - .unsigned => return mod.intValue( - int_ty, - std.mem.readVarPackedInt(u64, buffer, bit_offset, bits, endian, .unsigned), - ), - }, ty); + return mod.intValue( + ty, + std.mem.readVarPackedInt(i64, buffer, bit_offset, bits, endian, int_info.signedness), + ); } // Slow path, we have to construct a big-int @@ -1129,6 +804,11 @@ pub fn readFromPackedMemory( bigint.readPackedTwosComplement(buffer, bit_offset, bits, endian, int_info.signedness); return mod.intValue_big(ty, bigint.toConst()); }, + .Enum => { + const int_ty = ty.intTagType(mod); + const int_val = try Value.readFromPackedMemory(int_ty, mod, buffer, bit_offset, arena); + return mod.getCoerced(int_val, ty); + }, .Float => return Value.fromInterned((try mod.intern(.{ .float = .{ .ty = ty.toIntern(), .storage = switch (ty.floatBits(target)) { @@ -1149,7 +829,7 @@ pub fn readFromPackedMemory( for (elems, 0..) |_, i| { // On big-endian systems, LLVM reverses the element order of vectors by default const tgt_elem_i = if (endian == .big) elems.len - i - 1 else i; - elems[tgt_elem_i] = try (try readFromPackedMemory(elem_ty, mod, buffer, bit_offset + bits, arena)).intern(elem_ty, mod); + elems[tgt_elem_i] = (try readFromPackedMemory(elem_ty, mod, buffer, bit_offset + bits, arena)).toIntern(); bits += elem_bit_size; } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ @@ -1166,7 +846,7 @@ pub fn readFromPackedMemory( for (field_vals, 0..) |*field_val, i| { const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); const field_bits: u16 = @intCast(field_ty.bitSize(mod)); - field_val.* = try (try readFromPackedMemory(field_ty, mod, buffer, bit_offset + bits, arena)).intern(field_ty, mod); + field_val.* = (try readFromPackedMemory(field_ty, mod, buffer, bit_offset + bits, arena)).toIntern(); bits += field_bits; } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ @@ -1611,51 +1291,42 @@ pub fn maybeElemValue(val: Value, mod: *Module, index: usize) Allocator.Error!?V } pub fn maybeElemValueFull(val: Value, sema: ?*Sema, mod: *Module, index: usize) Allocator.Error!?Value { - return switch (val.ip_index) { - .none => switch (val.tag()) { - .bytes => try mod.intValue(Type.u8, val.castTag(.bytes).?.data[index]), - .repeated => val.castTag(.repeated).?.data, - .aggregate => val.castTag(.aggregate).?.data[index], - .slice => val.castTag(.slice).?.data.ptr.maybeElemValueFull(sema, mod, index), - else => null, - }, - else => switch (mod.intern_pool.indexToKey(val.toIntern())) { - .undef => |ty| Value.fromInterned((try mod.intern(.{ - .undef = Type.fromInterned(ty).elemType2(mod).toIntern(), - }))), - .slice => |slice| return Value.fromInterned(slice.ptr).maybeElemValueFull(sema, mod, index), - .ptr => |ptr| switch (ptr.addr) { - .decl => |decl| mod.declPtr(decl).val.maybeElemValueFull(sema, mod, index), - .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).maybeElemValueFull(sema, mod, index), - .comptime_alloc => |idx| if (sema) |s| Value.fromInterned( - try s.getComptimeAlloc(idx).val.intern(mod, s.arena), - ).maybeElemValueFull(sema, mod, index) else null, - .int, .eu_payload => null, - .opt_payload => |base| Value.fromInterned(base).maybeElemValueFull(sema, mod, index), - .comptime_field => |field_val| Value.fromInterned(field_val).maybeElemValueFull(sema, mod, index), - .elem => |elem| Value.fromInterned(elem.base).maybeElemValueFull(sema, mod, index + @as(usize, @intCast(elem.index))), - .field => |field| if (Value.fromInterned(field.base).pointerDecl(mod)) |decl_index| { - const base_decl = mod.declPtr(decl_index); - const field_val = try base_decl.val.fieldValue(mod, @as(usize, @intCast(field.index))); - return field_val.maybeElemValueFull(sema, mod, index); - } else null, - }, - .opt => |opt| Value.fromInterned(opt.val).maybeElemValueFull(sema, mod, index), - .aggregate => |aggregate| { - const len = mod.intern_pool.aggregateTypeLen(aggregate.ty); - if (index < len) return Value.fromInterned(switch (aggregate.storage) { - .bytes => |bytes| try mod.intern(.{ .int = .{ - .ty = .u8_type, - .storage = .{ .u64 = bytes[index] }, - } }), - .elems => |elems| elems[index], - .repeated_elem => |elem| elem, - }); - assert(index == len); - return Value.fromInterned(mod.intern_pool.indexToKey(aggregate.ty).array_type.sentinel); - }, - else => null, + return switch (mod.intern_pool.indexToKey(val.toIntern())) { + .undef => |ty| Value.fromInterned((try mod.intern(.{ + .undef = Type.fromInterned(ty).elemType2(mod).toIntern(), + }))), + .slice => |slice| return Value.fromInterned(slice.ptr).maybeElemValueFull(sema, mod, index), + .ptr => |ptr| switch (ptr.addr) { + .decl => |decl| mod.declPtr(decl).val.maybeElemValueFull(sema, mod, index), + .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).maybeElemValueFull(sema, mod, index), + .comptime_alloc => |idx| if (sema) |s| Value.fromInterned( + try s.getComptimeAlloc(idx).val.intern(mod, s.arena), + ).maybeElemValueFull(sema, mod, index) else null, + .int, .eu_payload => null, + .opt_payload => |base| Value.fromInterned(base).maybeElemValueFull(sema, mod, index), + .comptime_field => |field_val| Value.fromInterned(field_val).maybeElemValueFull(sema, mod, index), + .elem => |elem| Value.fromInterned(elem.base).maybeElemValueFull(sema, mod, index + @as(usize, @intCast(elem.index))), + .field => |field| if (Value.fromInterned(field.base).pointerDecl(mod)) |decl_index| { + const base_decl = mod.declPtr(decl_index); + const field_val = try base_decl.val.fieldValue(mod, @as(usize, @intCast(field.index))); + return field_val.maybeElemValueFull(sema, mod, index); + } else null, + }, + .opt => |opt| Value.fromInterned(opt.val).maybeElemValueFull(sema, mod, index), + .aggregate => |aggregate| { + const len = mod.intern_pool.aggregateTypeLen(aggregate.ty); + if (index < len) return Value.fromInterned(switch (aggregate.storage) { + .bytes => |bytes| try mod.intern(.{ .int = .{ + .ty = .u8_type, + .storage = .{ .u64 = bytes[index] }, + } }), + .elems => |elems| elems[index], + .repeated_elem => |elem| elem, + }); + assert(index == len); + return Value.fromInterned(mod.intern_pool.indexToKey(aggregate.ty).array_type.sentinel); }, + else => null, }; } @@ -1688,85 +1359,61 @@ pub fn sliceArray( ) error{OutOfMemory}!Value { // TODO: write something like getCoercedInts to avoid needing to dupe const mod = sema.mod; - return switch (val.ip_index) { - .none => switch (val.tag()) { - .slice => val.castTag(.slice).?.data.ptr.sliceArray(sema, start, end), - .bytes => Tag.bytes.create(sema.arena, val.castTag(.bytes).?.data[start..end]), - .repeated => val, - .aggregate => Tag.aggregate.create(sema.arena, val.castTag(.aggregate).?.data[start..end]), + return switch (mod.intern_pool.indexToKey(val.toIntern())) { + .ptr => |ptr| switch (ptr.addr) { + .decl => |decl| try mod.declPtr(decl).val.sliceArray(sema, start, end), + .comptime_alloc => |idx| try Value.fromInterned( + try sema.getComptimeAlloc(idx).val.intern(mod, sema.arena), + ).sliceArray(sema, start, end), + .comptime_field => |comptime_field| Value.fromInterned(comptime_field) + .sliceArray(sema, start, end), + .elem => |elem| Value.fromInterned(elem.base) + .sliceArray(sema, start + @as(usize, @intCast(elem.index)), end + @as(usize, @intCast(elem.index))), else => unreachable, }, - else => switch (mod.intern_pool.indexToKey(val.toIntern())) { - .ptr => |ptr| switch (ptr.addr) { - .decl => |decl| try mod.declPtr(decl).val.sliceArray(sema, start, end), - .comptime_alloc => |idx| try Value.fromInterned( - try sema.getComptimeAlloc(idx).val.intern(mod, sema.arena), - ).sliceArray(sema, start, end), - .comptime_field => |comptime_field| Value.fromInterned(comptime_field) - .sliceArray(sema, start, end), - .elem => |elem| Value.fromInterned(elem.base) - .sliceArray(sema, start + @as(usize, @intCast(elem.index)), end + @as(usize, @intCast(elem.index))), + .aggregate => |aggregate| Value.fromInterned((try mod.intern(.{ .aggregate = .{ + .ty = switch (mod.intern_pool.indexToKey(mod.intern_pool.typeOf(val.toIntern()))) { + .array_type => |array_type| try mod.arrayType(.{ + .len = @as(u32, @intCast(end - start)), + .child = array_type.child, + .sentinel = if (end == array_type.len) array_type.sentinel else .none, + }), + .vector_type => |vector_type| try mod.vectorType(.{ + .len = @as(u32, @intCast(end - start)), + .child = vector_type.child, + }), else => unreachable, + }.toIntern(), + .storage = switch (aggregate.storage) { + .bytes => .{ .bytes = try sema.arena.dupe(u8, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.bytes[start..end]) }, + .elems => .{ .elems = try sema.arena.dupe(InternPool.Index, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.elems[start..end]) }, + .repeated_elem => |elem| .{ .repeated_elem = elem }, }, - .aggregate => |aggregate| Value.fromInterned((try mod.intern(.{ .aggregate = .{ - .ty = switch (mod.intern_pool.indexToKey(mod.intern_pool.typeOf(val.toIntern()))) { - .array_type => |array_type| try mod.arrayType(.{ - .len = @as(u32, @intCast(end - start)), - .child = array_type.child, - .sentinel = if (end == array_type.len) array_type.sentinel else .none, - }), - .vector_type => |vector_type| try mod.vectorType(.{ - .len = @as(u32, @intCast(end - start)), - .child = vector_type.child, - }), - else => unreachable, - }.toIntern(), - .storage = switch (aggregate.storage) { - .bytes => .{ .bytes = try sema.arena.dupe(u8, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.bytes[start..end]) }, - .elems => .{ .elems = try sema.arena.dupe(InternPool.Index, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.elems[start..end]) }, - .repeated_elem => |elem| .{ .repeated_elem = elem }, - }, - } }))), - else => unreachable, - }, + } }))), + else => unreachable, }; } pub fn fieldValue(val: Value, mod: *Module, index: usize) !Value { - return switch (val.ip_index) { - .none => switch (val.tag()) { - .aggregate => { - const field_values = val.castTag(.aggregate).?.data; - return field_values[index]; - }, - .@"union" => { - const payload = val.castTag(.@"union").?.data; - // TODO assert the tag is correct - return payload.val; - }, - else => unreachable, - }, - else => switch (mod.intern_pool.indexToKey(val.toIntern())) { - .undef => |ty| Value.fromInterned((try mod.intern(.{ - .undef = Type.fromInterned(ty).structFieldType(index, mod).toIntern(), - }))), - .aggregate => |aggregate| Value.fromInterned(switch (aggregate.storage) { - .bytes => |bytes| try mod.intern(.{ .int = .{ - .ty = .u8_type, - .storage = .{ .u64 = bytes[index] }, - } }), - .elems => |elems| elems[index], - .repeated_elem => |elem| elem, - }), - // TODO assert the tag is correct - .un => |un| Value.fromInterned(un.val), - else => unreachable, - }, + return switch (mod.intern_pool.indexToKey(val.toIntern())) { + .undef => |ty| Value.fromInterned((try mod.intern(.{ + .undef = Type.fromInterned(ty).structFieldType(index, mod).toIntern(), + }))), + .aggregate => |aggregate| Value.fromInterned(switch (aggregate.storage) { + .bytes => |bytes| try mod.intern(.{ .int = .{ + .ty = .u8_type, + .storage = .{ .u64 = bytes[index] }, + } }), + .elems => |elems| elems[index], + .repeated_elem => |elem| elem, + }), + // TODO assert the tag is correct + .un => |un| Value.fromInterned(un.val), + else => unreachable, }; } pub fn unionTag(val: Value, mod: *Module) ?Value { - if (val.ip_index == .none) return val.castTag(.@"union").?.data.tag; return switch (mod.intern_pool.indexToKey(val.toIntern())) { .undef, .enum_tag => val, .un => |un| if (un.tag != .none) Value.fromInterned(un.tag) else return null, @@ -1775,7 +1422,6 @@ pub fn unionTag(val: Value, mod: *Module) ?Value { } pub fn unionValue(val: Value, mod: *Module) Value { - if (val.ip_index == .none) return val.castTag(.@"union").?.data.val; return switch (mod.intern_pool.indexToKey(val.toIntern())) { .un => |un| Value.fromInterned(un.val), else => unreachable, @@ -1821,7 +1467,7 @@ pub fn elemPtr( } pub fn isUndef(val: Value, mod: *Module) bool { - return val.ip_index != .none and mod.intern_pool.isUndef(val.toIntern()); + return mod.intern_pool.isUndef(val.toIntern()); } /// TODO: check for cases such as array that is not marked undef but all the element @@ -1915,7 +1561,7 @@ pub fn floatFromIntAdvanced(val: Value, arena: Allocator, int_ty: Type, float_ty const scalar_ty = float_ty.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try floatFromIntScalar(elem_val, scalar_ty, mod, opt_sema)).intern(scalar_ty, mod); + scalar.* = (try floatFromIntScalar(elem_val, scalar_ty, mod, opt_sema)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_ty.toIntern(), @@ -1993,7 +1639,7 @@ pub fn intAddSat( for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try intAddSatScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); + scalar.* = (try intAddSatScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -2043,7 +1689,7 @@ pub fn intSubSat( for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try intSubSatScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); + scalar.* = (try intSubSatScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -2095,8 +1741,8 @@ pub fn intMulWithOverflow( const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); const of_math_result = try intMulWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod); - of.* = try of_math_result.overflow_bit.intern(Type.u1, mod); - scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod); + of.* = of_math_result.overflow_bit.toIntern(); + scalar.* = of_math_result.wrapped_result.toIntern(); } return OverflowArithmeticResult{ .overflow_bit = Value.fromInterned((try mod.intern(.{ .aggregate = .{ @@ -2161,7 +1807,7 @@ pub fn numberMulWrap( for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try numberMulWrapScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); + scalar.* = (try numberMulWrapScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -2207,7 +1853,7 @@ pub fn intMulSat( for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try intMulSatScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); + scalar.* = (try intMulSatScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -2283,7 +1929,7 @@ pub fn bitwiseNot(val: Value, ty: Type, arena: Allocator, mod: *Module) !Value { const scalar_ty = ty.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try bitwiseNotScalar(elem_val, scalar_ty, arena, mod)).intern(scalar_ty, mod); + scalar.* = (try bitwiseNotScalar(elem_val, scalar_ty, arena, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -2326,7 +1972,7 @@ pub fn bitwiseAnd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: * for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try bitwiseAndScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); + scalar.* = (try bitwiseAndScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -2365,7 +2011,7 @@ pub fn bitwiseNand(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Mod for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try bitwiseNandScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); + scalar.* = (try bitwiseNandScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -2393,7 +2039,7 @@ pub fn bitwiseOr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *M for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try bitwiseOrScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); + scalar.* = (try bitwiseOrScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -2431,7 +2077,7 @@ pub fn bitwiseXor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: * for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try bitwiseXorScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); + scalar.* = (try bitwiseXorScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -2497,7 +2143,7 @@ fn intDivInner(lhs: Value, rhs: Value, ty: Type, overflow_idx: *usize, allocator }, else => |e| return e, }; - scalar.* = try val.intern(scalar_ty, mod); + scalar.* = val.toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -2545,7 +2191,7 @@ pub fn intDivFloor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try intDivFloorScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); + scalar.* = (try intDivFloorScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -2587,7 +2233,7 @@ pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Modu for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try intModScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); + scalar.* = (try intModScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -2624,7 +2270,6 @@ pub fn intModScalar(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: /// Returns true if the value is a floating point type and is NaN. Returns false otherwise. pub fn isNan(val: Value, mod: *const Module) bool { - if (val.ip_index == .none) return false; return switch (mod.intern_pool.indexToKey(val.toIntern())) { .float => |float| switch (float.storage) { inline else => |x| std.math.isNan(x), @@ -2635,7 +2280,6 @@ pub fn isNan(val: Value, mod: *const Module) bool { /// Returns true if the value is a floating point type and is infinite. Returns false otherwise. pub fn isInf(val: Value, mod: *const Module) bool { - if (val.ip_index == .none) return false; return switch (mod.intern_pool.indexToKey(val.toIntern())) { .float => |float| switch (float.storage) { inline else => |x| std.math.isInf(x), @@ -2645,7 +2289,6 @@ pub fn isInf(val: Value, mod: *const Module) bool { } pub fn isNegativeInf(val: Value, mod: *const Module) bool { - if (val.ip_index == .none) return false; return switch (mod.intern_pool.indexToKey(val.toIntern())) { .float => |float| switch (float.storage) { inline else => |x| std.math.isNegativeInf(x), @@ -2661,7 +2304,7 @@ pub fn floatRem(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, mod: for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try floatRemScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try floatRemScalar(lhs_elem, rhs_elem, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -2694,7 +2337,7 @@ pub fn floatMod(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, mod: for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try floatModScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try floatModScalar(lhs_elem, rhs_elem, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -2755,7 +2398,7 @@ fn intMulInner(lhs: Value, rhs: Value, ty: Type, overflow_idx: *usize, allocator }, else => |e| return e, }; - scalar.* = try val.intern(scalar_ty, mod); + scalar.* = val.toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -2797,7 +2440,7 @@ pub fn intTrunc(val: Value, ty: Type, allocator: Allocator, signedness: std.buil const scalar_ty = ty.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try intTruncScalar(elem_val, scalar_ty, allocator, signedness, bits, mod)).intern(scalar_ty, mod); + scalar.* = (try intTruncScalar(elem_val, scalar_ty, allocator, signedness, bits, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -2822,7 +2465,7 @@ pub fn intTruncBitsAsValue( for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); const bits_elem = try bits.elemValue(mod, i); - scalar.* = try (try intTruncScalar(elem_val, scalar_ty, allocator, signedness, @as(u16, @intCast(bits_elem.toUnsignedInt(mod))), mod)).intern(scalar_ty, mod); + scalar.* = (try intTruncScalar(elem_val, scalar_ty, allocator, signedness, @as(u16, @intCast(bits_elem.toUnsignedInt(mod))), mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -2862,7 +2505,7 @@ pub fn shl(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try shlScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); + scalar.* = (try shlScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -2912,8 +2555,8 @@ pub fn shlWithOverflow( const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); const of_math_result = try shlWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod); - of.* = try of_math_result.overflow_bit.intern(Type.u1, mod); - scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod); + of.* = of_math_result.overflow_bit.toIntern(); + scalar.* = of_math_result.wrapped_result.toIntern(); } return OverflowArithmeticResult{ .overflow_bit = Value.fromInterned((try mod.intern(.{ .aggregate = .{ @@ -2973,7 +2616,7 @@ pub fn shlSat( for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try shlSatScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); + scalar.* = (try shlSatScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -3023,7 +2666,7 @@ pub fn shlTrunc( for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try shlTruncScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); + scalar.* = (try shlTruncScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -3053,7 +2696,7 @@ pub fn shr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try shrScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); + scalar.* = (try shrScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -3105,7 +2748,7 @@ pub fn floatNeg( const scalar_ty = float_type.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try floatNegScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try floatNegScalar(elem_val, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3148,7 +2791,7 @@ pub fn floatAdd( for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try floatAddScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try floatAddScalar(lhs_elem, rhs_elem, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3192,7 +2835,7 @@ pub fn floatSub( for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try floatSubScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try floatSubScalar(lhs_elem, rhs_elem, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3236,7 +2879,7 @@ pub fn floatDiv( for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try floatDivScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try floatDivScalar(lhs_elem, rhs_elem, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3280,7 +2923,7 @@ pub fn floatDivFloor( for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try floatDivFloorScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try floatDivFloorScalar(lhs_elem, rhs_elem, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3324,7 +2967,7 @@ pub fn floatDivTrunc( for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try floatDivTruncScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try floatDivTruncScalar(lhs_elem, rhs_elem, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3368,7 +3011,7 @@ pub fn floatMul( for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try (try floatMulScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try floatMulScalar(lhs_elem, rhs_elem, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3405,7 +3048,7 @@ pub fn sqrt(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value const scalar_ty = float_type.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try sqrtScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try sqrtScalar(elem_val, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3437,7 +3080,7 @@ pub fn sin(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value const scalar_ty = float_type.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try sinScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try sinScalar(elem_val, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3469,7 +3112,7 @@ pub fn cos(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value const scalar_ty = float_type.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try cosScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try cosScalar(elem_val, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3501,7 +3144,7 @@ pub fn tan(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value const scalar_ty = float_type.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try tanScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try tanScalar(elem_val, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3533,7 +3176,7 @@ pub fn exp(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value const scalar_ty = float_type.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try expScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try expScalar(elem_val, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3565,7 +3208,7 @@ pub fn exp2(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value const scalar_ty = float_type.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try exp2Scalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try exp2Scalar(elem_val, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3597,7 +3240,7 @@ pub fn log(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value const scalar_ty = float_type.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try logScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try logScalar(elem_val, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3629,7 +3272,7 @@ pub fn log2(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value const scalar_ty = float_type.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try log2Scalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try log2Scalar(elem_val, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3661,7 +3304,7 @@ pub fn log10(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Valu const scalar_ty = float_type.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try log10Scalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try log10Scalar(elem_val, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3693,7 +3336,7 @@ pub fn abs(val: Value, ty: Type, arena: Allocator, mod: *Module) !Value { const scalar_ty = ty.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try absScalar(elem_val, scalar_ty, mod, arena)).intern(scalar_ty, mod); + scalar.* = (try absScalar(elem_val, scalar_ty, mod, arena)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = ty.toIntern(), @@ -3744,7 +3387,7 @@ pub fn floor(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Valu const scalar_ty = float_type.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try floorScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try floorScalar(elem_val, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3776,7 +3419,7 @@ pub fn ceil(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value const scalar_ty = float_type.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try ceilScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try ceilScalar(elem_val, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3808,7 +3451,7 @@ pub fn round(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Valu const scalar_ty = float_type.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try roundScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try roundScalar(elem_val, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3840,7 +3483,7 @@ pub fn trunc(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Valu const scalar_ty = float_type.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try (try truncScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); + scalar.* = (try truncScalar(elem_val, scalar_ty, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3881,7 +3524,7 @@ pub fn mulAdd( const mulend1_elem = try mulend1.elemValue(mod, i); const mulend2_elem = try mulend2.elemValue(mod, i); const addend_elem = try addend.elemValue(mod, i); - scalar.* = try (try mulAddScalar(scalar_ty, mulend1_elem, mulend2_elem, addend_elem, mod)).intern(scalar_ty, mod); + scalar.* = (try mulAddScalar(scalar_ty, mulend1_elem, mulend2_elem, addend_elem, mod)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_type.toIntern(), @@ -3957,98 +3600,26 @@ pub fn intValueBounds(val: Value, mod: *Module) !?[2]Value { }; } -/// This type is not copyable since it may contain pointers to its inner data. -pub const Payload = struct { - tag: Tag, - - pub const Slice = struct { - base: Payload, - data: struct { - ptr: Value, - len: Value, - }, - }; - - pub const Bytes = struct { - base: Payload, - /// Includes the sentinel, if any. - data: []const u8, - }; - - pub const SubValue = struct { - base: Payload, - data: Value, - }; - - pub const Aggregate = struct { - base: Payload, - /// Field values. The types are according to the struct or array type. - /// The length is provided here so that copying a Value does not depend on the Type. - data: []Value, - }; - - pub const Union = struct { - pub const base_tag = Tag.@"union"; - - base: Payload = .{ .tag = base_tag }, - data: Data, - - pub const Data = struct { - tag: ?Value, - val: Value, - }; - }; -}; - 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 @"void": Value = .{ .ip_index = .void_value, .legacy = undefined }; -pub const @"null": Value = .{ .ip_index = .null_value, .legacy = undefined }; -pub const @"false": Value = .{ .ip_index = .bool_false, .legacy = undefined }; -pub const @"true": Value = .{ .ip_index = .bool_true, .legacy = undefined }; -pub const @"unreachable": Value = .{ .ip_index = .unreachable_value, .legacy = undefined }; - -pub const generic_poison: Value = .{ .ip_index = .generic_poison, .legacy = undefined }; -pub const generic_poison_type: Value = .{ .ip_index = .generic_poison_type, .legacy = undefined }; -pub const empty_struct: Value = .{ .ip_index = .empty_struct, .legacy = undefined }; +pub const zero_usize: Value = .{ .ip_index = .zero_usize }; +pub const zero_u8: Value = .{ .ip_index = .zero_u8 }; +pub const zero_comptime_int: Value = .{ .ip_index = .zero }; +pub const one_comptime_int: Value = .{ .ip_index = .one }; +pub const negative_one_comptime_int: Value = .{ .ip_index = .negative_one }; +pub const undef: Value = .{ .ip_index = .undef }; +pub const @"void": Value = .{ .ip_index = .void_value }; +pub const @"null": Value = .{ .ip_index = .null_value }; +pub const @"false": Value = .{ .ip_index = .bool_false }; +pub const @"true": Value = .{ .ip_index = .bool_true }; +pub const @"unreachable": Value = .{ .ip_index = .unreachable_value }; + +pub const generic_poison: Value = .{ .ip_index = .generic_poison }; +pub const generic_poison_type: Value = .{ .ip_index = .generic_poison_type }; +pub const empty_struct: Value = .{ .ip_index = .empty_struct }; pub fn makeBool(x: bool) Value { return if (x) Value.true else Value.false; } pub const RuntimeIndex = InternPool.RuntimeIndex; - -/// This function is used in the debugger pretty formatters in tools/ to fetch the -/// Tag to Payload mapping to facilitate fancy debug printing for this type. -fn dbHelper(self: *Value, tag_to_payload_map: *map: { - const tags = @typeInfo(Tag).Enum.fields; - var fields: [tags.len]std.builtin.Type.StructField = undefined; - for (&fields, tags) |*field, t| field.* = .{ - .name = t.name ++ "", - .type = *@field(Tag, t.name).Type(), - .default_value = null, - .is_comptime = false, - .alignment = 0, - }; - break :map @Type(.{ .Struct = .{ - .layout = .@"extern", - .fields = &fields, - .decls = &.{}, - .is_tuple = false, - } }); -}) void { - _ = self; - _ = tag_to_payload_map; -} - -comptime { - if (!builtin.strip_debug_info) { - _ = &dbHelper; - } -} diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index e90a68bea542..11c95e318a47 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -2216,7 +2216,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif }, else => {}, } - return func.fail("Expected a function, but instead found type '{}'", .{func_val.tag()}); + return func.fail("Expected a function, but instead found '{s}'", .{@tagName(ip.indexToKey(func_val.toIntern()))}); }; const sret = if (first_param_sret) blk: { diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 273358a6d247..8fe19d4e2107 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -12258,7 +12258,7 @@ fn genCall(self: *Self, info: union(enum) { switch (switch (func_key) { else => func_key, .ptr => |ptr| switch (ptr.addr) { - .decl => |decl| mod.intern_pool.indexToKey(try mod.declPtr(decl).internValue(mod)), + .decl => |decl| mod.intern_pool.indexToKey(mod.declPtr(decl).val.toIntern()), else => func_key, }, }) { diff --git a/src/codegen.zig b/src/codegen.zig index 5bc0d1a81f47..818284a8f06c 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -925,7 +925,7 @@ fn genDeclRef( const ptr_bits = target.ptrBitWidth(); const ptr_bytes: u64 = @divExact(ptr_bits, 8); - const decl_index = switch (zcu.intern_pool.indexToKey(try ptr_decl.internValue(zcu))) { + const decl_index = switch (zcu.intern_pool.indexToKey(ptr_decl.val.toIntern())) { .func => |func| func.owner_decl, .extern_func => |extern_func| extern_func.decl, else => ptr_decl_index, diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 32ad38cd4d71..d1575feaba77 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -2657,7 +2657,7 @@ fn genExports(o: *Object) !void { .anon, .flush => return, }; const decl = mod.declPtr(decl_index); - const tv: TypedValue = .{ .ty = decl.typeOf(mod), .val = Value.fromInterned((try decl.internValue(mod))) }; + const tv: TypedValue = .{ .ty = decl.typeOf(mod), .val = decl.val }; const fwd = o.dg.fwdDeclWriter(); const exports = mod.decl_exports.get(decl_index) orelse return; @@ -2894,7 +2894,7 @@ pub fn genDecl(o: *Object) !void { const mod = o.dg.module; const decl_index = o.dg.pass.decl; const decl = mod.declPtr(decl_index); - const tv: TypedValue = .{ .ty = decl.typeOf(mod), .val = Value.fromInterned((try decl.internValue(mod))) }; + const tv: TypedValue = .{ .ty = decl.typeOf(mod), .val = decl.val }; if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return; if (tv.val.getExternFunc(mod)) |_| { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index cef6a9f7f357..7bbe4e715a3e 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -5532,7 +5532,7 @@ pub const FuncGen = struct { const msg_decl_index = mod.panic_messages[@intFromEnum(panic_id)].unwrap().?; const msg_decl = mod.declPtr(msg_decl_index); const msg_len = msg_decl.typeOf(mod).childType(mod).arrayLen(mod); - const msg_ptr = try o.lowerValue(try msg_decl.internValue(mod)); + const msg_ptr = try o.lowerValue(msg_decl.val.toIntern()); const null_opt_addr_global = try fg.resolveNullOptUsize(); const target = mod.getTarget(); const llvm_usize = try o.lowerType(Type.usize); diff --git a/src/type.zig b/src/type.zig index 8a79cb445c23..a382a5ad97bc 100644 --- a/src/type.zig +++ b/src/type.zig @@ -2481,7 +2481,7 @@ pub const Type = struct { } const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); if (try field_ty.onePossibleValue(mod)) |field_opv| { - field_val.* = try field_opv.intern(field_ty, mod); + field_val.* = field_opv.toIntern(); } else return null; } From 152a2ceaf738301cd59165a4f17d915391321bdc Mon Sep 17 00:00:00 2001 From: mlugg Date: Tue, 26 Mar 2024 03:56:54 +0000 Subject: [PATCH 04/14] compiler: audit uses of `ptr.addr` in the frontend This commit also performs some refactors to `TypedValue.print` in preparation for improved comptime pointer access logic. Once that logic exists, `TypedValue.print` can use Sema to access pointers for more helpful printing. This commit also implements proposal #19435, because the existing logic there relied on some blatantly incorrect code in `Value.sliceLen`. Resolves: #19435 --- src/Sema.zig | 192 ++++++++------- src/TypedValue.zig | 520 +++++++++++++++++++--------------------- src/Value.zig | 136 ++++------- test/behavior/basic.zig | 25 -- 4 files changed, 406 insertions(+), 467 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 0d387faacf5e..c0b78c3e1def 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1881,10 +1881,10 @@ pub fn toConstString( air_inst: Air.Inst.Ref, reason: NeededComptimeReason, ) ![]u8 { - const wanted_type = Type.slice_const_u8; - const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); - const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, reason); - return val.toAllocatedBytes(wanted_type, sema.arena, sema.mod); + const coerced_inst = try sema.coerce(block, Type.slice_const_u8, air_inst, src); + const slice_val = try sema.resolveConstDefinedValue(block, src, coerced_inst, reason); + const arr_val = try sema.derefSliceAsArray(block, src, slice_val, reason); + return arr_val.toAllocatedBytes(arr_val.typeOf(sema.mod), sema.arena, sema.mod); } pub fn resolveConstStringIntern( @@ -14498,12 +14498,16 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai else => unreachable, }) |rhs_val| { const lhs_sub_val = if (lhs_ty.isSinglePointer(mod)) - (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? + try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty) orelse break :rs lhs_src + else if (lhs_ty.isSlice(mod)) + try sema.maybeDerefSliceAsArray(block, lhs_src, lhs_val) orelse break :rs lhs_src else lhs_val; const rhs_sub_val = if (rhs_ty.isSinglePointer(mod)) - (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).? + try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty) orelse break :rs rhs_src + else if (rhs_ty.isSlice(mod)) + try sema.maybeDerefSliceAsArray(block, rhs_src, rhs_val) orelse break :rs rhs_src else rhs_val; @@ -14623,10 +14627,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins .Pointer => { const ptr_info = operand_ty.ptrInfo(mod); switch (ptr_info.flags.size) { - // TODO: in the Many case here this should only work if the type - // has a sentinel, and this code should compute the length based - // on the sentinel value. - .Slice, .Many => { + .Slice => { const val = try sema.resolveConstDefinedValue(block, src, operand, .{ .needed_comptime_reason = "slice value being concatenated must be comptime-known", }); @@ -14636,7 +14637,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins .none => null, else => Value.fromInterned(ptr_info.sentinel), }, - .len = val.sliceLen(mod), + .len = try val.sliceLen(sema), }; }, .One => { @@ -14644,7 +14645,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins return Type.fromInterned(ptr_info.child).arrayInfo(mod); } }, - .C => {}, + .C, .Many => {}, } }, .Struct => { @@ -14830,9 +14831,11 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const ptr_addrspace = if (lhs_ty.zigTypeTag(mod) == .Pointer) lhs_ty.ptrAddressSpace(mod) else null; const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len); - if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| { + if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| ct: { const lhs_sub_val = if (lhs_ty.isSinglePointer(mod)) - (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? + try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty) orelse break :ct + else if (lhs_ty.isSlice(mod)) + try sema.maybeDerefSliceAsArray(block, lhs_src, lhs_val) orelse break :ct else lhs_val; @@ -14840,7 +14843,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // Optimization for the common pattern of a single element repeated N times, such // as zero-filling a byte array. if (lhs_len == 1 and lhs_info.sentinel == null) { - const elem_val = (try lhs_sub_val.maybeElemValueFull(sema, mod, 0)).?; + const elem_val = try lhs_sub_val.elemValue(mod, 0); break :v try mod.intern(.{ .aggregate = .{ .ty = result_ty.toIntern(), .storage = .{ .repeated_elem = elem_val.toIntern() }, @@ -14852,7 +14855,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai while (elem_i < result_len) { var lhs_i: usize = 0; while (lhs_i < lhs_len) : (lhs_i += 1) { - const elem_val = (try lhs_sub_val.maybeElemValueFull(sema, mod, lhs_i)).?; + const elem_val = try lhs_sub_val.elemValue(mod, lhs_i); element_vals[elem_i] = elem_val.toIntern(); elem_i += 1; } @@ -21124,7 +21127,9 @@ fn zirReify( .needed_comptime_reason = "operand to @Type must be comptime-known", }); const union_val = ip.indexToKey(val.toIntern()).un; - if (try sema.anyUndef(Value.fromInterned(union_val.val))) return sema.failWithUseOfUndef(block, src); + if (try sema.anyUndef(block, operand_src, Value.fromInterned(union_val.val))) { + return sema.failWithUseOfUndef(block, operand_src); + } const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?; switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) { .Type => return .type_type, @@ -21365,11 +21370,15 @@ fn zirReify( const payload_val = Value.fromInterned(union_val.val).optionalValue(mod) orelse return Air.internedToRef(Type.anyerror.toIntern()); - const len = try sema.usizeCast(block, src, payload_val.sliceLen(mod)); + const names_val = try sema.derefSliceAsArray(block, src, payload_val, .{ + .needed_comptime_reason = "error set contents must be comptime-known", + }); + + const len = try sema.usizeCast(block, src, names_val.typeOf(mod).arrayLen(mod)); var names: InferredErrorSet.NameMap = .{}; try names.ensureUnusedCapacity(sema.arena, len); for (0..len) |i| { - const elem_val = (try payload_val.maybeElemValueFull(sema, mod, i)).?; + const elem_val = try names_val.elemValue(mod, i); const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern())); const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( ip, @@ -21417,7 +21426,7 @@ fn zirReify( const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); // Decls - if (decls_val.sliceLen(mod) > 0) { + if (try decls_val.sliceLen(sema) > 0) { return sema.fail(block, src, "reified structs must have no decls", .{}); } @@ -21425,7 +21434,11 @@ fn zirReify( return sema.fail(block, src, "non-packed struct does not support backing integer type", .{}); } - return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool()); + const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ + .needed_comptime_reason = "struct fields must be comptime-known", + }); + + return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_arr, name_strategy, is_tuple_val.toBool()); }, .Enum => { const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); @@ -21446,11 +21459,15 @@ fn zirReify( try ip.getOrPutString(gpa, "is_exhaustive"), ).?); - if (decls_val.sliceLen(mod) > 0) { + if (try decls_val.sliceLen(sema) > 0) { return sema.fail(block, src, "reified enums must have no decls", .{}); } - return sema.reifyEnum(block, inst, src, tag_type_val.toType(), is_exhaustive_val.toBool(), fields_val, name_strategy); + const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ + .needed_comptime_reason = "enum fields must be comptime-known", + }); + + return sema.reifyEnum(block, inst, src, tag_type_val.toType(), is_exhaustive_val.toBool(), fields_arr, name_strategy); }, .Opaque => { const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); @@ -21460,7 +21477,7 @@ fn zirReify( ).?); // Decls - if (decls_val.sliceLen(mod) > 0) { + if (try decls_val.sliceLen(sema) > 0) { return sema.fail(block, src, "reified opaque must have no decls", .{}); } @@ -21505,12 +21522,16 @@ fn zirReify( try ip.getOrPutString(gpa, "decls"), ).?); - if (decls_val.sliceLen(mod) > 0) { + if (try decls_val.sliceLen(sema) > 0) { return sema.fail(block, src, "reified unions must have no decls", .{}); } const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); - return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_val, name_strategy); + const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ + .needed_comptime_reason = "union fields must be comptime-known", + }); + + return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_arr, name_strategy); }, .Fn => { const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); @@ -21530,7 +21551,7 @@ fn zirReify( ip, try ip.getOrPutString(gpa, "return_type"), ).?); - const params_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex( + const params_slice_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex( ip, try ip.getOrPutString(gpa, "params"), ).?); @@ -21549,12 +21570,16 @@ fn zirReify( const return_type = return_type_val.optionalValue(mod) orelse return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); - const args_len = try sema.usizeCast(block, src, params_val.sliceLen(mod)); + const params_val = try sema.derefSliceAsArray(block, operand_src, params_slice_val, .{ + .needed_comptime_reason = "function parameters must be comptime-known", + }); + + const args_len = try sema.usizeCast(block, src, params_val.typeOf(mod).arrayLen(mod)); const param_types = try sema.arena.alloc(InternPool.Index, args_len); var noalias_bits: u32 = 0; for (param_types, 0..) |*param_type, i| { - const elem_val = (try params_val.maybeElemValueFull(sema, mod, i)).?; + const elem_val = try params_val.elemValue(mod, i); const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern())); const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( ip, @@ -21615,7 +21640,7 @@ fn reifyEnum( // This logic must stay in sync with the structure of `std.builtin.Type.Enum` - search for `fieldValue`. - const fields_len: u32 = @intCast(fields_val.sliceLen(mod)); + const fields_len: u32 = @intCast(fields_val.typeOf(mod).arrayLen(mod)); // The validation work here is non-trivial, and it's possible the type already exists. // So in this first pass, let's just construct a hash to optimize for this case. If the @@ -21629,7 +21654,7 @@ fn reifyEnum( std.hash.autoHash(&hasher, fields_len); for (0..fields_len) |field_idx| { - const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; + const field_info = try fields_val.elemValue(mod, field_idx); const field_name_val = try field_info.fieldValue(mod, 0); const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1)); @@ -21674,7 +21699,7 @@ fn reifyEnum( wip_ty.setTagTy(ip, tag_ty.toIntern()); for (0..fields_len) |field_idx| { - const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; + const field_info = try fields_val.elemValue(mod, field_idx); const field_name_val = try field_info.fieldValue(mod, 0); const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1)); @@ -21736,7 +21761,7 @@ fn reifyUnion( // This logic must stay in sync with the structure of `std.builtin.Type.Union` - search for `fieldValue`. - const fields_len: u32 = @intCast(fields_val.sliceLen(mod)); + const fields_len: u32 = @intCast(fields_val.typeOf(mod).arrayLen(mod)); // The validation work here is non-trivial, and it's possible the type already exists. // So in this first pass, let's just construct a hash to optimize for this case. If the @@ -21752,7 +21777,7 @@ fn reifyUnion( var any_aligns = false; for (0..fields_len) |field_idx| { - const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; + const field_info = try fields_val.elemValue(mod, field_idx); const field_name_val = try field_info.fieldValue(mod, 0); const field_type_val = try field_info.fieldValue(mod, 1); @@ -21828,7 +21853,7 @@ fn reifyUnion( var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len); for (field_types, 0..) |*field_ty, field_idx| { - const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; + const field_info = try fields_val.elemValue(mod, field_idx); const field_name_val = try field_info.fieldValue(mod, 0); const field_type_val = try field_info.fieldValue(mod, 1); @@ -21880,7 +21905,7 @@ fn reifyUnion( try field_names.ensureTotalCapacity(sema.arena, fields_len); for (field_types, 0..) |*field_ty, field_idx| { - const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; + const field_info = try fields_val.elemValue(mod, field_idx); const field_name_val = try field_info.fieldValue(mod, 0); const field_type_val = try field_info.fieldValue(mod, 1); @@ -21974,7 +21999,7 @@ fn reifyStruct( // This logic must stay in sync with the structure of `std.builtin.Type.Struct` - search for `fieldValue`. - const fields_len: u32 = @intCast(fields_val.sliceLen(mod)); + const fields_len: u32 = @intCast(fields_val.typeOf(mod).arrayLen(mod)); // The validation work here is non-trivial, and it's possible the type already exists. // So in this first pass, let's just construct a hash to optimize for this case. If the @@ -21993,7 +22018,7 @@ fn reifyStruct( var any_aligned_fields = false; for (0..fields_len) |field_idx| { - const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; + const field_info = try fields_val.elemValue(mod, field_idx); const field_name_val = try field_info.fieldValue(mod, 0); const field_type_val = try field_info.fieldValue(mod, 1); @@ -22071,7 +22096,7 @@ fn reifyStruct( const struct_type = ip.loadStructType(wip_ty.index); for (0..fields_len) |field_idx| { - const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; + const field_info = try fields_val.elemValue(mod, field_idx); const field_name_val = try field_info.fieldValue(mod, 0); const field_type_val = try field_info.fieldValue(mod, 1); @@ -23892,11 +23917,9 @@ fn resolveExportOptions( const visibility_src = sema.maybeOptionsSrc(block, src, "visibility"); const name_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src); - const name_val = try sema.resolveConstDefinedValue(block, name_src, name_operand, .{ + const name = try sema.toConstString(block, name_src, name_operand, .{ .needed_comptime_reason = "name of exported value must be comptime-known", }); - const name_ty = Type.slice_const_u8; - const name = try name_val.toAllocatedBytes(name_ty, sema.arena, mod); const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "linkage"), linkage_src); const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_operand, .{ @@ -23908,9 +23931,10 @@ fn resolveExportOptions( const section_opt_val = try sema.resolveConstDefinedValue(block, section_src, section_operand, .{ .needed_comptime_reason = "linksection of exported value must be comptime-known", }); - const section_ty = Type.slice_const_u8; const section = if (section_opt_val.optionalValue(mod)) |section_val| - try section_val.toAllocatedBytes(section_ty, sema.arena, mod) + try sema.toConstString(block, section_src, Air.internedToRef(section_val.toIntern()), .{ + .needed_comptime_reason = "linksection of exported value must be comptime-known", + }) else null; @@ -26028,10 +26052,9 @@ fn resolveExternOptions( const thread_local_src = sema.maybeOptionsSrc(block, src, "thread_local"); const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src); - const name_val = try sema.resolveConstDefinedValue(block, name_src, name_ref, .{ + const name = try sema.toConstString(block, name_src, name_ref, .{ .needed_comptime_reason = "name of the extern symbol must be comptime-known", }); - const name = try name_val.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod); const library_name_inst = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "library_name"), library_src); const library_name_val = try sema.resolveConstDefinedValue(block, library_src, library_name_inst, .{ @@ -26050,7 +26073,9 @@ fn resolveExternOptions( }); const library_name = if (library_name_val.optionalValue(mod)) |library_name_payload| library_name: { - const library_name = try library_name_payload.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod); + const library_name = try sema.toConstString(block, library_src, Air.internedToRef(library_name_payload.toIntern()), .{ + .needed_comptime_reason = "library in which extern symbol is must be comptime-known", + }); if (library_name.len == 0) { return sema.fail(block, library_src, "library name cannot be empty", .{}); } @@ -28564,7 +28589,7 @@ fn elemValSlice( if (maybe_slice_val) |slice_val| { runtime_src = elem_index_src; - const slice_len = slice_val.sliceLen(mod); + const slice_len = try slice_val.sliceLen(sema); const slice_len_s = slice_len + @intFromBool(slice_sent); if (slice_len_s == 0) { return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); @@ -28589,7 +28614,7 @@ fn elemValSlice( try sema.requireRuntimeBlock(block, src, runtime_src); if (oob_safety and block.wantSafety()) { const len_inst = if (maybe_slice_val) |slice_val| - try mod.intRef(Type.usize, slice_val.sliceLen(mod)) + try mod.intRef(Type.usize, try slice_val.sliceLen(sema)) else try block.addTyOp(.slice_len, Type.usize, slice); const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; @@ -28626,7 +28651,7 @@ fn elemPtrSlice( if (slice_val.isUndef(mod)) { return mod.undefRef(elem_ptr_ty); } - const slice_len = slice_val.sliceLen(mod); + const slice_len = try slice_val.sliceLen(sema); const slice_len_s = slice_len + @intFromBool(slice_sent); if (slice_len_s == 0) { return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); @@ -28649,7 +28674,7 @@ fn elemPtrSlice( const len_inst = len: { if (maybe_undef_slice_val) |slice_val| if (!slice_val.isUndef(mod)) - break :len try mod.intRef(Type.usize, slice_val.sliceLen(mod)); + break :len try mod.intRef(Type.usize, try slice_val.sliceLen(sema)); break :len try block.addTyOp(.slice_len, Type.usize, slice); }; const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; @@ -31523,16 +31548,11 @@ fn coerceArrayPtrToSlice( if (try sema.resolveValue(inst)) |val| { const ptr_array_ty = sema.typeOf(inst); const array_ty = ptr_array_ty.childType(mod); + const slice_ptr_ty = dest_ty.slicePtrFieldType(mod); + const slice_ptr = try mod.getCoerced(val, slice_ptr_ty); const slice_val = try mod.intern(.{ .slice = .{ .ty = dest_ty.toIntern(), - .ptr = try mod.intern(.{ .ptr = .{ - .ty = dest_ty.slicePtrFieldType(mod).toIntern(), - .addr = switch (mod.intern_pool.indexToKey(val.toIntern())) { - .undef => .{ .int = try mod.intern(.{ .undef = .usize_type }) }, - .ptr => |ptr| ptr.addr, - else => unreachable, - }, - } }), + .ptr = slice_ptr.toIntern(), .len = (try mod.intValue(Type.usize, array_ty.arrayLen(mod))).toIntern(), } }); return Air.internedToRef(slice_val); @@ -32602,7 +32622,7 @@ fn analyzeSliceLen( if (slice_val.isUndef(mod)) { return mod.undefRef(Type.usize); } - return mod.intRef(Type.usize, slice_val.sliceLen(sema.mod)); + return mod.intRef(Type.usize, try slice_val.sliceLen(sema)); } try sema.requireRuntimeBlock(block, src, null); return block.addTyOp(.slice_len, Type.usize, slice_inst); @@ -33041,7 +33061,7 @@ fn analyzeSlice( return sema.fail(block, src, "slice of undefined", .{}); } const has_sentinel = slice_ty.sentinel(mod) != null; - const slice_len = slice_val.sliceLen(mod); + const slice_len = try slice_val.sliceLen(sema); const len_plus_sent = slice_len + @intFromBool(has_sentinel); const slice_len_val_with_sentinel = try mod.intValue(Type.usize, len_plus_sent); if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, Type.usize))) { @@ -33056,7 +33076,7 @@ fn analyzeSlice( "end index {} out of bounds for slice of length {d}{s}", .{ end_val.fmtValue(Type.usize, mod), - slice_val.sliceLen(mod), + try slice_val.sliceLen(sema), sentinel_label, }, ); @@ -33285,7 +33305,7 @@ fn analyzeSlice( if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| { // we don't need to add one for sentinels because the // underlying value data includes the sentinel - break :blk try mod.intRef(Type.usize, slice_val.sliceLen(mod)); + break :blk try mod.intRef(Type.usize, try slice_val.sliceLen(sema)); } const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice); @@ -39003,22 +39023,22 @@ fn validateRuntimeValue(sema: *Sema, block: *Block, val_src: LazySrcLoc, val: Ai } /// Returns true if any value contained in `val` is undefined. -fn anyUndef(sema: *Sema, val: Value) !bool { +fn anyUndef(sema: *Sema, block: *Block, src: LazySrcLoc, val: Value) !bool { const mod = sema.mod; - return switch (val.toIntern()) { + return switch (mod.intern_pool.indexToKey(val.toIntern())) { .undef => true, - else => switch (mod.intern_pool.indexToKey(val.toIntern())) { - .undef => true, - .simple_value => |v| v == .undefined, - .slice => |slice| for (0..@intCast(Value.fromInterned(slice.len).toUnsignedInt(mod))) |idx| { - if (try sema.anyUndef((try val.maybeElemValueFull(sema, mod, idx)).?)) break true; - } else false, - .aggregate => |aggregate| for (0..aggregate.storage.values().len) |i| { - const elem = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.values()[i]; - if (try sema.anyUndef(Value.fromInterned(elem))) break true; - } else false, - else => false, - }, + .simple_value => |v| v == .undefined, + .slice => { + // If the slice contents are runtime-known, reification will fail later on with a + // specific error message. + const arr = try sema.maybeDerefSliceAsArray(block, src, val) orelse return false; + return sema.anyUndef(block, src, arr); + }, + .aggregate => |aggregate| for (0..aggregate.storage.values().len) |i| { + const elem = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.values()[i]; + if (try sema.anyUndef(block, src, Value.fromInterned(elem))) break true; + } else false, + else => false, }; } @@ -39050,6 +39070,20 @@ fn derefSliceAsArray( slice_val: Value, reason: NeededComptimeReason, ) CompileError!Value { + return try sema.maybeDerefSliceAsArray(block, src, slice_val) orelse { + return sema.failWithNeededComptime(block, src, reason); + }; +} + +/// Given a slice value, attempts to dereference it into a comptime-known array. +/// Returns `null` if the contents of the slice are not comptime-known. +/// Asserts that `slice_val` is a slice. +fn maybeDerefSliceAsArray( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + slice_val: Value, +) CompileError!?Value { const zcu = sema.mod; const ip = &zcu.intern_pool; assert(Type.fromInterned(ip.typeOf(slice_val.toIntern())).isSlice(zcu)); @@ -39072,7 +39106,5 @@ fn derefSliceAsArray( break :p p; }); const casted_ptr = try zcu.getCoerced(Value.fromInterned(slice.ptr), ptr_ty); - return try sema.pointerDeref(block, src, casted_ptr, ptr_ty) orelse { - return sema.failWithNeededComptime(block, src, reason); - }; + return sema.pointerDeref(block, src, casted_ptr, ptr_ty); } diff --git a/src/TypedValue.zig b/src/TypedValue.zig index 4679ce20ee49..ceef4116a264 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -1,7 +1,10 @@ const std = @import("std"); const Type = @import("type.zig").Type; const Value = @import("Value.zig"); -const Module = @import("Module.zig"); +const Zcu = @import("Module.zig"); +const Module = Zcu; +const Sema = @import("Sema.zig"); +const InternPool = @import("InternPool.zig"); const Allocator = std.mem.Allocator; const TypedValue = @This(); const Target = std.Target; @@ -61,8 +64,10 @@ pub fn format( ) !void { _ = options; comptime std.debug.assert(fmt.len == 0); - return ctx.tv.print(writer, 3, ctx.mod) catch |err| switch (err) { + return ctx.tv.print(writer, 3, ctx.mod, null) catch |err| switch (err) { error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function + error.ComptimeBreak, error.ComptimeReturn => unreachable, + error.AnalysisFail, error.NeededSourceLocation => unreachable, // TODO: re-evaluate when we actually pass `opt_sema` else => |e| return e, }; } @@ -73,11 +78,12 @@ pub fn print( writer: anytype, level: u8, mod: *Module, -) (@TypeOf(writer).Error || Allocator.Error)!void { - var val = tv.val; - var ty = tv.ty; + /// If this `Sema` is provided, we will recurse through pointers where possible to provide friendly output. + opt_sema: ?*Sema, +) (@TypeOf(writer).Error || Module.CompileError)!void { const ip = &mod.intern_pool; - while (true) switch (ip.indexToKey(val.toIntern())) { + const val = tv.val; + switch (ip.indexToKey(val.toIntern())) { .int_type, .ptr_type, .array_type, @@ -94,324 +100,298 @@ pub fn print( .func_type, .error_set_type, .inferred_error_set_type, - => return Type.print(val.toType(), writer, mod), - .undef => return writer.writeAll("undefined"), + => try Type.print(val.toType(), writer, mod), + .undef => try writer.writeAll("undefined"), .simple_value => |simple_value| switch (simple_value) { - .void => return writer.writeAll("{}"), - .empty_struct => return printAggregate(ty, val, writer, level, mod), - .generic_poison => return writer.writeAll("(generic poison)"), - else => return writer.writeAll(@tagName(simple_value)), + .void => try writer.writeAll("{}"), + .empty_struct => try writer.writeAll(".{}"), + .generic_poison => try writer.writeAll("(generic poison)"), + else => try writer.writeAll(@tagName(simple_value)), }, - .variable => return writer.writeAll("(variable)"), - .extern_func => |extern_func| return writer.print("(extern function '{}')", .{ + .variable => try writer.writeAll("(variable)"), + .extern_func => |extern_func| try writer.print("(extern function '{}')", .{ mod.declPtr(extern_func.decl).name.fmt(ip), }), - .func => |func| return writer.print("(function '{}')", .{ + .func => |func| try writer.print("(function '{}')", .{ mod.declPtr(func.owner_decl).name.fmt(ip), }), .int => |int| switch (int.storage) { - inline .u64, .i64, .big_int => |x| return writer.print("{}", .{x}), - .lazy_align => |lazy_ty| return writer.print("{d}", .{ - Type.fromInterned(lazy_ty).abiAlignment(mod), - }), - .lazy_size => |lazy_ty| return writer.print("{d}", .{ - Type.fromInterned(lazy_ty).abiSize(mod), - }), + inline .u64, .i64, .big_int => |x| try writer.print("{}", .{x}), + .lazy_align => |ty| if (opt_sema) |sema| { + const a = (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar; + try writer.print("{}", .{a.toByteUnits(0)}); + } else try writer.print("@alignOf({})", .{Type.fromInterned(ty).fmt(mod)}), + .lazy_size => |ty| if (opt_sema) |sema| { + const s = (try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar; + try writer.print("{}", .{s}); + } else try writer.print("@sizeOf({})", .{Type.fromInterned(ty).fmt(mod)}), }, - .err => |err| return writer.print("error.{}", .{ + .err => |err| try writer.print("error.{}", .{ err.name.fmt(ip), }), .error_union => |error_union| switch (error_union.val) { - .err_name => |err_name| return writer.print("error.{}", .{ + .err_name => |err_name| try writer.print("error.{}", .{ err_name.fmt(ip), }), - .payload => |payload| { - val = Value.fromInterned(payload); - ty = ty.errorUnionPayload(mod); - }, + .payload => |payload| try print(.{ + .ty = tv.ty.errorUnionPayload(mod), + .val = Value.fromInterned(payload), + }, writer, level, mod, opt_sema), }, - .enum_literal => |enum_literal| return writer.print(".{}", .{ + .enum_literal => |enum_literal| try writer.print(".{}", .{ enum_literal.fmt(ip), }), .enum_tag => |enum_tag| { - if (level == 0) { - return writer.writeAll("(enum)"); - } - const enum_type = ip.loadEnumType(ty.toIntern()); + const enum_type = ip.loadEnumType(val.typeOf(mod).toIntern()); if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| { try writer.print(".{i}", .{enum_type.names.get(ip)[tag_index].fmt(ip)}); return; } + if (level == 0) { + try writer.writeAll("@enumFromInt(...)"); + } try writer.writeAll("@enumFromInt("); try print(.{ .ty = Type.fromInterned(ip.typeOf(enum_tag.int)), .val = Value.fromInterned(enum_tag.int), - }, writer, level - 1, mod); + }, writer, level - 1, mod, opt_sema); try writer.writeAll(")"); - return; }, - .empty_enum_value => return writer.writeAll("(empty enum value)"), + .empty_enum_value => try writer.writeAll("(empty enum value)"), .float => |float| switch (float.storage) { - inline else => |x| return writer.print("{d}", .{@as(f64, @floatCast(x))}), + inline else => |x| try writer.print("{d}", .{@as(f64, @floatCast(x))}), }, .slice => |slice| { - const ptr_ty = switch (ip.indexToKey(slice.ptr)) { - .ptr => |ptr| ty: { - if (ptr.addr == .int) return print(.{ - .ty = Type.fromInterned(ptr.ty), - .val = Value.fromInterned(slice.ptr), - }, writer, level - 1, mod); - break :ty ip.indexToKey(ptr.ty).ptr_type; - }, - .undef => |ptr_ty| ip.indexToKey(ptr_ty).ptr_type, - else => unreachable, + const print_contents = switch (ip.getBackingAddrTag(slice.ptr).?) { + .field, .elem, .eu_payload, .opt_payload => unreachable, + .anon_decl, .comptime_alloc, .comptime_field => true, + .decl, .int => false, }; - if (level == 0) { - return writer.writeAll(".{ ... }"); - } - const elem_ty = Type.fromInterned(ptr_ty.child); - const len = Value.fromInterned(slice.len).toUnsignedInt(mod); - if (elem_ty.eql(Type.u8, mod)) str: { - const max_len = @min(len, max_string_len); - var buf: [max_string_len]u8 = undefined; - for (buf[0..max_len], 0..) |*c, i| { - const maybe_elem = try val.maybeElemValue(mod, i); - const elem = maybe_elem orelse return writer.writeAll(".{ (reinterpreted data) }"); - if (elem.isUndef(mod)) break :str; - c.* = @as(u8, @intCast(elem.toUnsignedInt(mod))); - } - const truncated = if (len > max_string_len) " (truncated)" else ""; - return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); + if (print_contents) { + // TODO: eventually we want to load the slice as an array with `opt_sema`, but that's + // currently not possible without e.g. triggering compile errors. } - try writer.writeAll(".{ "); - const max_len = @min(len, max_aggregate_items); - for (0..max_len) |i| { - if (i != 0) try writer.writeAll(", "); - const maybe_elem = try val.maybeElemValue(mod, i); - const elem = maybe_elem orelse return writer.writeAll("(reinterpreted data) }"); - try print(.{ - .ty = elem_ty, - .val = elem, - }, writer, level - 1, mod); - } - if (len > max_aggregate_items) { - try writer.writeAll(", ..."); - } - return writer.writeAll(" }"); + try printPtr(slice.ptr, writer, false, false, 0, level, mod, opt_sema); + try writer.writeAll("[0.."); + try print(.{ + .ty = Type.usize, + .val = Value.fromInterned(slice.len), + }, writer, level - 1, mod, opt_sema); + try writer.writeAll("]"); }, - .ptr => |ptr| { - switch (ptr.addr) { - .decl => |decl_index| { - const decl = mod.declPtr(decl_index); - if (level == 0) return writer.print("(decl '{}')", .{decl.name.fmt(ip)}); - return print(.{ - .ty = decl.typeOf(mod), - .val = decl.val, - }, writer, level - 1, mod); - }, - .anon_decl => |anon_decl| { - const decl_val = anon_decl.val; - if (level == 0) return writer.print("(anon decl '{d}')", .{ - @intFromEnum(decl_val), - }); - return print(.{ - .ty = Type.fromInterned(ip.typeOf(decl_val)), - .val = Value.fromInterned(decl_val), - }, writer, level - 1, mod); - }, - .comptime_alloc => { - // TODO: we need a Sema to print this! - return writer.writeAll("(comptime alloc)"); - }, - .comptime_field => |field_val_ip| { - return print(.{ - .ty = Type.fromInterned(ip.typeOf(field_val_ip)), - .val = Value.fromInterned(field_val_ip), - }, writer, level - 1, mod); - }, - .int => |int_ip| { - try writer.writeAll("@ptrFromInt("); - try print(.{ - .ty = Type.usize, - .val = Value.fromInterned(int_ip), - }, writer, level - 1, mod); - try writer.writeByte(')'); - }, - .eu_payload => |eu_ip| { - try writer.writeAll("(payload of "); - try print(.{ - .ty = Type.fromInterned(ip.typeOf(eu_ip)), - .val = Value.fromInterned(eu_ip), - }, writer, level - 1, mod); - try writer.writeAll(")"); - }, - .opt_payload => |opt_ip| { - try print(.{ - .ty = Type.fromInterned(ip.typeOf(opt_ip)), - .val = Value.fromInterned(opt_ip), - }, writer, level - 1, mod); - try writer.writeAll(".?"); - }, - .elem => |elem| { - if (level == 0) { - try writer.writeAll("(...)"); - } else { - try print(.{ - .ty = Type.fromInterned(ip.typeOf(elem.base)), - .val = Value.fromInterned(elem.base), - }, writer, level - 1, mod); - } - try writer.print("[{}]", .{elem.index}); - }, - .field => |field| { - const ptr_container_ty = Type.fromInterned(ip.typeOf(field.base)); - if (level == 0) { - try writer.writeAll("(...)"); - } else { - try print(.{ - .ty = ptr_container_ty, - .val = Value.fromInterned(field.base), - }, writer, level - 1, mod); - } - - const container_ty = ptr_container_ty.childType(mod); - switch (container_ty.zigTypeTag(mod)) { - .Struct => { - if (container_ty.structFieldName(@intCast(field.index), mod).unwrap()) |field_name| { - try writer.print(".{i}", .{field_name.fmt(ip)}); - } else { - try writer.print("[{d}]", .{field.index}); - } - }, - .Union => { - const field_name = mod.typeToUnion(container_ty).?.loadTagType(ip).names.get(ip)[@intCast(field.index)]; - try writer.print(".{i}", .{field_name.fmt(ip)}); - }, - .Pointer => { - std.debug.assert(container_ty.isSlice(mod)); - try writer.writeAll(switch (field.index) { - Value.slice_ptr_index => ".ptr", - Value.slice_len_index => ".len", - else => unreachable, - }); - }, - else => unreachable, - } - }, + .ptr => { + const print_contents = switch (ip.getBackingAddrTag(val.toIntern()).?) { + .field, .elem, .eu_payload, .opt_payload => unreachable, + .anon_decl, .comptime_alloc, .comptime_field => true, + .decl, .int => false, + }; + if (print_contents) { + // TODO: eventually we want to load the pointer with `opt_sema`, but that's + // currently not possible without e.g. triggering compile errors. } - return; + try printPtr(val.toIntern(), writer, false, false, 0, level, mod, opt_sema); }, .opt => |opt| switch (opt.val) { - .none => return writer.writeAll("null"), - else => |payload| { - val = Value.fromInterned(payload); - ty = ty.optionalChild(mod); - }, - }, - .aggregate => |aggregate| switch (aggregate.storage) { - .bytes => |bytes| { - // Strip the 0 sentinel off of strings before printing - const zero_sent = blk: { - const sent = ty.sentinel(mod) orelse break :blk false; - break :blk sent.eql(Value.zero_u8, Type.u8, mod); - }; - const str = if (zero_sent) bytes[0 .. bytes.len - 1] else bytes; - return writer.print("\"{}\"", .{std.zig.fmtEscapes(str)}); - }, - .elems, .repeated_elem => return printAggregate(ty, val, writer, level, mod), + .none => try writer.writeAll("null"), + else => |payload| try print(.{ + .ty = tv.ty.childType(mod), + .val = Value.fromInterned(payload), + }, writer, level, mod, opt_sema), }, + .aggregate => |aggregate| try printAggregate(val, aggregate, writer, level, mod, opt_sema), .un => |un| { - try writer.writeAll(".{ "); - if (level > 0) { - if (un.tag != .none) { - try print(.{ - .ty = ty.unionTagTypeHypothetical(mod), - .val = Value.fromInterned(un.tag), - }, writer, level - 1, mod); - try writer.writeAll(" = "); - const field_ty = ty.unionFieldType(Value.fromInterned(un.tag), mod).?; - try print(.{ - .ty = field_ty, - .val = Value.fromInterned(un.val), - }, writer, level - 1, mod); - } else { - try writer.writeAll("(unknown tag) = "); - const backing_ty = try ty.unionBackingType(mod); - try print(.{ - .ty = backing_ty, - .val = Value.fromInterned(un.val), - }, writer, level - 1, mod); - } - } else try writer.writeAll("..."); - return writer.writeAll(" }"); + if (level == 0) { + try writer.writeAll(".{ ... }"); + return; + } + if (un.tag == .none) { + const backing_ty = try tv.ty.unionBackingType(mod); + try writer.print("@bitCast(@as({}, ", .{backing_ty.fmt(mod)}); + try print(.{ + .ty = backing_ty, + .val = Value.fromInterned(un.val), + }, writer, level - 1, mod, opt_sema); + try writer.writeAll("))"); + } else { + try writer.writeAll(".{ "); + try print(.{ + .ty = tv.ty.unionTagTypeHypothetical(mod), + .val = Value.fromInterned(un.tag), + }, writer, level - 1, mod, opt_sema); + try writer.writeAll(" = "); + const field_ty = tv.ty.unionFieldType(Value.fromInterned(un.tag), mod).?; + try print(.{ + .ty = field_ty, + .val = Value.fromInterned(un.val), + }, writer, level - 1, mod, opt_sema); + try writer.writeAll(" }"); + } }, .memoized_call => unreachable, - }; + } } fn printAggregate( - ty: Type, val: Value, + aggregate: InternPool.Key.Aggregate, writer: anytype, level: u8, - mod: *Module, -) (@TypeOf(writer).Error || Allocator.Error)!void { + zcu: *Zcu, + opt_sema: ?*Sema, +) (@TypeOf(writer).Error || Module.CompileError)!void { if (level == 0) { return writer.writeAll(".{ ... }"); } - const ip = &mod.intern_pool; - if (ty.zigTypeTag(mod) == .Struct) { - try writer.writeAll(".{"); - const max_len = @min(ty.structFieldCount(mod), max_aggregate_items); - - for (0..max_len) |i| { - if (i != 0) try writer.writeAll(", "); + const ip = &zcu.intern_pool; + const ty = Type.fromInterned(aggregate.ty); + switch (ty.zigTypeTag(zcu)) { + .Struct => if (!ty.isTuple(zcu)) { + if (ty.structFieldCount(zcu) == 0) { + return writer.writeAll(".{}"); + } + try writer.writeAll(".{ "); + const max_len = @min(ty.structFieldCount(zcu), max_aggregate_items); + for (0..max_len) |i| { + if (i != 0) try writer.writeAll(", "); + const field_name = ty.structFieldName(@intCast(i), zcu).unwrap().?; + try writer.print(".{i} = ", .{field_name.fmt(ip)}); + try print(.{ + .ty = ty.structFieldType(i, zcu), + .val = try val.fieldValue(zcu, i), + }, writer, level - 1, zcu, opt_sema); + } + try writer.writeAll(" }"); + return; + }, + .Array => if (aggregate.storage == .bytes) { + return writer.print("\"{}\".*", .{std.zig.fmtEscapes(aggregate.storage.bytes)}); + } else if (ty.arrayLen(zcu) == 0) { + return writer.writeAll(".{}"); + }, + .Vector => if (ty.arrayLen(zcu) == 0) { + return writer.writeAll(".{}"); + }, + else => unreachable, + } - const field_name = ty.structFieldName(@intCast(i), mod); + const elem_ty = ty.childType(zcu); + const len = ty.arrayLen(zcu); - if (field_name.unwrap()) |name| try writer.print(".{} = ", .{name.fmt(ip)}); - try print(.{ - .ty = ty.structFieldType(i, mod), - .val = try val.fieldValue(mod, i), - }, writer, level - 1, mod); - } - if (ty.structFieldCount(mod) > max_aggregate_items) { - try writer.writeAll(", ..."); - } - return writer.writeAll("}"); - } else { - const elem_ty = ty.elemType2(mod); - const len = ty.arrayLen(mod); + try writer.writeAll(".{ "); - if (elem_ty.eql(Type.u8, mod)) str: { - const max_len: usize = @min(len, max_string_len); - var buf: [max_string_len]u8 = undefined; + const max_len = @min(len, max_aggregate_items); + for (0..max_len) |i| { + if (i != 0) try writer.writeAll(", "); + try print(.{ + .ty = elem_ty, + .val = try val.fieldValue(zcu, i), + }, writer, level - 1, zcu, opt_sema); + } + if (len > max_aggregate_items) { + try writer.writeAll(", ..."); + } + return writer.writeAll(" }"); +} - var i: u32 = 0; - while (i < max_len) : (i += 1) { - const elem = try val.fieldValue(mod, i); - if (elem.isUndef(mod)) break :str; - buf[i] = std.math.cast(u8, elem.toUnsignedInt(mod)) orelse break :str; +fn printPtr( + ptr_val: InternPool.Index, + writer: anytype, + force_type: bool, + force_addrof: bool, + leading_parens: u32, + level: u8, + zcu: *Zcu, + opt_sema: ?*Sema, +) (@TypeOf(writer).Error || Module.CompileError)!void { + const ip = &zcu.intern_pool; + const ptr = switch (ip.indexToKey(ptr_val)) { + .undef => |ptr_ty| { + if (force_addrof) try writer.writeAll("&"); + try writer.writeByteNTimes('(', leading_parens); + try writer.print("@as({}, undefined)", .{Type.fromInterned(ptr_ty).fmt(zcu)}); + return; + }, + .ptr => |ptr| ptr, + else => unreachable, + }; + switch (ptr.addr) { + .int => |int| { + if (force_addrof) try writer.writeAll("&"); + try writer.writeByteNTimes('(', leading_parens); + if (force_type) { + try writer.print("@as({}, @ptrFromInt(", .{Type.fromInterned(ptr.ty).fmt(zcu)}); + try print(.{ + .ty = Type.usize, + .val = Value.fromInterned(int), + }, writer, level - 1, zcu, opt_sema); + try writer.writeAll("))"); + } else { + try writer.writeAll("@ptrFromInt("); + try print(.{ + .ty = Type.usize, + .val = Value.fromInterned(int), + }, writer, level - 1, zcu, opt_sema); + try writer.writeAll(")"); } - - const truncated = if (len > max_string_len) " (truncated)" else ""; - return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); - } - - try writer.writeAll(".{ "); - - const max_len = @min(len, max_aggregate_items); - var i: u32 = 0; - while (i < max_len) : (i += 1) { - if (i != 0) try writer.writeAll(", "); + }, + .decl => |index| { + try writer.writeAll("&"); + try zcu.declPtr(index).renderFullyQualifiedName(zcu, writer); + }, + .comptime_alloc => try writer.writeAll("&(comptime alloc)"), + .anon_decl => |anon| { + const ty = Type.fromInterned(ip.typeOf(anon.val)); + try writer.print("&@as({}, ", .{ty.fmt(zcu)}); try print(.{ - .ty = elem_ty, - .val = try val.fieldValue(mod, i), - }, writer, level - 1, mod); - } - if (len > max_aggregate_items) { - try writer.writeAll(", ..."); - } - return writer.writeAll(" }"); + .ty = ty, + .val = Value.fromInterned(anon.val), + }, writer, level - 1, zcu, opt_sema); + try writer.writeAll(")"); + }, + .comptime_field => |val| { + const ty = Type.fromInterned(ip.typeOf(val)); + try writer.print("&@as({}, ", .{ty.fmt(zcu)}); + try print(.{ + .ty = ty, + .val = Value.fromInterned(val), + }, writer, level - 1, zcu, opt_sema); + try writer.writeAll(")"); + }, + .eu_payload => |base| { + try printPtr(base, writer, true, true, leading_parens, level, zcu, opt_sema); + try writer.writeAll(".?"); + }, + .opt_payload => |base| { + try writer.writeAll("("); + try printPtr(base, writer, true, true, leading_parens + 1, level, zcu, opt_sema); + try writer.writeAll(" catch unreachable"); + }, + .elem => |elem| { + try printPtr(elem.base, writer, true, true, leading_parens, level, zcu, opt_sema); + try writer.print("[{d}]", .{elem.index}); + }, + .field => |field| { + try printPtr(field.base, writer, true, true, leading_parens, level, zcu, opt_sema); + const base_ty = Type.fromInterned(ip.typeOf(field.base)).childType(zcu); + switch (base_ty.zigTypeTag(zcu)) { + .Struct => if (base_ty.isTuple(zcu)) { + try writer.print("[{d}]", .{field.index}); + } else { + const field_name = base_ty.structFieldName(@intCast(field.index), zcu).unwrap().?; + try writer.print(".{i}", .{field_name.fmt(ip)}); + }, + .Union => { + const tag_ty = base_ty.unionTagTypeHypothetical(zcu); + const field_name = tag_ty.enumFieldName(@intCast(field.index), zcu); + try writer.print(".{i}", .{field_name.fmt(ip)}); + }, + .Pointer => switch (field.index) { + Value.slice_ptr_index => try writer.writeAll(".ptr"), + Value.slice_len_index => try writer.writeAll(".len"), + else => unreachable, + }, + else => unreachable, + } + }, } } diff --git a/src/Value.zig b/src/Value.zig index 040961fa385a..290f38d1178e 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -305,16 +305,16 @@ pub fn toBool(val: Value) bool { }; } -fn isDeclRef(val: Value, mod: *Module) bool { +fn ptrHasIntAddr(val: Value, mod: *Module) bool { var check = val; while (true) switch (mod.intern_pool.indexToKey(check.toIntern())) { .ptr => |ptr| switch (ptr.addr) { - .decl, .comptime_alloc, .comptime_field, .anon_decl => return true, + .decl, .comptime_alloc, .comptime_field, .anon_decl => return false, + .int => return true, .eu_payload, .opt_payload => |base| check = Value.fromInterned(base), .elem, .field => |base_index| check = Value.fromInterned(base_index.base), - .int => return false, }, - else => return false, + else => unreachable, }; } @@ -439,7 +439,7 @@ pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) error{ }, .Pointer => { if (ty.isSlice(mod)) return error.IllDefinedMemoryLayout; - if (val.isDeclRef(mod)) return error.ReinterpretDeclRef; + if (!val.ptrHasIntAddr(mod)) return error.ReinterpretDeclRef; return val.writeToMemory(Type.usize, mod, buffer); }, .Optional => { @@ -566,7 +566,7 @@ pub fn writeToPackedMemory( }, .Pointer => { assert(!ty.isSlice(mod)); // No well defined layout. - if (val.isDeclRef(mod)) return error.ReinterpretDeclRef; + if (!val.ptrHasIntAddr(mod)) return error.ReinterpretDeclRef; return val.writeToPackedMemory(Type.usize, mod, buffer, bit_offset); }, .Optional => { @@ -1261,62 +1261,23 @@ pub fn slicePtr(val: Value, mod: *Module) Value { return Value.fromInterned(mod.intern_pool.slicePtr(val.toIntern())); } -pub fn sliceLen(val: Value, mod: *Module) u64 { - const ip = &mod.intern_pool; - return switch (ip.indexToKey(val.toIntern())) { - .ptr => |ptr| switch (ip.indexToKey(switch (ptr.addr) { - .decl => |decl| mod.declPtr(decl).typeOf(mod).toIntern(), - .comptime_alloc => @panic("TODO"), - .anon_decl => |anon_decl| ip.typeOf(anon_decl.val), - .comptime_field => |comptime_field| ip.typeOf(comptime_field), - else => unreachable, - })) { - .array_type => |array_type| array_type.len, - else => 1, - }, - .slice => |slice| Value.fromInterned(slice.len).toUnsignedInt(mod), - else => unreachable, - }; -} - -/// Asserts the value is a single-item pointer to an array, or an array, -/// or an unknown-length pointer, and returns the element value at the index. -pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value { - return (try val.maybeElemValue(mod, index)).?; -} - -/// Like `elemValue`, but returns `null` instead of asserting on failure. -pub fn maybeElemValue(val: Value, mod: *Module, index: usize) Allocator.Error!?Value { - return val.maybeElemValueFull(null, mod, index); +/// Gets the `len` field of a slice value as a `u64`. +/// Resolves the length using the provided `Sema` if necessary. +pub fn sliceLen(val: Value, sema: *Sema) !u64 { + return Value.fromInterned(sema.mod.intern_pool.sliceLen(val.toIntern())).toUnsignedIntAdvanced(sema); } -pub fn maybeElemValueFull(val: Value, sema: ?*Sema, mod: *Module, index: usize) Allocator.Error!?Value { - return switch (mod.intern_pool.indexToKey(val.toIntern())) { - .undef => |ty| Value.fromInterned((try mod.intern(.{ - .undef = Type.fromInterned(ty).elemType2(mod).toIntern(), - }))), - .slice => |slice| return Value.fromInterned(slice.ptr).maybeElemValueFull(sema, mod, index), - .ptr => |ptr| switch (ptr.addr) { - .decl => |decl| mod.declPtr(decl).val.maybeElemValueFull(sema, mod, index), - .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).maybeElemValueFull(sema, mod, index), - .comptime_alloc => |idx| if (sema) |s| Value.fromInterned( - try s.getComptimeAlloc(idx).val.intern(mod, s.arena), - ).maybeElemValueFull(sema, mod, index) else null, - .int, .eu_payload => null, - .opt_payload => |base| Value.fromInterned(base).maybeElemValueFull(sema, mod, index), - .comptime_field => |field_val| Value.fromInterned(field_val).maybeElemValueFull(sema, mod, index), - .elem => |elem| Value.fromInterned(elem.base).maybeElemValueFull(sema, mod, index + @as(usize, @intCast(elem.index))), - .field => |field| if (Value.fromInterned(field.base).pointerDecl(mod)) |decl_index| { - const base_decl = mod.declPtr(decl_index); - const field_val = try base_decl.val.fieldValue(mod, @as(usize, @intCast(field.index))); - return field_val.maybeElemValueFull(sema, mod, index); - } else null, - }, - .opt => |opt| Value.fromInterned(opt.val).maybeElemValueFull(sema, mod, index), +/// Asserts the value is an aggregate, and returns the element value at the given index. +pub fn elemValue(val: Value, zcu: *Zcu, index: usize) Allocator.Error!Value { + const ip = &zcu.intern_pool; + switch (zcu.intern_pool.indexToKey(val.toIntern())) { + .undef => |ty| { + return Value.fromInterned(try zcu.intern(.{ .undef = Type.fromInterned(ty).childType(zcu).toIntern() })); + }, .aggregate => |aggregate| { - const len = mod.intern_pool.aggregateTypeLen(aggregate.ty); + const len = ip.aggregateTypeLen(aggregate.ty); if (index < len) return Value.fromInterned(switch (aggregate.storage) { - .bytes => |bytes| try mod.intern(.{ .int = .{ + .bytes => |bytes| try zcu.intern(.{ .int = .{ .ty = .u8_type, .storage = .{ .u64 = bytes[index] }, } }), @@ -1324,10 +1285,10 @@ pub fn maybeElemValueFull(val: Value, sema: ?*Sema, mod: *Module, index: usize) .repeated_elem => |elem| elem, }); assert(index == len); - return Value.fromInterned(mod.intern_pool.indexToKey(aggregate.ty).array_type.sentinel); + return Type.fromInterned(aggregate.ty).sentinel(zcu).?; }, - else => null, - }; + else => unreachable, + } } pub fn isLazyAlign(val: Value, mod: *Module) bool { @@ -1359,39 +1320,26 @@ pub fn sliceArray( ) error{OutOfMemory}!Value { // TODO: write something like getCoercedInts to avoid needing to dupe const mod = sema.mod; - return switch (mod.intern_pool.indexToKey(val.toIntern())) { - .ptr => |ptr| switch (ptr.addr) { - .decl => |decl| try mod.declPtr(decl).val.sliceArray(sema, start, end), - .comptime_alloc => |idx| try Value.fromInterned( - try sema.getComptimeAlloc(idx).val.intern(mod, sema.arena), - ).sliceArray(sema, start, end), - .comptime_field => |comptime_field| Value.fromInterned(comptime_field) - .sliceArray(sema, start, end), - .elem => |elem| Value.fromInterned(elem.base) - .sliceArray(sema, start + @as(usize, @intCast(elem.index)), end + @as(usize, @intCast(elem.index))), + const aggregate = mod.intern_pool.indexToKey(val.toIntern()).aggregate; + return Value.fromInterned(try mod.intern(.{ .aggregate = .{ + .ty = switch (mod.intern_pool.indexToKey(mod.intern_pool.typeOf(val.toIntern()))) { + .array_type => |array_type| try mod.arrayType(.{ + .len = @as(u32, @intCast(end - start)), + .child = array_type.child, + .sentinel = if (end == array_type.len) array_type.sentinel else .none, + }), + .vector_type => |vector_type| try mod.vectorType(.{ + .len = @as(u32, @intCast(end - start)), + .child = vector_type.child, + }), else => unreachable, + }.toIntern(), + .storage = switch (aggregate.storage) { + .bytes => .{ .bytes = try sema.arena.dupe(u8, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.bytes[start..end]) }, + .elems => .{ .elems = try sema.arena.dupe(InternPool.Index, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.elems[start..end]) }, + .repeated_elem => |elem| .{ .repeated_elem = elem }, }, - .aggregate => |aggregate| Value.fromInterned((try mod.intern(.{ .aggregate = .{ - .ty = switch (mod.intern_pool.indexToKey(mod.intern_pool.typeOf(val.toIntern()))) { - .array_type => |array_type| try mod.arrayType(.{ - .len = @as(u32, @intCast(end - start)), - .child = array_type.child, - .sentinel = if (end == array_type.len) array_type.sentinel else .none, - }), - .vector_type => |vector_type| try mod.vectorType(.{ - .len = @as(u32, @intCast(end - start)), - .child = vector_type.child, - }), - else => unreachable, - }.toIntern(), - .storage = switch (aggregate.storage) { - .bytes => .{ .bytes = try sema.arena.dupe(u8, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.bytes[start..end]) }, - .elems => .{ .elems = try sema.arena.dupe(InternPool.Index, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.elems[start..end]) }, - .repeated_elem => |elem| .{ .repeated_elem = elem }, - }, - } }))), - else => unreachable, - }; + } })); } pub fn fieldValue(val: Value, mod: *Module, index: usize) !Value { @@ -3586,6 +3534,10 @@ pub fn isGenericPoison(val: Value) bool { return val.toIntern() == .generic_poison; } +pub fn typeOf(val: Value, zcu: *const Zcu) Type { + return Type.fromInterned(zcu.intern_pool.typeOf(val.toIntern())); +} + /// For an integer (comptime or fixed-width) `val`, returns the comptime-known bounds of the value. /// If `val` is not undef, the bounds are both `val`. /// If `val` is undef and has a fixed-width type, the bounds are the bounds of the type. diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index e76416ddb0fe..c9abaf9c8bbc 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -693,31 +693,6 @@ test "string concatenation" { try expect(b[len] == 0); } -fn manyptrConcat(comptime s: [*:0]const u8) [*:0]const u8 { - return "very " ++ s; -} - -test "comptime manyptr concatenation" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - - const s = "epic"; - const actual = manyptrConcat(s); - const expected = "very epic"; - - const len = mem.len(actual); - const len_with_null = len + 1; - { - var i: u32 = 0; - while (i < len_with_null) : (i += 1) { - try expect(actual[i] == expected[i]); - } - } - try expect(actual[len] == 0); - try expect(expected[len] == 0); -} - test "result location is optional inside error union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO From 26a94e8481385619ae049143dd67e551f333fa3f Mon Sep 17 00:00:00 2001 From: mlugg Date: Tue, 26 Mar 2024 04:06:39 +0000 Subject: [PATCH 05/14] Zcu: eliminate `Decl.alive` field Legacy anon decls now have three uses: * Type owner decls * Function owner decls * `@export` and `@extern` Therefore, there are no longer any cases where we wish to explicitly omit legacy anon decls from the binary. This means we can remove the concept of an "alive" vs "dead" `Decl`, which also allows us to remove the separate `anon_work_queue` in `Compilation`. --- src/Compilation.zig | 19 +---------- src/InternPool.zig | 1 - src/Module.zig | 64 +------------------------------------ src/Sema.zig | 2 -- src/arch/wasm/CodeGen.zig | 2 -- src/arch/x86_64/CodeGen.zig | 2 -- src/codegen.zig | 4 --- src/codegen/c.zig | 1 - src/codegen/llvm.zig | 7 ---- src/codegen/spirv.zig | 1 - 10 files changed, 2 insertions(+), 101 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index b95a50cc5910..5bbca51ede99 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -102,7 +102,6 @@ link_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{}, lld_errors: std.ArrayListUnmanaged(LldError) = .{}, work_queue: std.fifo.LinearFifo(Job, .Dynamic), -anon_work_queue: std.fifo.LinearFifo(Job, .Dynamic), /// These jobs are to invoke the Clang compiler to create an object file, which /// gets linked with the Compilation. @@ -1417,7 +1416,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil .emit_llvm_ir = options.emit_llvm_ir, .emit_llvm_bc = options.emit_llvm_bc, .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa), - .anon_work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa), .c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa), .win32_resource_work_queue = if (build_options.only_core_functionality) {} else std.fifo.LinearFifo(*Win32Resource, .Dynamic).init(gpa), .astgen_work_queue = std.fifo.LinearFifo(*Module.File, .Dynamic).init(gpa), @@ -1840,7 +1838,6 @@ pub fn destroy(comp: *Compilation) void { if (comp.module) |zcu| zcu.deinit(); comp.cache_use.deinit(); comp.work_queue.deinit(); - comp.anon_work_queue.deinit(); comp.c_object_work_queue.deinit(); if (!build_options.only_core_functionality) { comp.win32_resource_work_queue.deinit(); @@ -3354,18 +3351,11 @@ pub fn performAllTheWork( mod.sema_prog_node = undefined; }; - // In this main loop we give priority to non-anonymous Decls in the work queue, so - // that they can establish references to anonymous Decls, setting alive=true in the - // backend, preventing anonymous Decls from being prematurely destroyed. while (true) { if (comp.work_queue.readItem()) |work_item| { try processOneJob(comp, work_item, main_progress_node); continue; } - if (comp.anon_work_queue.readItem()) |work_item| { - try processOneJob(comp, work_item, main_progress_node); - continue; - } if (comp.module) |zcu| { // If there's no work queued, check if there's anything outdated // which we need to work on, and queue it if so. @@ -3413,14 +3403,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v assert(decl.has_tv); - if (decl.alive) { - try module.linkerUpdateDecl(decl_index); - return; - } - - // Instead of sending this decl to the linker, we actually will delete it - // because we found out that it in fact was never referenced. - module.deleteUnusedDecl(decl_index); + try module.linkerUpdateDecl(decl_index); return; }, } diff --git a/src/InternPool.zig b/src/InternPool.zig index e4132e577ee7..63d29d376080 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -6740,7 +6740,6 @@ fn finishFuncInstance( .zir_decl_index = fn_owner_decl.zir_decl_index, .is_pub = fn_owner_decl.is_pub, .is_exported = fn_owner_decl.is_exported, - .alive = true, .kind = .anon, }); errdefer ip.destroyDecl(gpa, decl_index); diff --git a/src/Module.zig b/src/Module.zig index 4391472fa530..b3abefb57623 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -394,15 +394,6 @@ pub const Decl = struct { is_pub: bool, /// Whether the corresponding AST decl has a `export` keyword. is_exported: bool, - /// Flag used by garbage collection to mark and sweep. - /// Decls which correspond to an AST node always have this field set to `true`. - /// Anonymous Decls are initialized with this field set to `false` and then it - /// is the responsibility of machine code backends to mark it `true` whenever - /// a `decl_ref` Value is encountered that points to this Decl. - /// When the `codegen_decl` job is encountered in the main work queue, if the - /// Decl is marked alive, then it sends the Decl to the linker. Otherwise it - /// deletes the Decl on the spot. - alive: bool, /// If true `name` is already fully qualified. name_fully_qualified: bool = false, /// What kind of a declaration is this. @@ -3525,7 +3516,6 @@ fn semaFile(mod: *Module, file: *File) SemaError!void { new_decl.is_exported = false; new_decl.alignment = .none; new_decl.@"linksection" = .none; - new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive. new_decl.analysis = .in_progress; if (file.status != .success_zir) { @@ -4375,7 +4365,6 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void const decl = zcu.declPtr(decl_index); const was_exported = decl.is_exported; assert(decl.kind == kind); // ZIR tracking should preserve this - assert(decl.alive); decl.name = decl_name; decl.src_node = decl_node; decl.src_line = line; @@ -4392,7 +4381,6 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void new_decl.is_pub = declaration.flags.is_pub; new_decl.is_exported = declaration.flags.is_export; new_decl.zir_decl_index = tracked_inst.toOptional(); - new_decl.alive = true; // This Decl corresponds to an AST node and is therefore always alive. break :decl_index .{ false, new_decl_index }; }; @@ -4470,12 +4458,8 @@ pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void { /// Finalize the creation of an anon decl. pub fn finalizeAnonDecl(mod: *Module, decl_index: Decl.Index) Allocator.Error!void { - // The Decl starts off with alive=false and the codegen backend will set alive=true - // if the Decl is referenced by an instruction or another constant. Otherwise, - // the Decl will be garbage collected by the `codegen_decl` task instead of sent - // to the linker. if (mod.declPtr(decl_index).typeOf(mod).isFnOrHasRuntimeBits(mod)) { - try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = decl_index }); + try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index }); } } @@ -4815,7 +4799,6 @@ pub fn allocateNewDecl( .zir_decl_index = .none, .is_pub = false, .is_exported = false, - .alive = false, .kind = .anon, }); @@ -5582,51 +5565,6 @@ fn reportRetryableFileError( gop.value_ptr.* = err_msg; } -pub fn markReferencedDeclsAlive(mod: *Module, val: Value) Allocator.Error!void { - switch (mod.intern_pool.indexToKey(val.toIntern())) { - .variable => |variable| try mod.markDeclIndexAlive(variable.decl), - .extern_func => |extern_func| try mod.markDeclIndexAlive(extern_func.decl), - .func => |func| try mod.markDeclIndexAlive(func.owner_decl), - .error_union => |error_union| switch (error_union.val) { - .err_name => {}, - .payload => |payload| try mod.markReferencedDeclsAlive(Value.fromInterned(payload)), - }, - .slice => |slice| { - try mod.markReferencedDeclsAlive(Value.fromInterned(slice.ptr)); - try mod.markReferencedDeclsAlive(Value.fromInterned(slice.len)); - }, - .ptr => |ptr| switch (ptr.addr) { - .decl => |decl| try mod.markDeclIndexAlive(decl), - .anon_decl => {}, - .int, .comptime_field, .comptime_alloc => {}, - .eu_payload, .opt_payload => |parent| try mod.markReferencedDeclsAlive(Value.fromInterned(parent)), - .elem, .field => |base_index| try mod.markReferencedDeclsAlive(Value.fromInterned(base_index.base)), - }, - .opt => |opt| if (opt.val != .none) try mod.markReferencedDeclsAlive(Value.fromInterned(opt.val)), - .aggregate => |aggregate| for (aggregate.storage.values()) |elem| - try mod.markReferencedDeclsAlive(Value.fromInterned(elem)), - .un => |un| { - if (un.tag != .none) try mod.markReferencedDeclsAlive(Value.fromInterned(un.tag)); - try mod.markReferencedDeclsAlive(Value.fromInterned(un.val)); - }, - else => {}, - } -} - -pub fn markDeclAlive(mod: *Module, decl: *Decl) Allocator.Error!void { - if (decl.alive) return; - decl.alive = true; - - // This is the first time we are marking this Decl alive. We must - // therefore recurse into its value and mark any Decl it references - // as also alive, so that any Decl referenced does not get garbage collected. - try mod.markReferencedDeclsAlive(decl.val); -} - -fn markDeclIndexAlive(mod: *Module, decl_index: Decl.Index) Allocator.Error!void { - return mod.markDeclAlive(mod.declPtr(decl_index)); -} - pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u8) !void { const gop = try mod.global_assembly.getOrPut(mod.gpa, decl_index); if (gop.found_existing) { diff --git a/src/Sema.zig b/src/Sema.zig index c0b78c3e1def..8dfd0248f518 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -6445,8 +6445,6 @@ pub fn analyzeExport( return sema.fail(block, src, "export target cannot be extern", .{}); } - // This decl is alive no matter what, since it's being exported - try mod.markDeclAlive(exported_decl); try sema.maybeQueueFuncBodyAnalysis(exported_decl_index); try addExport(mod, .{ diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 11c95e318a47..be7f4ab66a45 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -3121,7 +3121,6 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: InternPool.DeclIndex, offset: u32) InnerError!WValue { const mod = func.bin_file.base.comp.module.?; const decl = mod.declPtr(decl_index); - try mod.markDeclAlive(decl); const ptr_ty = try mod.singleMutPtrType(decl.typeOf(mod)); return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset); } @@ -3178,7 +3177,6 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: InternPool.Decl return WValue{ .imm32 = 0xaaaaaaaa }; } - try mod.markDeclAlive(decl); const atom_index = try func.bin_file.getOrCreateAtomForDecl(decl_index); const atom = func.bin_file.getAtom(atom_index); diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 8fe19d4e2107..c5b815b4298f 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -12263,7 +12263,6 @@ fn genCall(self: *Self, info: union(enum) { }, }) { .func => |func| { - try mod.markDeclAlive(mod.declPtr(func.owner_decl)); if (self.bin_file.cast(link.File.Elf)) |elf_file| { const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl); const sym = elf_file.symbol(sym_index); @@ -12323,7 +12322,6 @@ fn genCall(self: *Self, info: union(enum) { }, .extern_func => |extern_func| { const owner_decl = mod.declPtr(extern_func.decl); - try mod.markDeclAlive(owner_decl); const lib_name = mod.intern_pool.stringToSliceUnwrap(extern_func.lib_name); const decl_name = mod.intern_pool.stringToSlice(owner_decl.name); try self.genExternSymbolRef(.call, lib_name, decl_name); diff --git a/src/codegen.zig b/src/codegen.zig index 818284a8f06c..48a7f840b2e7 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -835,8 +835,6 @@ fn lowerDeclRef( return Result.ok; } - try zcu.markDeclAlive(decl); - const vaddr = try lf.getDeclVAddr(decl_index, .{ .parent_atom_index = reloc_info.parent_atom_index, .offset = code.items.len, @@ -958,8 +956,6 @@ fn genDeclRef( } } - try zcu.markDeclAlive(decl); - const decl_namespace = zcu.namespacePtr(decl.src_namespace); const single_threaded = decl_namespace.file_scope.mod.single_threaded; const is_threadlocal = tv.val.isPtrToThreadLocal(zcu) and !single_threaded; diff --git a/src/codegen/c.zig b/src/codegen/c.zig index d1575feaba77..ed506cfdfe6c 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -2010,7 +2010,6 @@ pub const DeclGen = struct { fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: InternPool.DeclIndex, export_index: u32) !void { const mod = dg.module; const decl = mod.declPtr(decl_index); - try mod.markDeclAlive(decl); if (mod.decl_exports.get(decl_index)) |exports| { try writer.print("{ }", .{ diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 7bbe4e715a3e..421c767bd812 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3722,15 +3722,11 @@ pub const Object = struct { => unreachable, // non-runtime values .extern_func => |extern_func| { const fn_decl_index = extern_func.decl; - const fn_decl = mod.declPtr(fn_decl_index); - try mod.markDeclAlive(fn_decl); const function_index = try o.resolveLlvmFunction(fn_decl_index); return function_index.ptrConst(&o.builder).global.toConst(); }, .func => |func| { const fn_decl_index = func.owner_decl; - const fn_decl = mod.declPtr(fn_decl_index); - try mod.markDeclAlive(fn_decl); const function_index = try o.resolveLlvmFunction(fn_decl_index); return function_index.ptrConst(&o.builder).global.toConst(); }, @@ -4262,7 +4258,6 @@ pub const Object = struct { fn lowerParentPtrDecl(o: *Object, decl_index: InternPool.DeclIndex) Allocator.Error!Builder.Constant { const mod = o.module; const decl = mod.declPtr(decl_index); - try mod.markDeclAlive(decl); const ptr_ty = try mod.singleMutPtrType(decl.typeOf(mod)); return o.lowerDeclRefValue(ptr_ty, decl_index); } @@ -4455,8 +4450,6 @@ pub const Object = struct { if ((!is_fn_body and !decl_ty.hasRuntimeBits(mod)) or (is_fn_body and mod.typeToFunc(decl_ty).?.is_generic)) return o.lowerPtrToVoid(ty); - try mod.markDeclAlive(decl); - const llvm_global = if (is_fn_body) (try o.resolveLlvmFunction(decl_index)).ptrConst(&o.builder).global else diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 17b44806e20f..3e560b0918e8 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -255,7 +255,6 @@ pub const Object = struct { pub fn resolveDecl(self: *Object, mod: *Module, decl_index: InternPool.DeclIndex) !SpvModule.Decl.Index { const decl = mod.declPtr(decl_index); assert(decl.has_tv); // TODO: Do we need to handle a situation where this is false? - try mod.markDeclAlive(decl); const entry = try self.decl_link.getOrPut(self.gpa, decl_index); if (!entry.found_existing) { From 920f2c7794ba9b3eb3f3b78c60a0caf544f68927 Mon Sep 17 00:00:00 2001 From: mlugg Date: Tue, 26 Mar 2024 04:11:05 +0000 Subject: [PATCH 06/14] compiler: minor cleanups --- src/Module.zig | 2 +- src/Sema.zig | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index b3abefb57623..419205c30f53 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -477,7 +477,7 @@ pub const Decl = struct { pub fn typeOf(decl: Decl, zcu: *const Zcu) Type { assert(decl.has_tv); - return Type.fromInterned(zcu.intern_pool.typeOf(decl.val.toIntern())); + return decl.val.typeOf(zcu); } pub fn typedValue(decl: Decl, zcu: *const Zcu) error{AnalysisFail}!TypedValue { diff --git a/src/Sema.zig b/src/Sema.zig index 8dfd0248f518..436715d54d0c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -32431,7 +32431,7 @@ fn optRefValue(sema: *Sema, opt_val: ?Value) !Value { return Value.fromInterned((try mod.intern(.{ .opt = .{ .ty = (try mod.optionalType(ptr_anyopaque_ty.toIntern())).toIntern(), .val = if (opt_val) |val| (try mod.getCoerced( - Value.fromInterned((try sema.refValue(val.toIntern()))), + Value.fromInterned(try sema.refValue(val.toIntern())), ptr_anyopaque_ty, )).toIntern() else .none, } }))); @@ -36952,7 +36952,7 @@ fn semaStructFieldInits( }); }; - if (Value.fromInterned(default_val.toIntern()).canMutateComptimeVarState(mod)) { + if (default_val.canMutateComptimeVarState(mod)) { const init_src = mod.fieldSrcLoc(decl_index, .{ .index = field_i, .range = .value, @@ -39050,11 +39050,11 @@ fn sliceToIpString( ) CompileError!InternPool.NullTerminatedString { const zcu = sema.mod; const ip = &zcu.intern_pool; - const slice_ty = Type.fromInterned(ip.typeOf(slice_val.toIntern())); + const slice_ty = slice_val.typeOf(zcu); assert(slice_ty.isSlice(zcu)); assert(slice_ty.childType(zcu).toIntern() == .u8_type); const array_val = try sema.derefSliceAsArray(block, src, slice_val, reason); - const array_ty = Type.fromInterned(ip.typeOf(array_val.toIntern())); + const array_ty = array_val.typeOf(zcu); return array_val.toIpString(array_ty, zcu); } @@ -39084,7 +39084,7 @@ fn maybeDerefSliceAsArray( ) CompileError!?Value { const zcu = sema.mod; const ip = &zcu.intern_pool; - assert(Type.fromInterned(ip.typeOf(slice_val.toIntern())).isSlice(zcu)); + assert(slice_val.typeOf(zcu).isSlice(zcu)); const slice = switch (ip.indexToKey(slice_val.toIntern())) { .undef => return sema.failWithUseOfUndef(block, src), .slice => |slice| slice, From 0d8c7ae0078e970af39a3be760f25c51829b44f9 Mon Sep 17 00:00:00 2001 From: mlugg Date: Tue, 26 Mar 2024 04:19:50 +0000 Subject: [PATCH 07/14] Zcu.Decl: replace `typedValue` with `valueOrFail` Now that the legacy `Value` representation is eliminated, we can begin to phase out the redundant `TypedValue` type. --- src/Module.zig | 14 ++++---------- src/Sema.zig | 30 +++++++++++++----------------- src/codegen/llvm.zig | 2 +- 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 419205c30f53..6f65cf8d2e53 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -480,17 +480,11 @@ pub const Decl = struct { return decl.val.typeOf(zcu); } - pub fn typedValue(decl: Decl, zcu: *const Zcu) error{AnalysisFail}!TypedValue { + /// Small wrapper for Sema to use over direct access to the `val` field. + /// If the value is not populated, instead returns `error.AnalysisFail`. + pub fn valueOrFail(decl: Decl) error{AnalysisFail}!Value { if (!decl.has_tv) return error.AnalysisFail; - return .{ - .ty = decl.typeOf(zcu), - .val = decl.val, - }; - } - - pub fn isFunction(decl: Decl, zcu: *const Zcu) !bool { - const tv = try decl.typedValue(zcu); - return tv.ty.zigTypeTag(zcu) == .Fn; + return decl.val; } /// If the Decl owns its value and it is a struct, return it, diff --git a/src/Sema.zig b/src/Sema.zig index 436715d54d0c..0ff162ed2a73 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -26660,13 +26660,12 @@ fn prepareSimplePanic(sema: *Sema, block: *Block) !void { // decl_index may be an alias; we must find the decl that actually // owns the function. try sema.ensureDeclAnalyzed(decl_index); - const tv = try mod.declPtr(decl_index).typedValue(mod); + const fn_val = try mod.declPtr(decl_index).valueOrFail(); try sema.declareDependency(.{ .decl_val = decl_index }); - assert(tv.ty.zigTypeTag(mod) == .Fn); - assert(try sema.fnHasRuntimeBits(tv.ty)); - const func_index = tv.val.toIntern(); - try mod.ensureFuncBodyAnalysisQueued(func_index); - mod.panic_func_index = func_index; + assert(fn_val.typeOf(mod).zigTypeTag(mod) == .Fn); + assert(try sema.fnHasRuntimeBits(fn_val.typeOf(mod))); + try mod.ensureFuncBodyAnalysisQueued(fn_val.toIntern()); + mod.panic_func_index = fn_val.toIntern(); } if (mod.null_stack_trace == .none) { @@ -32449,8 +32448,8 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn const mod = sema.mod; try sema.ensureDeclAnalyzed(decl_index); - const decl_tv = try mod.declPtr(decl_index).typedValue(mod); - const owner_decl = mod.declPtr(switch (mod.intern_pool.indexToKey(decl_tv.val.toIntern())) { + const decl_val = try mod.declPtr(decl_index).valueOrFail(); + const owner_decl = mod.declPtr(switch (mod.intern_pool.indexToKey(decl_val.toIntern())) { .variable => |variable| variable.decl, .extern_func => |extern_func| extern_func.decl, .func => |func| func.owner_decl, @@ -32459,10 +32458,10 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn // TODO: if this is a `decl_ref` of a non-variable decl, only depend on decl type try sema.declareDependency(.{ .decl_val = decl_index }); const ptr_ty = try sema.ptrType(.{ - .child = decl_tv.ty.toIntern(), + .child = decl_val.typeOf(mod).toIntern(), .flags = .{ .alignment = owner_decl.alignment, - .is_const = if (decl_tv.val.getVariable(mod)) |variable| variable.is_const else true, + .is_const = if (decl_val.getVariable(mod)) |variable| variable.is_const else true, .address_space = owner_decl.@"addrspace", }, }); @@ -32478,12 +32477,10 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn fn maybeQueueFuncBodyAnalysis(sema: *Sema, decl_index: InternPool.DeclIndex) !void { const mod = sema.mod; const decl = mod.declPtr(decl_index); - const tv = try decl.typedValue(mod); - if (tv.ty.zigTypeTag(mod) != .Fn) return; - if (!try sema.fnHasRuntimeBits(tv.ty)) return; - const func_index = tv.val.toIntern(); - if (!mod.intern_pool.isFuncBody(func_index)) return; // undef or extern function - try mod.ensureFuncBodyAnalysisQueued(func_index); + const decl_val = try decl.valueOrFail(); + if (!mod.intern_pool.isFuncBody(decl_val.toIntern())) return; + if (!try sema.fnHasRuntimeBits(decl_val.typeOf(mod))) return; + try mod.ensureFuncBodyAnalysisQueued(decl_val.toIntern()); } fn analyzeRef( @@ -39049,7 +39046,6 @@ fn sliceToIpString( reason: NeededComptimeReason, ) CompileError!InternPool.NullTerminatedString { const zcu = sema.mod; - const ip = &zcu.intern_pool; const slice_ty = slice_val.typeOf(zcu); assert(slice_ty.isSlice(zcu)); assert(slice_ty.childType(zcu).toIntern() == .u8_type); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 421c767bd812..f4d91c2ebba7 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1762,7 +1762,7 @@ pub const Object = struct { const decl_name = decl_name: { const decl_name = mod.intern_pool.stringToSlice(decl.name); - if (mod.getTarget().isWasm() and try decl.isFunction(mod)) { + if (mod.getTarget().isWasm() and decl.val.typeOf(mod).zigTypeTag(mod) == .Fn) { if (mod.intern_pool.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| { if (!std.mem.eql(u8, lib_name, "c")) { break :decl_name try self.builder.strtabStringFmt("{s}|{s}", .{ decl_name, lib_name }); From b8d114a29e341a0cbd4c22cf02cb1588b0154446 Mon Sep 17 00:00:00 2001 From: mlugg Date: Tue, 26 Mar 2024 04:39:01 +0000 Subject: [PATCH 08/14] Zcu: use `Value` instead of `TypedValue` when initializing legacy anon decls Also removes some unnecessary uses of legacy anon decls for constructing the array of test functions for the test runner. --- src/Module.zig | 74 ++++++++---------------- src/Sema.zig | 152 +++++++++++++++++++++++++++++++------------------ 2 files changed, 121 insertions(+), 105 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 6f65cf8d2e53..044c4fb45b5c 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -22,7 +22,6 @@ const Compilation = @import("Compilation.zig"); const Cache = std.Build.Cache; const Value = @import("Value.zig"); const Type = @import("type.zig").Type; -const TypedValue = @import("TypedValue.zig"); const Package = @import("Package.zig"); const link = @import("link.zig"); const Air = @import("Air.zig"); @@ -4827,40 +4826,18 @@ pub fn errorSetBits(mod: *Module) u16 { return std.math.log2_int_ceil(ErrorInt, mod.error_limit + 1); // +1 for no error } -pub fn createAnonymousDecl(mod: *Module, block: *Sema.Block, typed_value: TypedValue) !Decl.Index { - const src_decl = mod.declPtr(block.src_decl); - return mod.createAnonymousDeclFromDecl(src_decl, block.namespace, typed_value); -} - -pub fn createAnonymousDeclFromDecl( - mod: *Module, - src_decl: *Decl, - namespace: Namespace.Index, - tv: TypedValue, -) !Decl.Index { - const new_decl_index = try mod.allocateNewDecl(namespace, src_decl.src_node); - errdefer mod.destroyDecl(new_decl_index); - const name = try mod.intern_pool.getOrPutStringFmt(mod.gpa, "{}__anon_{d}", .{ - src_decl.name.fmt(&mod.intern_pool), @intFromEnum(new_decl_index), - }); - try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, tv, name); - return new_decl_index; -} - pub fn initNewAnonDecl( mod: *Module, new_decl_index: Decl.Index, src_line: u32, - typed_value: TypedValue, + val: Value, name: InternPool.NullTerminatedString, ) Allocator.Error!void { - assert(typed_value.ty.toIntern() == mod.intern_pool.typeOf(typed_value.val.toIntern())); - const new_decl = mod.declPtr(new_decl_index); new_decl.name = name; new_decl.src_line = src_line; - new_decl.val = typed_value.val; + new_decl.val = val; new_decl.alignment = .none; new_decl.@"linksection" = .none; new_decl.has_tv = true; @@ -5391,7 +5368,7 @@ pub fn populateTestFunctions( const decl = mod.declPtr(decl_index); const test_fn_ty = decl.typeOf(mod).slicePtrFieldType(mod).childType(mod); - const array_decl_index = d: { + const array_anon_decl: InternPool.Key.Ptr.Addr.AnonDecl = array: { // Add mod.test_functions to an array decl then make the test_functions // decl reference it as a slice. const test_fn_vals = try gpa.alloc(InternPool.Index, mod.test_functions.count()); @@ -5401,21 +5378,20 @@ pub fn populateTestFunctions( const test_decl = mod.declPtr(test_decl_index); const test_decl_name = try gpa.dupe(u8, ip.stringToSlice(try test_decl.fullyQualifiedName(mod))); defer gpa.free(test_decl_name); - const test_name_decl_index = n: { - const test_name_decl_ty = try mod.arrayType(.{ + const test_name_anon_decl: InternPool.Key.Ptr.Addr.AnonDecl = n: { + const test_name_ty = try mod.arrayType(.{ .len = test_decl_name.len, .child = .u8_type, }); - const test_name_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, .{ - .ty = test_name_decl_ty, - .val = Value.fromInterned((try mod.intern(.{ .aggregate = .{ - .ty = test_name_decl_ty.toIntern(), - .storage = .{ .bytes = test_decl_name }, - } }))), - }); - break :n test_name_decl_index; + const test_name_val = try mod.intern(.{ .aggregate = .{ + .ty = test_name_ty.toIntern(), + .storage = .{ .bytes = test_decl_name }, + } }); + break :n .{ + .orig_ty = (try mod.singleConstPtrType(test_name_ty)).toIntern(), + .val = test_name_val, + }; }; - try mod.linkerUpdateDecl(test_name_decl_index); const test_fn_fields = .{ // name @@ -5423,7 +5399,7 @@ pub fn populateTestFunctions( .ty = .slice_const_u8_type, .ptr = try mod.intern(.{ .ptr = .{ .ty = .manyptr_const_u8_type, - .addr = .{ .decl = test_name_decl_index }, + .addr = .{ .anon_decl = test_name_anon_decl }, } }), .len = try mod.intern(.{ .int = .{ .ty = .usize_type, @@ -5447,22 +5423,20 @@ pub fn populateTestFunctions( } }); } - const array_decl_ty = try mod.arrayType(.{ + const array_ty = try mod.arrayType(.{ .len = test_fn_vals.len, .child = test_fn_ty.toIntern(), .sentinel = .none, }); - const array_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, .{ - .ty = array_decl_ty, - .val = Value.fromInterned((try mod.intern(.{ .aggregate = .{ - .ty = array_decl_ty.toIntern(), - .storage = .{ .elems = test_fn_vals }, - } }))), - }); - - break :d array_decl_index; + const array_val = try mod.intern(.{ .aggregate = .{ + .ty = array_ty.toIntern(), + .storage = .{ .elems = test_fn_vals }, + } }); + break :array .{ + .orig_ty = (try mod.singleConstPtrType(array_ty)).toIntern(), + .val = array_val, + }; }; - try mod.linkerUpdateDecl(array_decl_index); { const new_ty = try mod.ptrType(.{ @@ -5477,7 +5451,7 @@ pub fn populateTestFunctions( .ty = new_ty.toIntern(), .ptr = try mod.intern(.{ .ptr = .{ .ty = new_ty.slicePtrFieldType(mod).toIntern(), - .addr = .{ .decl = array_decl_index }, + .addr = .{ .anon_decl = array_anon_decl }, } }), .len = (try mod.intValue(Type.usize, mod.test_functions.count())).toIntern(), } }); diff --git a/src/Sema.zig b/src/Sema.zig index 0ff162ed2a73..8c47a39f78e4 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2825,10 +2825,14 @@ fn zirStructDecl( }); errdefer wip_ty.cancel(ip); - const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ - .ty = Type.type, - .val = Value.fromInterned(wip_ty.index), - }, small.name_strategy, "struct", inst); + const new_decl_index = try sema.createAnonymousDeclTypeNamed( + block, + src, + Value.fromInterned(wip_ty.index), + small.name_strategy, + "struct", + inst, + ); mod.declPtr(new_decl_index).owns_tv = true; errdefer mod.abortAnonDecl(new_decl_index); @@ -2861,7 +2865,7 @@ fn createAnonymousDeclTypeNamed( sema: *Sema, block: *Block, src: LazySrcLoc, - typed_value: TypedValue, + val: Value, name_strategy: Zir.Inst.NameStrategy, anon_prefix: []const u8, inst: ?Zir.Inst.Index, @@ -2887,12 +2891,12 @@ fn createAnonymousDeclTypeNamed( const name = mod.intern_pool.getOrPutStringFmt(gpa, "{}__{s}_{d}", .{ src_decl.name.fmt(&mod.intern_pool), anon_prefix, @intFromEnum(new_decl_index), }) catch unreachable; - try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, typed_value, name); + try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name); return new_decl_index; }, .parent => { const name = mod.declPtr(block.src_decl).name; - try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, typed_value, name); + try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name); return new_decl_index; }, .func => { @@ -2915,7 +2919,7 @@ fn createAnonymousDeclTypeNamed( // function and the name doesn't matter since it will later // result in a compile error. const arg_val = sema.resolveConstValue(block, .unneeded, arg, undefined) catch - return sema.createAnonymousDeclTypeNamed(block, src, typed_value, .anon, anon_prefix, null); + return sema.createAnonymousDeclTypeNamed(block, src, val, .anon, anon_prefix, null); if (arg_i != 0) try writer.writeByte(','); try writer.print("{}", .{arg_val.fmtValue(sema.typeOf(arg), sema.mod)}); @@ -2928,7 +2932,7 @@ fn createAnonymousDeclTypeNamed( try writer.writeByte(')'); const name = try mod.intern_pool.getOrPutString(gpa, buf.items); - try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, typed_value, name); + try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name); return new_decl_index; }, .dbg_var => { @@ -2943,12 +2947,12 @@ fn createAnonymousDeclTypeNamed( src_decl.name.fmt(&mod.intern_pool), zir_data[i].str_op.getStr(sema.code), }); - try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, typed_value, name); + try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name); return new_decl_index; }, else => {}, }; - return sema.createAnonymousDeclTypeNamed(block, src, typed_value, .anon, anon_prefix, null); + return sema.createAnonymousDeclTypeNamed(block, src, val, .anon, anon_prefix, null); }, } } @@ -3048,10 +3052,14 @@ fn zirEnumDecl( errdefer if (!done) wip_ty.cancel(ip); - const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ - .ty = Type.type, - .val = Value.fromInterned(wip_ty.index), - }, small.name_strategy, "enum", inst); + const new_decl_index = try sema.createAnonymousDeclTypeNamed( + block, + src, + Value.fromInterned(wip_ty.index), + small.name_strategy, + "enum", + inst, + ); const new_decl = mod.declPtr(new_decl_index); new_decl.owns_tv = true; errdefer if (!done) mod.abortAnonDecl(new_decl_index); @@ -3315,10 +3323,14 @@ fn zirUnionDecl( }); errdefer wip_ty.cancel(ip); - const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ - .ty = Type.type, - .val = Value.fromInterned(wip_ty.index), - }, small.name_strategy, "union", inst); + const new_decl_index = try sema.createAnonymousDeclTypeNamed( + block, + src, + Value.fromInterned(wip_ty.index), + small.name_strategy, + "union", + inst, + ); mod.declPtr(new_decl_index).owns_tv = true; errdefer mod.abortAnonDecl(new_decl_index); @@ -3399,10 +3411,14 @@ fn zirOpaqueDecl( }; errdefer wip_ty.cancel(ip); - const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ - .ty = Type.type, - .val = Value.fromInterned(wip_ty.index), - }, small.name_strategy, "opaque", inst); + const new_decl_index = try sema.createAnonymousDeclTypeNamed( + block, + src, + Value.fromInterned(wip_ty.index), + small.name_strategy, + "opaque", + inst, + ); mod.declPtr(new_decl_index).owns_tv = true; errdefer mod.abortAnonDecl(new_decl_index); @@ -3462,10 +3478,14 @@ fn zirErrorSetDecl( const error_set_ty = try mod.errorSetFromUnsortedNames(names.keys()); - const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ - .ty = Type.type, - .val = error_set_ty.toValue(), - }, name_strategy, "error", inst); + const new_decl_index = try sema.createAnonymousDeclTypeNamed( + block, + src, + error_set_ty.toValue(), + name_strategy, + "error", + inst, + ); const new_decl = mod.declPtr(new_decl_index); new_decl.owns_tv = true; errdefer mod.abortAnonDecl(new_decl_index); @@ -21490,10 +21510,14 @@ fn zirReify( }; errdefer wip_ty.cancel(ip); - const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ - .ty = Type.type, - .val = Value.fromInterned(wip_ty.index), - }, name_strategy, "opaque", inst); + const new_decl_index = try sema.createAnonymousDeclTypeNamed( + block, + src, + Value.fromInterned(wip_ty.index), + name_strategy, + "opaque", + inst, + ); mod.declPtr(new_decl_index).owns_tv = true; errdefer mod.abortAnonDecl(new_decl_index); @@ -21686,10 +21710,14 @@ fn reifyEnum( return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{}); } - const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ - .ty = Type.type, - .val = Value.fromInterned(wip_ty.index), - }, name_strategy, "enum", inst); + const new_decl_index = try sema.createAnonymousDeclTypeNamed( + block, + src, + Value.fromInterned(wip_ty.index), + name_strategy, + "enum", + inst, + ); mod.declPtr(new_decl_index).owns_tv = true; errdefer mod.abortAnonDecl(new_decl_index); @@ -21829,10 +21857,14 @@ fn reifyUnion( }; errdefer wip_ty.cancel(ip); - const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ - .ty = Type.type, - .val = Value.fromInterned(wip_ty.index), - }, name_strategy, "union", inst); + const new_decl_index = try sema.createAnonymousDeclTypeNamed( + block, + src, + Value.fromInterned(wip_ty.index), + name_strategy, + "union", + inst, + ); mod.declPtr(new_decl_index).owns_tv = true; errdefer mod.abortAnonDecl(new_decl_index); @@ -22084,10 +22116,14 @@ fn reifyStruct( .auto => {}, }; - const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ - .ty = Type.type, - .val = Value.fromInterned(wip_ty.index), - }, name_strategy, "struct", inst); + const new_decl_index = try sema.createAnonymousDeclTypeNamed( + block, + src, + Value.fromInterned(wip_ty.index), + name_strategy, + "struct", + inst, + ); mod.declPtr(new_decl_index).owns_tv = true; errdefer mod.abortAnonDecl(new_decl_index); @@ -26139,9 +26175,10 @@ fn zirBuiltinExtern( const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node); errdefer mod.destroyDecl(new_decl_index); const new_decl = mod.declPtr(new_decl_index); - try mod.initNewAnonDecl(new_decl_index, sema.owner_decl.src_line, .{ - .ty = Type.fromInterned(ptr_info.child), - .val = Value.fromInterned( + try mod.initNewAnonDecl( + new_decl_index, + sema.owner_decl.src_line, + Value.fromInterned( if (Type.fromInterned(ptr_info.child).zigTypeTag(mod) == .Fn) try ip.getExternFunc(sema.gpa, .{ .ty = ptr_info.child, @@ -26160,7 +26197,8 @@ fn zirBuiltinExtern( .is_weak_linkage = options.linkage == .weak, } }), ), - }, options.name); + options.name, + ); new_decl.owns_tv = true; // Note that this will queue the anon decl for codegen, so that the backend can // correctly handle the extern, including duplicate detection. @@ -37381,10 +37419,12 @@ fn generateUnionTagTypeNumbered( errdefer mod.destroyDecl(new_decl_index); const fqn = try union_owner_decl.fullyQualifiedName(mod); const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)}); - try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{ - .ty = Type.noreturn, - .val = Value.@"unreachable", - }, name); + try mod.initNewAnonDecl( + new_decl_index, + src_decl.src_line, + Value.@"unreachable", + name, + ); errdefer mod.abortAnonDecl(new_decl_index); const new_decl = mod.declPtr(new_decl_index); @@ -37425,10 +37465,12 @@ fn generateUnionTagTypeSimple( const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node); errdefer mod.destroyDecl(new_decl_index); const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)}); - try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{ - .ty = Type.noreturn, - .val = Value.@"unreachable", - }, name); + try mod.initNewAnonDecl( + new_decl_index, + src_decl.src_line, + Value.@"unreachable", + name, + ); mod.declPtr(new_decl_index).name_fully_qualified = true; break :new_decl_index new_decl_index; }; From a61def10c66abc871f92c84d9cef85b6b7752cbf Mon Sep 17 00:00:00 2001 From: mlugg Date: Tue, 26 Mar 2024 05:38:32 +0000 Subject: [PATCH 09/14] compiler: eliminate most usages of TypedValue --- src/Module.zig | 31 ++-- src/Sema.zig | 29 ++-- src/TypedValue.zig | 40 +---- src/Value.zig | 6 +- src/arch/aarch64/CodeGen.zig | 10 +- src/arch/arm/CodeGen.zig | 10 +- src/arch/riscv64/CodeGen.zig | 10 +- src/arch/sparc64/CodeGen.zig | 11 +- src/arch/wasm/CodeGen.zig | 32 ++-- src/arch/x86_64/CodeGen.zig | 101 +++++------- src/codegen.zig | 288 +++++++++++++++-------------------- src/codegen/c.zig | 63 ++++---- src/codegen/llvm.zig | 29 ++-- src/link.zig | 6 +- src/link/C.zig | 6 +- src/link/Coff.zig | 18 +-- src/link/Elf.zig | 6 +- src/link/Elf/ZigObject.zig | 25 ++- src/link/MachO.zig | 6 +- src/link/MachO/ZigObject.zig | 21 +-- src/link/Plan9.zig | 15 +- src/link/Wasm.zig | 6 +- src/link/Wasm/ZigObject.zig | 24 ++- src/type.zig | 1 - 24 files changed, 307 insertions(+), 487 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 044c4fb45b5c..df39a2a869f9 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -3678,20 +3678,21 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { const address_space_src: LazySrcLoc = .{ .node_offset_var_decl_addrspace = 0 }; const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 }; const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 }; - const decl_tv = try sema.resolveFinalDeclValue(&block_scope, init_src, result_ref); + const decl_val = try sema.resolveFinalDeclValue(&block_scope, init_src, result_ref); + const decl_ty = decl_val.typeOf(mod); // Note this resolves the type of the Decl, not the value; if this Decl // is a struct, for example, this resolves `type` (which needs no resolution), // not the struct itself. - try sema.resolveTypeLayout(decl_tv.ty); + try sema.resolveTypeLayout(decl_ty); if (decl.kind == .@"usingnamespace") { - if (!decl_tv.ty.eql(Type.type, mod)) { + if (!decl_ty.eql(Type.type, mod)) { return sema.fail(&block_scope, ty_src, "expected type, found {}", .{ - decl_tv.ty.fmt(mod), + decl_ty.fmt(mod), }); } - const ty = decl_tv.val.toType(); + const ty = decl_val.toType(); if (ty.getNamespace(mod) == null) { return sema.fail(&block_scope, ty_src, "type {} has no namespace", .{ty.fmt(mod)}); } @@ -3713,10 +3714,10 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { var queue_linker_work = true; var is_func = false; var is_inline = false; - switch (decl_tv.val.toIntern()) { + switch (decl_val.toIntern()) { .generic_poison => unreachable, .unreachable_value => unreachable, - else => switch (ip.indexToKey(decl_tv.val.toIntern())) { + else => switch (ip.indexToKey(decl_val.toIntern())) { .variable => |variable| { decl.owns_tv = variable.decl == decl_index; queue_linker_work = decl.owns_tv; @@ -3731,7 +3732,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { .func => |func| { decl.owns_tv = func.owner_decl == decl_index; queue_linker_work = false; - is_inline = decl.owns_tv and decl_tv.ty.fnCallingConvention(mod) == .Inline; + is_inline = decl.owns_tv and decl_ty.fnCallingConvention(mod) == .Inline; is_func = decl.owns_tv; }, @@ -3739,7 +3740,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { }, } - decl.val = decl_tv.val; + decl.val = decl_val; // Function linksection, align, and addrspace were already set by Sema if (!is_func) { decl.alignment = blk: { @@ -3762,7 +3763,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { break :blk section.toOptional(); }; decl.@"addrspace" = blk: { - const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_tv.val.toIntern())) { + const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_val.toIntern())) { .variable => .variable, .extern_func, .func => .function, else => .constant, @@ -3784,10 +3785,10 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { decl.analysis = .complete; const result: SemaDeclResult = if (old_has_tv) .{ - .invalidate_decl_val = !decl_tv.ty.eql(old_ty, mod) or - !decl.val.eql(old_val, decl_tv.ty, mod) or + .invalidate_decl_val = !decl_ty.eql(old_ty, mod) or + !decl.val.eql(old_val, decl_ty, mod) or is_inline != old_is_inline, - .invalidate_decl_ref = !decl_tv.ty.eql(old_ty, mod) or + .invalidate_decl_ref = !decl_ty.eql(old_ty, mod) or decl.alignment != old_align or decl.@"linksection" != old_linksection or decl.@"addrspace" != old_addrspace or @@ -3797,11 +3798,11 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { .invalidate_decl_ref = true, }; - const has_runtime_bits = queue_linker_work and (is_func or try sema.typeHasRuntimeBits(decl_tv.ty)); + const has_runtime_bits = queue_linker_work and (is_func or try sema.typeHasRuntimeBits(decl_ty)); if (has_runtime_bits) { // Needed for codegen_decl which will call updateDecl and then the // codegen backend wants full access to the Decl Type. - try sema.resolveTypeFully(decl_tv.ty); + try sema.resolveTypeFully(decl_ty); try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index }); diff --git a/src/Sema.zig b/src/Sema.zig index 8c47a39f78e4..18f4e01dd248 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -175,7 +175,6 @@ const Sema = @This(); const Value = @import("Value.zig"); const MutableValue = @import("mutable_value.zig").MutableValue; const Type = @import("type.zig").Type; -const TypedValue = @import("TypedValue.zig"); const Air = @import("Air.zig"); const Zir = std.zig.Zir; const Module = @import("Module.zig"); @@ -1708,7 +1707,7 @@ fn analyzeBodyInner( .needed_comptime_reason = "condition in comptime branch must be comptime-known", .block_comptime_reason = block.comptime_reason, }); - const inline_body = if (cond.val.toBool()) then_body else else_body; + const inline_body = if (cond.toBool()) then_body else else_body; try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src); @@ -1728,7 +1727,7 @@ fn analyzeBodyInner( .needed_comptime_reason = "condition in comptime branch must be comptime-known", .block_comptime_reason = block.comptime_reason, }); - const inline_body = if (cond.val.toBool()) then_body else else_body; + const inline_body = if (cond.toBool()) then_body else else_body; try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src); const old_runtime_index = block.runtime_index; @@ -2179,13 +2178,9 @@ fn resolveInstConst( src: LazySrcLoc, zir_ref: Zir.Inst.Ref, reason: NeededComptimeReason, -) CompileError!TypedValue { +) CompileError!Value { const air_ref = try sema.resolveInst(zir_ref); - const val = try sema.resolveConstDefinedValue(block, src, air_ref, reason); - return .{ - .ty = sema.typeOf(air_ref), - .val = val, - }; + return sema.resolveConstDefinedValue(block, src, air_ref, reason); } /// Value Tag may be `undef` or `variable`. @@ -2194,7 +2189,7 @@ pub fn resolveFinalDeclValue( block: *Block, src: LazySrcLoc, air_ref: Air.Inst.Ref, -) CompileError!TypedValue { +) CompileError!Value { const val = try sema.resolveValueAllowVariables(air_ref) orelse { return sema.failWithNeededComptime(block, src, .{ .needed_comptime_reason = "global variable initializer must be comptime-known", @@ -2204,10 +2199,7 @@ pub fn resolveFinalDeclValue( if (val.canMutateComptimeVarState(sema.mod)) { return sema.fail(block, src, "global variable contains reference to comptime var", .{}); } - return .{ - .ty = sema.typeOf(air_ref), - .val = val, - }; + return val; } fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc, reason: NeededComptimeReason) CompileError { @@ -6414,7 +6406,7 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const options = try sema.resolveExportOptions(block, options_src, extra.options); if (options.linkage == .internal) return; - if (operand.val.getFunction(mod)) |function| { + if (operand.getFunction(mod)) |function| { const decl_index = function.owner_decl; return sema.analyzeExport(block, src, options, decl_index); } @@ -6424,7 +6416,7 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError .src = src, .owner_decl = sema.owner_decl_index, .src_decl = block.src_decl, - .exported = .{ .value = operand.val.toIntern() }, + .exported = .{ .value = operand.toIntern() }, .status = .in_progress, }); } @@ -25831,7 +25823,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A } else if (extra.data.bits.has_ret_ty_ref) blk: { const ret_ty_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); extra_index += 1; - const ret_ty_tv = sema.resolveInstConst(block, ret_src, ret_ty_ref, .{ + const ret_ty_val = sema.resolveInstConst(block, ret_src, ret_ty_ref, .{ .needed_comptime_reason = "return type must be comptime-known", }) catch |err| switch (err) { error.GenericPoison => { @@ -25839,8 +25831,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A }, else => |e| return e, }; - const ty = ret_ty_tv.val.toType(); - break :blk ty; + break :blk ret_ty_val.toType(); } else Type.void; const noalias_bits: u32 = if (extra.data.bits.has_any_noalias) blk: { diff --git a/src/TypedValue.zig b/src/TypedValue.zig index ceef4116a264..6947e4cad22a 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -1,3 +1,6 @@ +//! This type exists only for legacy purposes, and will be removed in the future. +//! It is a thin wrapper around a `Value` which also, redundantly, stores its `Type`. + const std = @import("std"); const Type = @import("type.zig").Type; const Value = @import("Value.zig"); @@ -12,42 +15,6 @@ const Target = std.Target; ty: Type, val: Value, -/// Memory management for TypedValue. The main purpose of this type -/// is to be small and have a deinit() function to free associated resources. -pub const Managed = struct { - /// If the tag value is less than Tag.no_payload_count, then no pointer - /// dereference is needed. - typed_value: TypedValue, - /// If this is `null` then there is no memory management needed. - arena: ?*std.heap.ArenaAllocator.State = null, - - pub fn deinit(self: *Managed, allocator: Allocator) void { - if (self.arena) |a| a.promote(allocator).deinit(); - self.* = undefined; - } -}; - -/// Assumes arena allocation. Does a recursive copy. -pub fn copy(self: TypedValue, arena: Allocator) error{OutOfMemory}!TypedValue { - return TypedValue{ - .ty = self.ty, - .val = try self.val.copy(arena), - }; -} - -pub fn eql(a: TypedValue, b: TypedValue, mod: *Module) bool { - if (a.ty.toIntern() != b.ty.toIntern()) return false; - return a.val.eql(b.val, a.ty, mod); -} - -pub fn hash(tv: TypedValue, hasher: *std.hash.Wyhash, mod: *Module) void { - return tv.val.hash(tv.ty, hasher, mod); -} - -pub fn intFromEnum(tv: TypedValue, mod: *Module) Allocator.Error!Value { - return tv.val.intFromEnum(tv.ty, mod); -} - const max_aggregate_items = 100; const max_string_len = 256; @@ -72,7 +39,6 @@ pub fn format( }; } -/// Prints the Value according to the Type, not according to the Value Tag. pub fn print( tv: TypedValue, writer: anytype, diff --git a/src/Value.zig b/src/Value.zig index 290f38d1178e..81b8583a84e4 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -249,12 +249,12 @@ pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64 .int => |int| Value.fromInterned(int).getUnsignedIntAdvanced(mod, opt_sema), .elem => |elem| { const base_addr = (try Value.fromInterned(elem.base).getUnsignedIntAdvanced(mod, opt_sema)) orelse return null; - const elem_ty = Type.fromInterned(mod.intern_pool.typeOf(elem.base)).elemType2(mod); + const elem_ty = Value.fromInterned(elem.base).typeOf(mod).elemType2(mod); return base_addr + elem.index * elem_ty.abiSize(mod); }, .field => |field| { const base_addr = (try Value.fromInterned(field.base).getUnsignedIntAdvanced(mod, opt_sema)) orelse return null; - const struct_ty = Type.fromInterned(mod.intern_pool.typeOf(field.base)).childType(mod); + const struct_ty = Value.fromInterned(field.base).typeOf(mod).childType(mod); if (opt_sema) |sema| try sema.resolveTypeLayout(struct_ty); return base_addr + struct_ty.structFieldOffset(@as(usize, @intCast(field.index)), mod); }, @@ -1390,7 +1390,7 @@ pub fn elemPtr( }; switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) { .ptr => |ptr| switch (ptr.addr) { - .elem => |elem| if (Type.fromInterned(mod.intern_pool.typeOf(elem.base)).elemType2(mod).eql(elem_ty, mod)) + .elem => |elem| if (Value.fromInterned(elem.base).typeOf(mod).elemType2(mod).eql(elem_ty, mod)) return Value.fromInterned((try mod.intern(.{ .ptr = .{ .ty = elem_ptr_ty.toIntern(), .addr = .{ .elem = .{ diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 9926f3ef7b9e..b9f8259c05dc 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -10,7 +10,6 @@ const Emit = @import("Emit.zig"); const Liveness = @import("../../Liveness.zig"); const Type = @import("../../type.zig").Type; const Value = @import("../../Value.zig"); -const TypedValue = @import("../../TypedValue.zig"); const link = @import("../../link.zig"); const Module = @import("../../Module.zig"); const InternPool = @import("../../InternPool.zig"); @@ -6143,10 +6142,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { if (!inst_ty.hasRuntimeBitsIgnoreComptime(mod) and !inst_ty.isError(mod)) return MCValue{ .none = {} }; - const inst_index = inst.toIndex() orelse return self.genTypedValue(.{ - .ty = inst_ty, - .val = (try self.air.value(inst, mod)).?, - }); + const inst_index = inst.toIndex() orelse return self.genTypedValue((try self.air.value(inst, mod)).?); return self.getResolvedInstValue(inst_index); } @@ -6163,11 +6159,11 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { } } -fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { +fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { const mcv: MCValue = switch (try codegen.genTypedValue( self.bin_file, self.src_loc, - arg_tv, + val, self.owner_decl, )) { .mcv => |mcv| switch (mcv) { diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index ab1b41a25e80..86d4e8f7fdd6 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -10,7 +10,6 @@ const Emit = @import("Emit.zig"); const Liveness = @import("../../Liveness.zig"); const Type = @import("../../type.zig").Type; const Value = @import("../../Value.zig"); -const TypedValue = @import("../../TypedValue.zig"); const link = @import("../../link.zig"); const Module = @import("../../Module.zig"); const InternPool = @import("../../InternPool.zig"); @@ -6097,10 +6096,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { if (!inst_ty.hasRuntimeBitsIgnoreComptime(mod) and !inst_ty.isError(mod)) return MCValue{ .none = {} }; - const inst_index = inst.toIndex() orelse return self.genTypedValue(.{ - .ty = inst_ty, - .val = (try self.air.value(inst, mod)).?, - }); + const inst_index = inst.toIndex() orelse return self.genTypedValue((try self.air.value(inst, mod)).?); return self.getResolvedInstValue(inst_index); } @@ -6117,12 +6113,12 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { } } -fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { +fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { const mod = self.bin_file.comp.module.?; const mcv: MCValue = switch (try codegen.genTypedValue( self.bin_file, self.src_loc, - arg_tv, + val, mod.funcOwnerDeclIndex(self.func_index), )) { .mcv => |mcv| switch (mcv) { diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index e7a872d616ab..5abe3afcfd2a 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -9,7 +9,6 @@ const Emit = @import("Emit.zig"); const Liveness = @import("../../Liveness.zig"); const Type = @import("../../type.zig").Type; const Value = @import("../../Value.zig"); -const TypedValue = @import("../../TypedValue.zig"); const link = @import("../../link.zig"); const Module = @import("../../Module.zig"); const InternPool = @import("../../InternPool.zig"); @@ -2552,10 +2551,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { if (!inst_ty.hasRuntimeBits(mod)) return MCValue{ .none = {} }; - const inst_index = inst.toIndex() orelse return self.genTypedValue(.{ - .ty = inst_ty, - .val = (try self.air.value(inst, mod)).?, - }); + const inst_index = inst.toIndex() orelse return self.genTypedValue((try self.air.value(inst, mod)).?); return self.getResolvedInstValue(inst_index); } @@ -2572,12 +2568,12 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { } } -fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { +fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { const mod = self.bin_file.comp.module.?; const mcv: MCValue = switch (try codegen.genTypedValue( self.bin_file, self.src_loc, - typed_value, + val, mod.funcOwnerDeclIndex(self.func_index), )) { .mcv => |mcv| switch (mcv) { diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index d3417fd6decb..19c18ec4a6b0 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -12,7 +12,7 @@ const builtin = @import("builtin"); const link = @import("../../link.zig"); const Module = @import("../../Module.zig"); const InternPool = @import("../../InternPool.zig"); -const TypedValue = @import("../../TypedValue.zig"); +const Value = @import("../../Value.zig"); const ErrorMsg = Module.ErrorMsg; const codegen = @import("../../codegen.zig"); const Air = @import("../../Air.zig"); @@ -4118,12 +4118,12 @@ fn genStoreASI(self: *Self, value_reg: Register, addr_reg: Register, off_reg: Re } } -fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { +fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { const mod = self.bin_file.comp.module.?; const mcv: MCValue = switch (try codegen.genTypedValue( self.bin_file, self.src_loc, - typed_value, + val, mod.funcOwnerDeclIndex(self.func_index), )) { .mcv => |mcv| switch (mcv) { @@ -4546,10 +4546,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { return self.getResolvedInstValue(inst); } - return self.genTypedValue(.{ - .ty = ty, - .val = (try self.air.value(ref, mod)).?, - }); + return self.genTypedValue((try self.air.value(ref, mod)).?); } fn ret(self: *Self, mcv: MCValue) !void { diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index be7f4ab66a45..6dc231672406 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -18,7 +18,6 @@ const Value = @import("../../Value.zig"); const Compilation = @import("../../Compilation.zig"); const LazySrcLoc = std.zig.LazySrcLoc; const link = @import("../../link.zig"); -const TypedValue = @import("../../TypedValue.zig"); const Air = @import("../../Air.zig"); const Liveness = @import("../../Liveness.zig"); const target_util = @import("../../target.zig"); @@ -805,7 +804,7 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue { // In the other cases, we will simply lower the constant to a value that fits // into a single local (such as a pointer, integer, bool, etc). const result = if (isByRef(ty, mod)) blk: { - const sym_index = try func.bin_file.lowerUnnamedConst(.{ .ty = ty, .val = val }, func.decl_index); + const sym_index = try func.bin_file.lowerUnnamedConst(val, func.decl_index); break :blk WValue{ .memory = sym_index }; } else try func.lowerConstant(val, ty); @@ -3119,10 +3118,7 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue } fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: InternPool.DeclIndex, offset: u32) InnerError!WValue { - const mod = func.bin_file.base.comp.module.?; - const decl = mod.declPtr(decl_index); - const ptr_ty = try mod.singleMutPtrType(decl.typeOf(mod)); - return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset); + return func.lowerDeclRefValue(ptr_val, decl_index, offset); } fn lowerAnonDeclRef( @@ -3157,7 +3153,7 @@ fn lowerAnonDeclRef( } else return WValue{ .memory_offset = .{ .pointer = target_sym_index, .offset = offset } }; } -fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: InternPool.DeclIndex, offset: u32) InnerError!WValue { +fn lowerDeclRefValue(func: *CodeGen, val: Value, decl_index: InternPool.DeclIndex, offset: u32) InnerError!WValue { const mod = func.bin_file.base.comp.module.?; const decl = mod.declPtr(decl_index); @@ -3165,11 +3161,11 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: InternPool.Decl // want to lower the actual decl, rather than the alias itself. if (decl.val.getFunction(mod)) |func_val| { if (func_val.owner_decl != decl_index) { - return func.lowerDeclRefValue(tv, func_val.owner_decl, offset); + return func.lowerDeclRefValue(val, func_val.owner_decl, offset); } } else if (decl.val.getExternFunc(mod)) |func_val| { if (func_val.decl != decl_index) { - return func.lowerDeclRefValue(tv, func_val.decl, offset); + return func.lowerDeclRefValue(val, func_val.decl, offset); } } const decl_ty = decl.typeOf(mod); @@ -3280,23 +3276,23 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue { }, .error_union => |error_union| { const err_int_ty = try mod.errorIntType(); - const err_tv: TypedValue = switch (error_union.val) { + const err_ty, const err_val = switch (error_union.val) { .err_name => |err_name| .{ - .ty = ty.errorUnionSet(mod), - .val = Value.fromInterned((try mod.intern(.{ .err = .{ + ty.errorUnionSet(mod), + Value.fromInterned((try mod.intern(.{ .err = .{ .ty = ty.errorUnionSet(mod).toIntern(), .name = err_name, } }))), }, .payload => .{ - .ty = err_int_ty, - .val = try mod.intValue(err_int_ty, 0), + err_int_ty, + try mod.intValue(err_int_ty, 0), }, }; const payload_type = ty.errorUnionPayload(mod); if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) { // We use the error type directly as the type. - return func.lowerConstant(err_tv.val, err_tv.ty); + return func.lowerConstant(err_val, err_ty); } return func.fail("Wasm TODO: lowerConstant error union with non-zero-bit payload type", .{}); @@ -3320,10 +3316,10 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue { .elem, .field => |base_index| ptr = ip.indexToKey(base_index.base).ptr, .comptime_field, .comptime_alloc => unreachable, }; - return .{ .memory = try func.bin_file.lowerUnnamedConst(.{ .ty = ty, .val = val }, owner_decl) }; + return .{ .memory = try func.bin_file.lowerUnnamedConst(val, owner_decl) }; }, .ptr => |ptr| switch (ptr.addr) { - .decl => |decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl, 0), + .decl => |decl| return func.lowerDeclRefValue(val, decl, 0), .int => |int| return func.lowerConstant(Value.fromInterned(int), Type.fromInterned(ip.typeOf(int))), .opt_payload, .elem, .field => return func.lowerParentPtr(val, 0), .anon_decl => |ad| return func.lowerAnonDeclRef(ad, 0), @@ -7285,7 +7281,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { .storage = .{ .bytes = tag_name }, } }); const tag_sym_index = try func.bin_file.lowerUnnamedConst( - .{ .ty = name_ty, .val = Value.fromInterned(name_val) }, + Value.fromInterned(name_val), enum_decl_index, ); diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index c5b815b4298f..680dce0b4868 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -32,7 +32,6 @@ const InternPool = @import("../../InternPool.zig"); const Alignment = InternPool.Alignment; const Target = std.Target; const Type = @import("../../type.zig").Type; -const TypedValue = @import("../../TypedValue.zig"); const Value = @import("../../Value.zig"); const Instruction = @import("encoder.zig").Instruction; @@ -2250,7 +2249,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { for (exitlude_jump_relocs, 0..) |*exitlude_jump_reloc, tag_index| { const tag_name_len = ip.stringToSlice(tag_names.get(ip)[tag_index]).len; const tag_val = try mod.enumValueFieldIndex(enum_ty, @intCast(tag_index)); - const tag_mcv = try self.genTypedValue(.{ .ty = enum_ty, .val = tag_val }); + const tag_mcv = try self.genTypedValue(tag_val); try self.genBinOpMir(.{ ._, .cmp }, enum_ty, enum_mcv, tag_mcv); const skip_reloc = try self.asmJccReloc(.ne, undefined); @@ -3323,7 +3322,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { .storage = .{ .repeated_elem = mask_val.ip_index }, } }); - const splat_mcv = try self.genTypedValue(.{ .ty = splat_ty, .val = Value.fromInterned(splat_val) }); + const splat_mcv = try self.genTypedValue(Value.fromInterned(splat_val)); const splat_addr_mcv: MCValue = switch (splat_mcv) { .memory, .indirect, .load_frame => splat_mcv.address(), else => .{ .register = try self.copyToTmpRegister(Type.usize, splat_mcv.address()) }, @@ -4992,17 +4991,14 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { defer self.register_manager.unlockReg(shift_lock); const mask_ty = try mod.vectorType(.{ .len = 16, .child = .u8_type }); - const mask_mcv = try self.genTypedValue(.{ - .ty = mask_ty, - .val = Value.fromInterned((try mod.intern(.{ .aggregate = .{ - .ty = mask_ty.toIntern(), - .storage = .{ .elems = &([1]InternPool.Index{ - (try rhs_ty.childType(mod).maxIntScalar(mod, Type.u8)).toIntern(), - } ++ [1]InternPool.Index{ - (try mod.intValue(Type.u8, 0)).toIntern(), - } ** 15) }, - } }))), - }); + const mask_mcv = try self.genTypedValue(Value.fromInterned(try mod.intern(.{ .aggregate = .{ + .ty = mask_ty.toIntern(), + .storage = .{ .elems = &([1]InternPool.Index{ + (try rhs_ty.childType(mod).maxIntScalar(mod, Type.u8)).toIntern(), + } ++ [1]InternPool.Index{ + (try mod.intValue(Type.u8, 0)).toIntern(), + } ** 15) }, + } }))); const mask_addr_reg = try self.copyToTmpRegister(Type.usize, mask_mcv.address()); const mask_addr_lock = self.register_manager.lockRegAssumeUnused(mask_addr_reg); @@ -6860,11 +6856,11 @@ fn floatSign(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type) .child = (try mod.intType(.signed, scalar_bits)).ip_index, }); - const sign_mcv = try self.genTypedValue(.{ .ty = vec_ty, .val = switch (tag) { + const sign_mcv = try self.genTypedValue(switch (tag) { .neg => try vec_ty.minInt(mod, vec_ty), .abs => try vec_ty.maxInt(mod, vec_ty), else => unreachable, - } }); + }); const sign_mem: Memory = if (sign_mcv.isMemory()) try sign_mcv.mem(self, Memory.Size.fromSize(abi_size)) else @@ -11130,10 +11126,7 @@ fn genBinOp( .cmp_neq, => { const unsigned_ty = try lhs_ty.toUnsigned(mod); - const not_mcv = try self.genTypedValue(.{ - .ty = lhs_ty, - .val = try unsigned_ty.maxInt(mod, unsigned_ty), - }); + const not_mcv = try self.genTypedValue(try unsigned_ty.maxInt(mod, unsigned_ty)); const not_mem: Memory = if (not_mcv.isMemory()) try not_mcv.mem(self, Memory.Size.fromSize(abi_size)) else @@ -14692,10 +14685,7 @@ fn genSetReg( ), else => unreachable, }, - .segment, .x87, .mmx, .sse => try self.genSetReg(dst_reg, ty, try self.genTypedValue(.{ - .ty = ty, - .val = try mod.undefValue(ty), - }), opts), + .segment, .x87, .mmx, .sse => try self.genSetReg(dst_reg, ty, try self.genTypedValue(try mod.undefValue(ty)), opts), }, .eflags => |cc| try self.asmSetccRegister(cc, dst_reg.to8()), .immediate => |imm| { @@ -16893,13 +16883,10 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void { .ty = mask_elem_ty.toIntern(), .storage = .{ .u64 = bit / elem_bits }, } }); - const mask_mcv = try self.genTypedValue(.{ - .ty = mask_ty, - .val = Value.fromInterned(try mod.intern(.{ .aggregate = .{ - .ty = mask_ty.toIntern(), - .storage = .{ .elems = mask_elems[0..vec_len] }, - } })), - }); + const mask_mcv = try self.genTypedValue(Value.fromInterned(try mod.intern(.{ .aggregate = .{ + .ty = mask_ty.toIntern(), + .storage = .{ .elems = mask_elems[0..vec_len] }, + } }))); const mask_mem: Memory = .{ .base = .{ .reg = try self.copyToTmpRegister(Type.usize, mask_mcv.address()) }, .mod = .{ .rm = .{ .size = self.memSize(ty) } }, @@ -16921,13 +16908,10 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void { .ty = mask_elem_ty.toIntern(), .storage = .{ .u64 = @as(u32, 1) << @intCast(bit & (elem_bits - 1)) }, } }); - const mask_mcv = try self.genTypedValue(.{ - .ty = mask_ty, - .val = Value.fromInterned(try mod.intern(.{ .aggregate = .{ - .ty = mask_ty.toIntern(), - .storage = .{ .elems = mask_elems[0..vec_len] }, - } })), - }); + const mask_mcv = try self.genTypedValue(Value.fromInterned(try mod.intern(.{ .aggregate = .{ + .ty = mask_ty.toIntern(), + .storage = .{ .elems = mask_elems[0..vec_len] }, + } }))); const mask_mem: Memory = .{ .base = .{ .reg = try self.copyToTmpRegister(Type.usize, mask_mcv.address()) }, .mod = .{ .rm = .{ .size = self.memSize(ty) } }, @@ -17658,13 +17642,10 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { else try select_mask_elem_ty.minIntScalar(mod, select_mask_elem_ty)).toIntern(); } - const select_mask_mcv = try self.genTypedValue(.{ - .ty = select_mask_ty, - .val = Value.fromInterned(try mod.intern(.{ .aggregate = .{ - .ty = select_mask_ty.toIntern(), - .storage = .{ .elems = select_mask_elems[0..mask_elems.len] }, - } })), - }); + const select_mask_mcv = try self.genTypedValue(Value.fromInterned(try mod.intern(.{ .aggregate = .{ + .ty = select_mask_ty.toIntern(), + .storage = .{ .elems = select_mask_elems[0..mask_elems.len] }, + } }))); if (self.hasFeature(.sse4_1)) { const mir_tag: Mir.Inst.FixedTag = .{ @@ -17809,13 +17790,10 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { } }); } const lhs_mask_ty = try mod.vectorType(.{ .len = max_abi_size, .child = .u8_type }); - const lhs_mask_mcv = try self.genTypedValue(.{ - .ty = lhs_mask_ty, - .val = Value.fromInterned(try mod.intern(.{ .aggregate = .{ - .ty = lhs_mask_ty.toIntern(), - .storage = .{ .elems = lhs_mask_elems[0..max_abi_size] }, - } })), - }); + const lhs_mask_mcv = try self.genTypedValue(Value.fromInterned(try mod.intern(.{ .aggregate = .{ + .ty = lhs_mask_ty.toIntern(), + .storage = .{ .elems = lhs_mask_elems[0..max_abi_size] }, + } }))); const lhs_mask_mem: Memory = .{ .base = .{ .reg = try self.copyToTmpRegister(Type.usize, lhs_mask_mcv.address()) }, .mod = .{ .rm = .{ .size = Memory.Size.fromSize(@max(max_abi_size, 16)) } }, @@ -17846,13 +17824,10 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { } }); } const rhs_mask_ty = try mod.vectorType(.{ .len = max_abi_size, .child = .u8_type }); - const rhs_mask_mcv = try self.genTypedValue(.{ - .ty = rhs_mask_ty, - .val = Value.fromInterned(try mod.intern(.{ .aggregate = .{ - .ty = rhs_mask_ty.toIntern(), - .storage = .{ .elems = rhs_mask_elems[0..max_abi_size] }, - } })), - }); + const rhs_mask_mcv = try self.genTypedValue(Value.fromInterned(try mod.intern(.{ .aggregate = .{ + .ty = rhs_mask_ty.toIntern(), + .storage = .{ .elems = rhs_mask_elems[0..max_abi_size] }, + } }))); const rhs_mask_mem: Memory = .{ .base = .{ .reg = try self.copyToTmpRegister(Type.usize, rhs_mask_mcv.address()) }, .mod = .{ .rm = .{ .size = Memory.Size.fromSize(@max(max_abi_size, 16)) } }, @@ -18138,7 +18113,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { .{ .frame = frame_index }, @intCast(elem_size * elements.len), elem_ty, - try self.genTypedValue(.{ .ty = elem_ty, .val = sentinel }), + try self.genTypedValue(sentinel), .{}, ); break :result .{ .load_frame = .{ .index = frame_index } }; @@ -18662,7 +18637,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { const ip_index = ref.toInterned().?; const gop = try self.const_tracking.getOrPut(self.gpa, ip_index); if (!gop.found_existing) gop.value_ptr.* = InstTracking.init(init: { - const const_mcv = try self.genTypedValue(.{ .ty = ty, .val = Value.fromInterned(ip_index) }); + const const_mcv = try self.genTypedValue(Value.fromInterned(ip_index)); switch (const_mcv) { .lea_tlv => |tlv_sym| switch (self.bin_file.tag) { .elf, .macho => { @@ -18727,9 +18702,9 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV return mcv; } -fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { +fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { const mod = self.bin_file.comp.module.?; - return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.owner.getDecl(mod))) { + return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, val, self.owner.getDecl(mod))) { .mcv => |mcv| switch (mcv) { .none => .none, .undef => .undef, diff --git a/src/codegen.zig b/src/codegen.zig index 48a7f840b2e7..049b10b3082d 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -19,7 +19,6 @@ const Liveness = @import("Liveness.zig"); const Module = @import("Module.zig"); const Target = std.Target; const Type = @import("type.zig").Type; -const TypedValue = @import("TypedValue.zig"); const Value = @import("Value.zig"); const Zir = std.zig.Zir; const Alignment = InternPool.Alignment; @@ -171,7 +170,7 @@ pub fn generateLazySymbol( pub fn generateSymbol( bin_file: *link.File, src_loc: Module.SrcLoc, - arg_tv: TypedValue, + val: Value, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, reloc_info: RelocInfo, @@ -181,23 +180,22 @@ pub fn generateSymbol( const mod = bin_file.comp.module.?; const ip = &mod.intern_pool; - const typed_value = arg_tv; + const ty = val.typeOf(mod); const target = mod.getTarget(); const endian = target.cpu.arch.endian(); - log.debug("generateSymbol: ty = {}, val = {}", .{ - typed_value.ty.fmt(mod), - typed_value.val.fmtValue(typed_value.ty, mod), + log.debug("generateSymbol: val = {}", .{ + val.fmtValue(ty, mod), }); - if (typed_value.val.isUndefDeep(mod)) { - const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; + if (val.isUndefDeep(mod)) { + const abi_size = math.cast(usize, ty.abiSize(mod)) orelse return error.Overflow; try code.appendNTimes(0xaa, abi_size); return .ok; } - switch (ip.indexToKey(typed_value.val.toIntern())) { + switch (ip.indexToKey(val.toIntern())) { .int_type, .ptr_type, .array_type, @@ -238,17 +236,17 @@ pub fn generateSymbol( .empty_enum_value, => unreachable, // non-runtime values .int => { - const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; + const abi_size = math.cast(usize, ty.abiSize(mod)) orelse return error.Overflow; var space: Value.BigIntSpace = undefined; - const val = typed_value.val.toBigInt(&space, mod); - val.writeTwosComplement(try code.addManyAsSlice(abi_size), endian); + const int_val = val.toBigInt(&space, mod); + int_val.writeTwosComplement(try code.addManyAsSlice(abi_size), endian); }, .err => |err| { const int = try mod.getErrorValue(err.name); try code.writer().writeInt(u16, @as(u16, @intCast(int)), endian); }, .error_union => |error_union| { - const payload_ty = typed_value.ty.errorUnionPayload(mod); + const payload_ty = ty.errorUnionPayload(mod); const err_val = switch (error_union.val) { .err_name => |err_name| @as(u16, @intCast(try mod.getErrorValue(err_name))), .payload => @as(u16, 0), @@ -261,7 +259,7 @@ pub fn generateSymbol( const payload_align = payload_ty.abiAlignment(mod); const error_align = Type.anyerror.abiAlignment(mod); - const abi_align = typed_value.ty.abiAlignment(mod); + const abi_align = ty.abiAlignment(mod); // error value first when its type is larger than the error union's payload if (error_align.order(payload_align) == .gt) { @@ -271,13 +269,10 @@ pub fn generateSymbol( // emit payload part of the error union { const begin = code.items.len; - switch (try generateSymbol(bin_file, src_loc, .{ - .ty = payload_ty, - .val = Value.fromInterned(switch (error_union.val) { - .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }), - .payload => |payload| payload, - }), - }, code, debug_output, reloc_info)) { + switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(switch (error_union.val) { + .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }), + .payload => |payload| payload, + }), code, debug_output, reloc_info)) { .ok => {}, .fail => |em| return .{ .fail = em }, } @@ -304,11 +299,8 @@ pub fn generateSymbol( } }, .enum_tag => |enum_tag| { - const int_tag_ty = typed_value.ty.intTagType(mod); - switch (try generateSymbol(bin_file, src_loc, .{ - .ty = int_tag_ty, - .val = try mod.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), - }, code, debug_output, reloc_info)) { + const int_tag_ty = ty.intTagType(mod); + switch (try generateSymbol(bin_file, src_loc, try mod.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), code, debug_output, reloc_info)) { .ok => {}, .fail => |em| return .{ .fail = em }, } @@ -319,42 +311,33 @@ pub fn generateSymbol( .f64 => |f64_val| writeFloat(f64, f64_val, target, endian, try code.addManyAsArray(8)), .f80 => |f80_val| { writeFloat(f80, f80_val, target, endian, try code.addManyAsArray(10)); - const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; + const abi_size = math.cast(usize, ty.abiSize(mod)) orelse return error.Overflow; try code.appendNTimes(0, abi_size - 10); }, .f128 => |f128_val| writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(16)), }, - .ptr => switch (try lowerParentPtr(bin_file, src_loc, typed_value.val.toIntern(), code, debug_output, reloc_info)) { + .ptr => switch (try lowerParentPtr(bin_file, src_loc, val.toIntern(), code, debug_output, reloc_info)) { .ok => {}, .fail => |em| return .{ .fail = em }, }, .slice => |slice| { - switch (try generateSymbol(bin_file, src_loc, .{ - .ty = typed_value.ty.slicePtrFieldType(mod), - .val = Value.fromInterned(slice.ptr), - }, code, debug_output, reloc_info)) { + switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(slice.ptr), code, debug_output, reloc_info)) { .ok => {}, .fail => |em| return .{ .fail = em }, } - switch (try generateSymbol(bin_file, src_loc, .{ - .ty = Type.usize, - .val = Value.fromInterned(slice.len), - }, code, debug_output, reloc_info)) { + switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(slice.len), code, debug_output, reloc_info)) { .ok => {}, .fail => |em| return .{ .fail = em }, } }, .opt => { - const payload_type = typed_value.ty.optionalChild(mod); - const payload_val = typed_value.val.optionalValue(mod); - const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; + const payload_type = ty.optionalChild(mod); + const payload_val = val.optionalValue(mod); + const abi_size = math.cast(usize, ty.abiSize(mod)) orelse return error.Overflow; - if (typed_value.ty.optionalReprIsPayload(mod)) { + if (ty.optionalReprIsPayload(mod)) { if (payload_val) |value| { - switch (try generateSymbol(bin_file, src_loc, .{ - .ty = payload_type, - .val = value, - }, code, debug_output, reloc_info)) { + switch (try generateSymbol(bin_file, src_loc, value, code, debug_output, reloc_info)) { .ok => {}, .fail => |em| return Result{ .fail = em }, } @@ -365,10 +348,7 @@ pub fn generateSymbol( const padding = abi_size - (math.cast(usize, payload_type.abiSize(mod)) orelse return error.Overflow) - 1; if (payload_type.hasRuntimeBits(mod)) { const value = payload_val orelse Value.fromInterned((try mod.intern(.{ .undef = payload_type.toIntern() }))); - switch (try generateSymbol(bin_file, src_loc, .{ - .ty = payload_type, - .val = value, - }, code, debug_output, reloc_info)) { + switch (try generateSymbol(bin_file, src_loc, value, code, debug_output, reloc_info)) { .ok => {}, .fail => |em| return Result{ .fail = em }, } @@ -377,7 +357,7 @@ pub fn generateSymbol( try code.appendNTimes(0, padding); } }, - .aggregate => |aggregate| switch (ip.indexToKey(typed_value.ty.toIntern())) { + .aggregate => |aggregate| switch (ip.indexToKey(ty.toIntern())) { .array_type => |array_type| switch (aggregate.storage) { .bytes => |bytes| try code.appendSlice(bytes), .elems, .repeated_elem => { @@ -385,17 +365,14 @@ pub fn generateSymbol( const len_including_sentinel = array_type.len + @intFromBool(array_type.sentinel != .none); while (index < len_including_sentinel) : (index += 1) { - switch (try generateSymbol(bin_file, src_loc, .{ - .ty = Type.fromInterned(array_type.child), - .val = Value.fromInterned(switch (aggregate.storage) { - .bytes => unreachable, - .elems => |elems| elems[@as(usize, @intCast(index))], - .repeated_elem => |elem| if (index < array_type.len) - elem - else - array_type.sentinel, - }), - }, code, debug_output, reloc_info)) { + switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(switch (aggregate.storage) { + .bytes => unreachable, + .elems => |elems| elems[@as(usize, @intCast(index))], + .repeated_elem => |elem| if (index < array_type.len) + elem + else + array_type.sentinel, + }), code, debug_output, reloc_info)) { .ok => {}, .fail => |em| return .{ .fail = em }, } @@ -403,7 +380,7 @@ pub fn generateSymbol( }, }, .vector_type => |vector_type| { - const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse + const abi_size = math.cast(usize, ty.abiSize(mod)) orelse return error.Overflow; if (vector_type.child == .bool_type) { const bytes = try code.addManyAsSlice(abi_size); @@ -449,16 +426,13 @@ pub fn generateSymbol( .elems, .repeated_elem => { var index: u64 = 0; while (index < vector_type.len) : (index += 1) { - switch (try generateSymbol(bin_file, src_loc, .{ - .ty = Type.fromInterned(vector_type.child), - .val = Value.fromInterned(switch (aggregate.storage) { - .bytes => unreachable, - .elems => |elems| elems[ - math.cast(usize, index) orelse return error.Overflow - ], - .repeated_elem => |elem| elem, - }), - }, code, debug_output, reloc_info)) { + switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(switch (aggregate.storage) { + .bytes => unreachable, + .elems => |elems| elems[ + math.cast(usize, index) orelse return error.Overflow + ], + .repeated_elem => |elem| elem, + }), code, debug_output, reloc_info)) { .ok => {}, .fail => |em| return .{ .fail = em }, } @@ -491,17 +465,14 @@ pub fn generateSymbol( .repeated_elem => |elem| elem, }; - switch (try generateSymbol(bin_file, src_loc, .{ - .ty = Type.fromInterned(field_ty), - .val = Value.fromInterned(field_val), - }, code, debug_output, reloc_info)) { + switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(field_val), code, debug_output, reloc_info)) { .ok => {}, .fail => |em| return Result{ .fail = em }, } const unpadded_field_end = code.items.len - struct_begin; // Pad struct members if required - const padded_field_end = typed_value.ty.structFieldOffset(index + 1, mod); + const padded_field_end = ty.structFieldOffset(index + 1, mod); const padding = math.cast(usize, padded_field_end - unpadded_field_end) orelse return error.Overflow; @@ -511,10 +482,10 @@ pub fn generateSymbol( } }, .struct_type => { - const struct_type = ip.loadStructType(typed_value.ty.toIntern()); + const struct_type = ip.loadStructType(ty.toIntern()); switch (struct_type.layout) { .@"packed" => { - const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse + const abi_size = math.cast(usize, ty.abiSize(mod)) orelse return error.Overflow; const current_pos = code.items.len; try code.resize(current_pos + abi_size); @@ -537,10 +508,7 @@ pub fn generateSymbol( return error.Overflow; var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size); defer tmp_list.deinit(); - switch (try generateSymbol(bin_file, src_loc, .{ - .ty = Type.fromInterned(field_ty), - .val = Value.fromInterned(field_val), - }, &tmp_list, debug_output, reloc_info)) { + switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(field_val), &tmp_list, debug_output, reloc_info)) { .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items), .fail => |em| return Result{ .fail = em }, } @@ -560,7 +528,7 @@ pub fn generateSymbol( const field_ty = field_types[field_index]; if (!Type.fromInterned(field_ty).hasRuntimeBits(mod)) continue; - const field_val = switch (ip.indexToKey(typed_value.val.toIntern()).aggregate.storage) { + const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) { .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ .ty = field_ty, .storage = .{ .u64 = bytes[field_index] }, @@ -575,10 +543,7 @@ pub fn generateSymbol( ) orelse return error.Overflow; if (padding > 0) try code.appendNTimes(0, padding); - switch (try generateSymbol(bin_file, src_loc, .{ - .ty = Type.fromInterned(field_ty), - .val = Value.fromInterned(field_val), - }, code, debug_output, reloc_info)) { + switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(field_val), code, debug_output, reloc_info)) { .ok => {}, .fail => |em| return Result{ .fail = em }, } @@ -599,37 +564,28 @@ pub fn generateSymbol( else => unreachable, }, .un => |un| { - const layout = typed_value.ty.unionGetLayout(mod); + const layout = ty.unionGetLayout(mod); if (layout.payload_size == 0) { - return generateSymbol(bin_file, src_loc, .{ - .ty = typed_value.ty.unionTagTypeSafety(mod).?, - .val = Value.fromInterned(un.tag), - }, code, debug_output, reloc_info); + return generateSymbol(bin_file, src_loc, Value.fromInterned(un.tag), code, debug_output, reloc_info); } // Check if we should store the tag first. if (layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align)) { - switch (try generateSymbol(bin_file, src_loc, .{ - .ty = typed_value.ty.unionTagTypeSafety(mod).?, - .val = Value.fromInterned(un.tag), - }, code, debug_output, reloc_info)) { + switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(un.tag), code, debug_output, reloc_info)) { .ok => {}, .fail => |em| return Result{ .fail = em }, } } - const union_obj = mod.typeToUnion(typed_value.ty).?; + const union_obj = mod.typeToUnion(ty).?; if (un.tag != .none) { - const field_index = typed_value.ty.unionTagFieldIndex(Value.fromInterned(un.tag), mod).?; + const field_index = ty.unionTagFieldIndex(Value.fromInterned(un.tag), mod).?; const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]); if (!field_ty.hasRuntimeBits(mod)) { try code.appendNTimes(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow); } else { - switch (try generateSymbol(bin_file, src_loc, .{ - .ty = field_ty, - .val = Value.fromInterned(un.val), - }, code, debug_output, reloc_info)) { + switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(un.val), code, debug_output, reloc_info)) { .ok => {}, .fail => |em| return Result{ .fail = em }, } @@ -640,20 +596,14 @@ pub fn generateSymbol( } } } else { - switch (try generateSymbol(bin_file, src_loc, .{ - .ty = Type.fromInterned(ip.typeOf(un.val)), - .val = Value.fromInterned(un.val), - }, code, debug_output, reloc_info)) { + switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(un.val), code, debug_output, reloc_info)) { .ok => {}, .fail => |em| return Result{ .fail = em }, } } if (layout.tag_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) { - switch (try generateSymbol(bin_file, src_loc, .{ - .ty = Type.fromInterned(union_obj.enum_tag_ty), - .val = Value.fromInterned(un.tag), - }, code, debug_output, reloc_info)) { + switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(un.tag), code, debug_output, reloc_info)) { .ok => {}, .fail => |em| return Result{ .fail = em }, } @@ -681,10 +631,7 @@ fn lowerParentPtr( return switch (ptr.addr) { .decl => |decl| try lowerDeclRef(bin_file, src_loc, decl, code, debug_output, reloc_info), .anon_decl => |ad| try lowerAnonDeclRef(bin_file, src_loc, ad, code, debug_output, reloc_info), - .int => |int| try generateSymbol(bin_file, src_loc, .{ - .ty = Type.usize, - .val = Value.fromInterned(int), - }, code, debug_output, reloc_info), + .int => |int| try generateSymbol(bin_file, src_loc, Value.fromInterned(int), code, debug_output, reloc_info), .eu_payload => |eu_payload| try lowerParentPtr( bin_file, src_loc, @@ -910,11 +857,12 @@ pub const GenResult = union(enum) { fn genDeclRef( lf: *link.File, src_loc: Module.SrcLoc, - tv: TypedValue, + val: Value, ptr_decl_index: InternPool.DeclIndex, ) CodeGenError!GenResult { const zcu = lf.comp.module.?; - log.debug("genDeclRef: ty = {}, val = {}", .{ tv.ty.fmt(zcu), tv.val.fmtValue(tv.ty, zcu) }); + const ty = val.typeOf(zcu); + log.debug("genDeclRef: val = {}", .{val.fmtValue(ty, zcu)}); const ptr_decl = zcu.declPtr(ptr_decl_index); const namespace = zcu.namespacePtr(ptr_decl.src_namespace); @@ -945,12 +893,12 @@ fn genDeclRef( const gpa = comp.gpa; // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? - if (tv.ty.castPtrToFn(zcu)) |fn_ty| { + if (ty.castPtrToFn(zcu)) |fn_ty| { if (zcu.typeToFunc(fn_ty).?.is_generic) { return GenResult.mcv(.{ .immediate = fn_ty.abiAlignment(zcu).toByteUnitsOptional().? }); } - } else if (tv.ty.zigTypeTag(zcu) == .Pointer) { - const elem_ty = tv.ty.elemType2(zcu); + } else if (ty.zigTypeTag(zcu) == .Pointer) { + const elem_ty = ty.elemType2(zcu); if (!elem_ty.hasRuntimeBits(zcu)) { return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(zcu).toByteUnitsOptional().? }); } @@ -958,7 +906,7 @@ fn genDeclRef( const decl_namespace = zcu.namespacePtr(decl.src_namespace); const single_threaded = decl_namespace.file_scope.mod.single_threaded; - const is_threadlocal = tv.val.isPtrToThreadLocal(zcu) and !single_threaded; + const is_threadlocal = val.isPtrToThreadLocal(zcu) and !single_threaded; const is_extern = decl.isExtern(zcu); if (lf.cast(link.File.Elf)) |elf_file| { @@ -1023,14 +971,14 @@ fn genDeclRef( fn genUnnamedConst( lf: *link.File, src_loc: Module.SrcLoc, - tv: TypedValue, + val: Value, owner_decl_index: InternPool.DeclIndex, ) CodeGenError!GenResult { const zcu = lf.comp.module.?; const gpa = lf.comp.gpa; - log.debug("genUnnamedConst: ty = {}, val = {}", .{ tv.ty.fmt(zcu), tv.val.fmtValue(tv.ty, zcu) }); + log.debug("genUnnamedConst: val = {}", .{val.fmtValue(val.typeOf(zcu), zcu)}); - const local_sym_index = lf.lowerUnnamedConst(tv, owner_decl_index) catch |err| { + const local_sym_index = lf.lowerUnnamedConst(val, owner_decl_index) catch |err| { return GenResult.fail(gpa, src_loc, "lowering unnamed constant failed: {s}", .{@errorName(err)}); }; switch (lf.tag) { @@ -1062,18 +1010,15 @@ fn genUnnamedConst( pub fn genTypedValue( lf: *link.File, src_loc: Module.SrcLoc, - arg_tv: TypedValue, + val: Value, owner_decl_index: InternPool.DeclIndex, ) CodeGenError!GenResult { const zcu = lf.comp.module.?; - const typed_value = arg_tv; + const ty = val.typeOf(zcu); - log.debug("genTypedValue: ty = {}, val = {}", .{ - typed_value.ty.fmt(zcu), - typed_value.val.fmtValue(typed_value.ty, zcu), - }); + log.debug("genTypedValue: val = {}", .{val.fmtValue(ty, zcu)}); - if (typed_value.val.isUndef(zcu)) + if (val.isUndef(zcu)) return GenResult.mcv(.undef); const owner_decl = zcu.declPtr(owner_decl_index); @@ -1081,85 +1026,92 @@ pub fn genTypedValue( const target = namespace.file_scope.mod.resolved_target.result; const ptr_bits = target.ptrBitWidth(); - if (!typed_value.ty.isSlice(zcu)) switch (zcu.intern_pool.indexToKey(typed_value.val.toIntern())) { + if (!ty.isSlice(zcu)) switch (zcu.intern_pool.indexToKey(val.toIntern())) { .ptr => |ptr| switch (ptr.addr) { - .decl => |decl| return genDeclRef(lf, src_loc, typed_value, decl), + .decl => |decl| return genDeclRef(lf, src_loc, val, decl), else => {}, }, else => {}, }; - switch (typed_value.ty.zigTypeTag(zcu)) { + switch (ty.zigTypeTag(zcu)) { .Void => return GenResult.mcv(.none), - .Pointer => switch (typed_value.ty.ptrSize(zcu)) { + .Pointer => switch (ty.ptrSize(zcu)) { .Slice => {}, - else => switch (typed_value.val.toIntern()) { + else => switch (val.toIntern()) { .null_value => { return GenResult.mcv(.{ .immediate = 0 }); }, .none => {}, - else => switch (zcu.intern_pool.indexToKey(typed_value.val.toIntern())) { + else => switch (zcu.intern_pool.indexToKey(val.toIntern())) { .int => { - return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(zcu) }); + return GenResult.mcv(.{ .immediate = val.toUnsignedInt(zcu) }); }, else => {}, }, }, }, .Int => { - const info = typed_value.ty.intInfo(zcu); + const info = ty.intInfo(zcu); if (info.bits <= ptr_bits) { const unsigned = switch (info.signedness) { - .signed => @as(u64, @bitCast(typed_value.val.toSignedInt(zcu))), - .unsigned => typed_value.val.toUnsignedInt(zcu), + .signed => @as(u64, @bitCast(val.toSignedInt(zcu))), + .unsigned => val.toUnsignedInt(zcu), }; return GenResult.mcv(.{ .immediate = unsigned }); } }, .Bool => { - return GenResult.mcv(.{ .immediate = @intFromBool(typed_value.val.toBool()) }); + return GenResult.mcv(.{ .immediate = @intFromBool(val.toBool()) }); }, .Optional => { - if (typed_value.ty.isPtrLikeOptional(zcu)) { - return genTypedValue(lf, src_loc, .{ - .ty = typed_value.ty.optionalChild(zcu), - .val = typed_value.val.optionalValue(zcu) orelse return GenResult.mcv(.{ .immediate = 0 }), - }, owner_decl_index); - } else if (typed_value.ty.abiSize(zcu) == 1) { - return GenResult.mcv(.{ .immediate = @intFromBool(!typed_value.val.isNull(zcu)) }); + if (ty.isPtrLikeOptional(zcu)) { + return genTypedValue( + lf, + src_loc, + val.optionalValue(zcu) orelse return GenResult.mcv(.{ .immediate = 0 }), + owner_decl_index, + ); + } else if (ty.abiSize(zcu) == 1) { + return GenResult.mcv(.{ .immediate = @intFromBool(!val.isNull(zcu)) }); } }, .Enum => { - const enum_tag = zcu.intern_pool.indexToKey(typed_value.val.toIntern()).enum_tag; - const int_tag_ty = zcu.intern_pool.typeOf(enum_tag.int); - return genTypedValue(lf, src_loc, .{ - .ty = Type.fromInterned(int_tag_ty), - .val = Value.fromInterned(enum_tag.int), - }, owner_decl_index); + const enum_tag = zcu.intern_pool.indexToKey(val.toIntern()).enum_tag; + return genTypedValue( + lf, + src_loc, + Value.fromInterned(enum_tag.int), + owner_decl_index, + ); }, .ErrorSet => { - const err_name = zcu.intern_pool.indexToKey(typed_value.val.toIntern()).err.name; + const err_name = zcu.intern_pool.indexToKey(val.toIntern()).err.name; const error_index = zcu.global_error_set.getIndex(err_name).?; return GenResult.mcv(.{ .immediate = error_index }); }, .ErrorUnion => { - const err_type = typed_value.ty.errorUnionSet(zcu); - const payload_type = typed_value.ty.errorUnionPayload(zcu); + const err_type = ty.errorUnionSet(zcu); + const payload_type = ty.errorUnionPayload(zcu); if (!payload_type.hasRuntimeBitsIgnoreComptime(zcu)) { // We use the error type directly as the type. const err_int_ty = try zcu.errorIntType(); - switch (zcu.intern_pool.indexToKey(typed_value.val.toIntern()).error_union.val) { - .err_name => |err_name| return genTypedValue(lf, src_loc, .{ - .ty = err_type, - .val = Value.fromInterned((try zcu.intern(.{ .err = .{ + switch (zcu.intern_pool.indexToKey(val.toIntern()).error_union.val) { + .err_name => |err_name| return genTypedValue( + lf, + src_loc, + Value.fromInterned(try zcu.intern(.{ .err = .{ .ty = err_type.toIntern(), .name = err_name, - } }))), - }, owner_decl_index), - .payload => return genTypedValue(lf, src_loc, .{ - .ty = err_int_ty, - .val = try zcu.intValue(err_int_ty, 0), - }, owner_decl_index), + } })), + owner_decl_index, + ), + .payload => return genTypedValue( + lf, + src_loc, + try zcu.intValue(err_int_ty, 0), + owner_decl_index, + ), } } }, @@ -1176,7 +1128,7 @@ pub fn genTypedValue( else => {}, } - return genUnnamedConst(lf, src_loc, typed_value, owner_decl_index); + return genUnnamedConst(lf, src_loc, val, owner_decl_index); } pub fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u64 { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index ed506cfdfe6c..7ae5c87ee540 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -9,7 +9,6 @@ const Module = @import("../Module.zig"); const Compilation = @import("../Compilation.zig"); const Value = @import("../Value.zig"); const Type = @import("../type.zig").Type; -const TypedValue = @import("../TypedValue.zig"); const C = link.File.C; const Decl = Module.Decl; const trace = @import("../tracy.zig").trace; @@ -1877,9 +1876,9 @@ pub const DeclGen = struct { try renderTypeSuffix(dg.pass, store.*, mod, w, cty_idx, .suffix, .{}); } - fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool { + fn declIsGlobal(dg: *DeclGen, val: Value) bool { const mod = dg.module; - return switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { + return switch (mod.intern_pool.indexToKey(val.ip_index)) { .variable => |variable| mod.decl_exports.contains(variable.decl), .extern_func => true, .func => |func| mod.decl_exports.contains(func.owner_decl), @@ -1972,7 +1971,7 @@ pub const DeclGen = struct { ) !void { const decl = dg.module.declPtr(decl_index); const fwd = dg.fwdDeclWriter(); - const is_global = variable.is_extern or dg.declIsGlobal(.{ .ty = decl.typeOf(dg.module), .val = decl.val }); + const is_global = variable.is_extern or dg.declIsGlobal(decl.val); try fwd.writeAll(if (is_global) "zig_extern " else "static "); const maybe_exports = dg.module.decl_exports.get(decl_index); const export_weak_linkage = if (maybe_exports) |exports| @@ -2656,13 +2655,12 @@ fn genExports(o: *Object) !void { .anon, .flush => return, }; const decl = mod.declPtr(decl_index); - const tv: TypedValue = .{ .ty = decl.typeOf(mod), .val = decl.val }; const fwd = o.dg.fwdDeclWriter(); const exports = mod.decl_exports.get(decl_index) orelse return; if (exports.items.len < 2) return; - const is_variable_const = switch (ip.indexToKey(tv.val.toIntern())) { + const is_variable_const = switch (ip.indexToKey(decl.val.toIntern())) { .func => return for (exports.items[1..], 1..) |@"export", i| { try fwd.writeAll("zig_extern "); if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage_fn "); @@ -2805,15 +2803,11 @@ pub fn genFunc(f: *Function) !void { const gpa = o.dg.gpa; const decl_index = o.dg.pass.decl; const decl = mod.declPtr(decl_index); - const tv: TypedValue = .{ - .ty = decl.typeOf(mod), - .val = decl.val, - }; o.code_header = std.ArrayList(u8).init(gpa); defer o.code_header.deinit(); - const is_global = o.dg.declIsGlobal(tv); + const is_global = o.dg.declIsGlobal(decl.val); const fwd_decl_writer = o.dg.fwdDeclWriter(); try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static "); @@ -2893,22 +2887,23 @@ pub fn genDecl(o: *Object) !void { const mod = o.dg.module; const decl_index = o.dg.pass.decl; const decl = mod.declPtr(decl_index); - const tv: TypedValue = .{ .ty = decl.typeOf(mod), .val = decl.val }; + const decl_val = decl.val; + const decl_ty = decl_val.typeOf(mod); - if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return; - if (tv.val.getExternFunc(mod)) |_| { + if (!decl_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return; + if (decl_val.getExternFunc(mod)) |_| { const fwd_decl_writer = o.dg.fwdDeclWriter(); try fwd_decl_writer.writeAll("zig_extern "); try o.dg.renderFunctionSignature(fwd_decl_writer, decl_index, .forward, .{ .export_index = 0 }); try fwd_decl_writer.writeAll(";\n"); try genExports(o); - } else if (tv.val.getVariable(mod)) |variable| { + } else if (decl_val.getVariable(mod)) |variable| { try o.dg.renderFwdDecl(decl_index, variable, .final); try genExports(o); if (variable.is_extern) return; - const is_global = variable.is_extern or o.dg.declIsGlobal(tv); + const is_global = variable.is_extern or o.dg.declIsGlobal(decl_val); const w = o.writer(); if (!is_global) try w.writeAll("static "); if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage "); @@ -2916,22 +2911,22 @@ pub fn genDecl(o: *Object) !void { if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| try w.print("zig_linksection(\"{s}\", ", .{s}); const decl_c_value = .{ .decl = decl_index }; - try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.alignment, .complete); + try o.dg.renderTypeAndName(w, decl_ty, decl_c_value, .{}, decl.alignment, .complete); if (decl.@"linksection" != .none) try w.writeAll(", read, write)"); try w.writeAll(" = "); - try o.dg.renderValue(w, tv.ty, Value.fromInterned(variable.init), .StaticInitializer); + try o.dg.renderValue(w, decl_ty, Value.fromInterned(variable.init), .StaticInitializer); try w.writeByte(';'); try o.indent_writer.insertNewline(); } else { const is_global = o.dg.module.decl_exports.contains(decl_index); const decl_c_value = .{ .decl = decl_index }; - try genDeclValue(o, tv, is_global, decl_c_value, decl.alignment, decl.@"linksection"); + try genDeclValue(o, decl_val, is_global, decl_c_value, decl.alignment, decl.@"linksection"); } } pub fn genDeclValue( o: *Object, - tv: TypedValue, + val: Value, is_global: bool, decl_c_value: CValue, alignment: Alignment, @@ -2940,8 +2935,10 @@ pub fn genDeclValue( const mod = o.dg.module; const fwd_decl_writer = o.dg.fwdDeclWriter(); + const ty = val.typeOf(mod); + try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static "); - try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, alignment, .complete); + try o.dg.renderTypeAndName(fwd_decl_writer, ty, decl_c_value, Const, alignment, .complete); switch (o.dg.pass) { .decl => |decl_index| { if (mod.decl_exports.get(decl_index)) |exports| { @@ -2964,10 +2961,10 @@ pub fn genDeclValue( if (mod.intern_pool.stringToSliceUnwrap(link_section)) |s| try w.print("zig_linksection(\"{s}\", ", .{s}); - try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, alignment, .complete); + try o.dg.renderTypeAndName(w, ty, decl_c_value, Const, alignment, .complete); if (link_section != .none) try w.writeAll(", read)"); try w.writeAll(" = "); - try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer); + try o.dg.renderValue(w, ty, val, .StaticInitializer); try w.writeAll(";\n"); } @@ -2978,14 +2975,10 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { const mod = dg.module; const decl_index = dg.pass.decl; const decl = mod.declPtr(decl_index); - const tv: TypedValue = .{ - .ty = decl.typeOf(mod), - .val = decl.val, - }; const writer = dg.fwdDeclWriter(); - switch (tv.ty.zigTypeTag(mod)) { - .Fn => if (dg.declIsGlobal(tv)) { + switch (decl.val.typeOf(mod).zigTypeTag(mod)) { + .Fn => if (dg.declIsGlobal(decl.val)) { try writer.writeAll("zig_extern "); try dg.renderFunctionSignature(writer, dg.pass.decl, .complete, .{ .export_index = 0 }); try dg.fwd_decl.appendSlice(";\n"); @@ -5304,25 +5297,25 @@ fn airIsNull( const err_int_ty = try mod.errorIntType(); const rhs = if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) - TypedValue{ .ty = Type.bool, .val = Value.true } + Value.true else if (optional_ty.isPtrLikeOptional(mod)) // operand is a regular pointer, test `operand !=/== NULL` - TypedValue{ .ty = optional_ty, .val = try mod.getCoerced(Value.null, optional_ty) } + try mod.getCoerced(Value.null, optional_ty) else if (payload_ty.zigTypeTag(mod) == .ErrorSet) - TypedValue{ .ty = err_int_ty, .val = try mod.intValue(err_int_ty, 0) } + try mod.intValue(err_int_ty, 0) else if (payload_ty.isSlice(mod) and optional_ty.optionalReprIsPayload(mod)) rhs: { try writer.writeAll(".ptr"); const slice_ptr_ty = payload_ty.slicePtrFieldType(mod); const opt_slice_ptr_ty = try mod.optionalType(slice_ptr_ty.toIntern()); - break :rhs TypedValue{ .ty = opt_slice_ptr_ty, .val = try mod.nullValue(opt_slice_ptr_ty) }; + break :rhs try mod.nullValue(opt_slice_ptr_ty); } else rhs: { try writer.writeAll(".is_null"); - break :rhs TypedValue{ .ty = Type.bool, .val = Value.true }; + break :rhs Value.true; }; try writer.writeByte(' '); try writer.writeAll(operator); try writer.writeByte(' '); - try f.object.dg.renderValue(writer, rhs.ty, rhs.val, .Other); + try f.object.dg.renderValue(writer, rhs.typeOf(mod), rhs, .Other); try writer.writeAll(";\n"); return local; } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index f4d91c2ebba7..8ddacbe11ca1 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -18,7 +18,6 @@ const Module = @import("../Module.zig"); const Zcu = Module; const InternPool = @import("../InternPool.zig"); const Package = @import("../Package.zig"); -const TypedValue = @import("../TypedValue.zig"); const Air = @import("../Air.zig"); const Liveness = @import("../Liveness.zig"); const Value = @import("../Value.zig"); @@ -4823,19 +4822,17 @@ pub const FuncGen = struct { const o = self.dg.object; const mod = o.module; - const llvm_val = try self.resolveValue(.{ - .ty = self.typeOf(inst), - .val = (try self.air.value(inst, mod)).?, - }); + const llvm_val = try self.resolveValue((try self.air.value(inst, mod)).?); gop.value_ptr.* = llvm_val.toValue(); return llvm_val.toValue(); } - fn resolveValue(self: *FuncGen, tv: TypedValue) Error!Builder.Constant { + fn resolveValue(self: *FuncGen, val: Value) Error!Builder.Constant { const o = self.dg.object; const mod = o.module; - const llvm_val = try o.lowerValue(tv.val.toIntern()); - if (!isByRef(tv.ty, mod)) return llvm_val; + const ty = val.typeOf(mod); + const llvm_val = try o.lowerValue(val.toIntern()); + if (!isByRef(ty, mod)) return llvm_val; // We have an LLVM value but we need to create a global constant and // set the value as its initializer, and then return a pointer to the global. @@ -4849,7 +4846,7 @@ pub const FuncGen = struct { variable_index.setLinkage(.private, &o.builder); variable_index.setMutability(.constant, &o.builder); variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); - variable_index.setAlignment(tv.ty.abiAlignment(mod).toLlvm(), &o.builder); + variable_index.setAlignment(ty.abiAlignment(mod).toLlvm(), &o.builder); return o.builder.convConst( .unneeded, variable_index.toConst(&o.builder), @@ -4861,11 +4858,10 @@ pub const FuncGen = struct { const o = self.dg.object; const mod = o.module; if (o.null_opt_usize == .no_init) { - const ty = try mod.intern(.{ .opt_type = .usize_type }); - o.null_opt_usize = try self.resolveValue(.{ - .ty = Type.fromInterned(ty), - .val = Value.fromInterned((try mod.intern(.{ .opt = .{ .ty = ty, .val = .none } }))), - }); + o.null_opt_usize = try self.resolveValue(Value.fromInterned(try mod.intern(.{ .opt = .{ + .ty = try mod.intern(.{ .opt_type = .usize_type }), + .val = .none, + } }))); } return o.null_opt_usize; } @@ -10061,10 +10057,7 @@ pub const FuncGen = struct { const elem_ptr = try self.wip.gep(.inbounds, llvm_result_ty, alloca_inst, &.{ usize_zero, try o.builder.intValue(llvm_usize, array_info.len), }, ""); - const llvm_elem = try self.resolveValue(.{ - .ty = array_info.elem_type, - .val = sent_val, - }); + const llvm_elem = try self.resolveValue(sent_val); try self.store(elem_ptr, elem_ptr_ty, llvm_elem.toValue(), .none); } diff --git a/src/link.zig b/src/link.zig index 6034d8df49ee..9e1daa09af28 100644 --- a/src/link.zig +++ b/src/link.zig @@ -17,7 +17,7 @@ const Liveness = @import("Liveness.zig"); const Module = @import("Module.zig"); const InternPool = @import("InternPool.zig"); const Type = @import("type.zig").Type; -const TypedValue = @import("TypedValue.zig"); +const Value = @import("Value.zig"); const LlvmObject = @import("codegen/llvm.zig").Object; /// When adding a new field, remember to update `hashAddSystemLibs`. @@ -376,14 +376,14 @@ pub const File = struct { /// Called from within the CodeGen to lower a local variable instantion as an unnamed /// constant. Returns the symbol index of the lowered constant in the read-only section /// of the final binary. - pub fn lowerUnnamedConst(base: *File, tv: TypedValue, decl_index: InternPool.DeclIndex) UpdateDeclError!u32 { + pub fn lowerUnnamedConst(base: *File, val: Value, decl_index: InternPool.DeclIndex) UpdateDeclError!u32 { if (build_options.only_c) @compileError("unreachable"); switch (base.tag) { .spirv => unreachable, .c => unreachable, .nvptx => unreachable, inline else => |t| { - return @fieldParentPtr(t.Type(), "base", base).lowerUnnamedConst(tv, decl_index); + return @fieldParentPtr(t.Type(), "base", base).lowerUnnamedConst(val, decl_index); }, } } diff --git a/src/link/C.zig b/src/link/C.zig index 1bfe55c70a89..73049b40cd13 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -283,13 +283,9 @@ fn updateAnonDecl(self: *C, module: *Module, i: usize) !void { code.* = object.code.moveToUnmanaged(); } - const tv: @import("../TypedValue.zig") = .{ - .ty = Type.fromInterned(module.intern_pool.typeOf(anon_decl)), - .val = Value.fromInterned(anon_decl), - }; const c_value: codegen.CValue = .{ .constant = anon_decl }; const alignment: Alignment = self.aligned_anon_decls.get(anon_decl) orelse .none; - codegen.genDeclValue(&object, tv, false, c_value, alignment, .none) catch |err| switch (err) { + codegen.genDeclValue(&object, Value.fromInterned(anon_decl), false, c_value, alignment, .none) catch |err| switch (err) { error.AnalysisFail => { @panic("TODO: C backend AnalysisFail on anonymous decl"); //try module.failed_decls.put(gpa, decl_index, object.dg.error_msg.?); diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 01fa6cac6716..7becb3f366f8 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1167,7 +1167,7 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air: return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index)); } -pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 { +pub fn lowerUnnamedConst(self: *Coff, val: Value, decl_index: InternPool.DeclIndex) !u32 { const gpa = self.base.comp.gpa; const mod = self.base.comp.module.?; const decl = mod.declPtr(decl_index); @@ -1180,7 +1180,8 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: InternPool.Dec const index = unnamed_consts.items.len; const sym_name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); defer gpa.free(sym_name); - const atom_index = switch (try self.lowerConst(sym_name, tv, tv.ty.abiAlignment(mod), self.rdata_section_index.?, decl.srcLoc(mod))) { + const ty = val.typeOf(mod); + const atom_index = switch (try self.lowerConst(sym_name, val, ty.abiAlignment(mod), self.rdata_section_index.?, decl.srcLoc(mod))) { .ok => |atom_index| atom_index, .fail => |em| { decl.analysis = .codegen_failure; @@ -1198,7 +1199,7 @@ const LowerConstResult = union(enum) { fail: *Module.ErrorMsg, }; -fn lowerConst(self: *Coff, name: []const u8, tv: TypedValue, required_alignment: InternPool.Alignment, sect_id: u16, src_loc: Module.SrcLoc) !LowerConstResult { +fn lowerConst(self: *Coff, name: []const u8, val: Value, required_alignment: InternPool.Alignment, sect_id: u16, src_loc: Module.SrcLoc) !LowerConstResult { const gpa = self.base.comp.gpa; var code_buffer = std.ArrayList(u8).init(gpa); @@ -1209,7 +1210,7 @@ fn lowerConst(self: *Coff, name: []const u8, tv: TypedValue, required_alignment: try self.setSymbolName(sym, name); sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_id + 1)); - const res = try codegen.generateSymbol(&self.base, src_loc, tv, &code_buffer, .none, .{ + const res = try codegen.generateSymbol(&self.base, src_loc, val, &code_buffer, .none, .{ .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, }); const code = switch (res) { @@ -1271,10 +1272,7 @@ pub fn updateDecl( defer code_buffer.deinit(); const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val; - const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ - .ty = decl.typeOf(mod), - .val = decl_val, - }, &code_buffer, .none, .{ + const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), decl_val, &code_buffer, .none, .{ .parent_atom_index = atom.getSymbolIndex().?, }); const code = switch (res) { @@ -1887,14 +1885,13 @@ pub fn lowerAnonDecl( } const val = Value.fromInterned(decl_val); - const tv = TypedValue{ .ty = ty, .val = val }; var name_buf: [32]u8 = undefined; const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ @intFromEnum(decl_val), }) catch unreachable; const res = self.lowerConst( name, - tv, + val, decl_alignment, self.rdata_section_index.?, src_loc, @@ -2754,7 +2751,6 @@ const TableSection = @import("table_section.zig").TableSection; const StringTable = @import("StringTable.zig"); const Type = @import("../type.zig").Type; const Value = @import("../Value.zig"); -const TypedValue = @import("../TypedValue.zig"); pub const base_tag: link.File.Tag = .coff; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index f0d3f89a7fc0..95ddc81e3c08 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -3039,8 +3039,8 @@ pub fn updateDecl( return self.zigObjectPtr().?.updateDecl(self, mod, decl_index); } -pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: InternPool.DeclIndex) !u32 { - return self.zigObjectPtr().?.lowerUnnamedConst(self, typed_value, decl_index); +pub fn lowerUnnamedConst(self: *Elf, val: Value, decl_index: InternPool.DeclIndex) !u32 { + return self.zigObjectPtr().?.lowerUnnamedConst(self, val, decl_index); } pub fn updateExports( @@ -6260,7 +6260,7 @@ const SharedObject = @import("Elf/SharedObject.zig"); const Symbol = @import("Elf/Symbol.zig"); const StringTable = @import("StringTable.zig"); const Thunk = thunks.Thunk; -const TypedValue = @import("../TypedValue.zig"); +const Value = @import("../Value.zig"); const VerneedSection = synthetic_sections.VerneedSection; const ZigGotSection = synthetic_sections.ZigGotSection; const ZigObject = @import("Elf/ZigObject.zig"); diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 3bf6f1246c66..6ed55dac10eb 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -702,7 +702,6 @@ pub fn lowerAnonDecl( } const val = Value.fromInterned(decl_val); - const tv = TypedValue{ .ty = ty, .val = val }; var name_buf: [32]u8 = undefined; const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ @intFromEnum(decl_val), @@ -710,7 +709,7 @@ pub fn lowerAnonDecl( const res = self.lowerConst( elf_file, name, - tv, + val, decl_alignment, elf_file.zig_data_rel_ro_section_index.?, src_loc, @@ -1157,19 +1156,13 @@ pub fn updateDecl( // TODO implement .debug_info for global variables const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val; const res = if (decl_state) |*ds| - try codegen.generateSymbol(&elf_file.base, decl.srcLoc(mod), .{ - .ty = decl.typeOf(mod), - .val = decl_val, - }, &code_buffer, .{ + try codegen.generateSymbol(&elf_file.base, decl.srcLoc(mod), decl_val, &code_buffer, .{ .dwarf = ds, }, .{ .parent_atom_index = sym_index, }) else - try codegen.generateSymbol(&elf_file.base, decl.srcLoc(mod), .{ - .ty = decl.typeOf(mod), - .val = decl_val, - }, &code_buffer, .none, .{ + try codegen.generateSymbol(&elf_file.base, decl.srcLoc(mod), decl_val, &code_buffer, .none, .{ .parent_atom_index = sym_index, }); @@ -1289,7 +1282,7 @@ fn updateLazySymbol( pub fn lowerUnnamedConst( self: *ZigObject, elf_file: *Elf, - typed_value: TypedValue, + val: Value, decl_index: InternPool.DeclIndex, ) !u32 { const gpa = elf_file.base.comp.gpa; @@ -1304,11 +1297,12 @@ pub fn lowerUnnamedConst( const index = unnamed_consts.items.len; const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); defer gpa.free(name); + const ty = val.typeOf(mod); const sym_index = switch (try self.lowerConst( elf_file, name, - typed_value, - typed_value.ty.abiAlignment(mod), + val, + ty.abiAlignment(mod), elf_file.zig_data_rel_ro_section_index.?, decl.srcLoc(mod), )) { @@ -1334,7 +1328,7 @@ fn lowerConst( self: *ZigObject, elf_file: *Elf, name: []const u8, - tv: TypedValue, + val: Value, required_alignment: InternPool.Alignment, output_section_index: u32, src_loc: Module.SrcLoc, @@ -1346,7 +1340,7 @@ fn lowerConst( const sym_index = try self.addAtom(elf_file); - const res = try codegen.generateSymbol(&elf_file.base, src_loc, tv, &code_buffer, .{ + const res = try codegen.generateSymbol(&elf_file.base, src_loc, val, &code_buffer, .{ .none = {}, }, .{ .parent_atom_index = sym_index, @@ -1657,5 +1651,4 @@ const Symbol = @import("Symbol.zig"); const StringTable = @import("../StringTable.zig"); const Type = @import("../../type.zig").Type; const Value = @import("../../Value.zig"); -const TypedValue = @import("../../TypedValue.zig"); const ZigObject = @This(); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 29ac89d26c0b..c2b8d02df574 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -3127,8 +3127,8 @@ pub fn updateFunc(self: *MachO, mod: *Module, func_index: InternPool.Index, air: return self.getZigObject().?.updateFunc(self, mod, func_index, air, liveness); } -pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: InternPool.DeclIndex) !u32 { - return self.getZigObject().?.lowerUnnamedConst(self, typed_value, decl_index); +pub fn lowerUnnamedConst(self: *MachO, val: Value, decl_index: InternPool.DeclIndex) !u32 { + return self.getZigObject().?.lowerUnnamedConst(self, val, decl_index); } pub fn updateDecl(self: *MachO, mod: *Module, decl_index: InternPool.DeclIndex) !void { @@ -4689,7 +4689,7 @@ const StubsHelperSection = synthetic.StubsHelperSection; const Symbol = @import("MachO/Symbol.zig"); const Thunk = thunks.Thunk; const TlvPtrSection = synthetic.TlvPtrSection; -const TypedValue = @import("../TypedValue.zig"); +const Value = @import("../Value.zig"); const UnwindInfo = @import("MachO/UnwindInfo.zig"); const WeakBindSection = synthetic.WeakBindSection; const ZigGotSection = synthetic.ZigGotSection; diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 42f186d96133..fb27c965252e 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -567,8 +567,6 @@ pub fn lowerAnonDecl( return .ok; } - const val = Value.fromInterned(decl_val); - const tv = TypedValue{ .ty = ty, .val = val }; var name_buf: [32]u8 = undefined; const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ @intFromEnum(decl_val), @@ -576,7 +574,7 @@ pub fn lowerAnonDecl( const res = self.lowerConst( macho_file, name, - tv, + Value.fromInterned(decl_val), decl_alignment, macho_file.zig_const_sect_index.?, src_loc, @@ -738,11 +736,7 @@ pub fn updateDecl( const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val; const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none; - const res = - try codegen.generateSymbol(&macho_file.base, decl.srcLoc(mod), .{ - .ty = decl.typeOf(mod), - .val = decl_val, - }, &code_buffer, dio, .{ + const res = try codegen.generateSymbol(&macho_file.base, decl.srcLoc(mod), decl_val, &code_buffer, dio, .{ .parent_atom_index = sym_index, }); @@ -1068,7 +1062,7 @@ fn getDeclOutputSection( pub fn lowerUnnamedConst( self: *ZigObject, macho_file: *MachO, - typed_value: TypedValue, + val: Value, decl_index: InternPool.DeclIndex, ) !u32 { const gpa = macho_file.base.comp.gpa; @@ -1086,8 +1080,8 @@ pub fn lowerUnnamedConst( const sym_index = switch (try self.lowerConst( macho_file, name, - typed_value, - typed_value.ty.abiAlignment(mod), + val, + val.typeOf(mod).abiAlignment(mod), macho_file.zig_const_sect_index.?, decl.srcLoc(mod), )) { @@ -1113,7 +1107,7 @@ fn lowerConst( self: *ZigObject, macho_file: *MachO, name: []const u8, - tv: TypedValue, + val: Value, required_alignment: Atom.Alignment, output_section_index: u8, src_loc: Module.SrcLoc, @@ -1125,7 +1119,7 @@ fn lowerConst( const sym_index = try self.addAtom(macho_file); - const res = try codegen.generateSymbol(&macho_file.base, src_loc, tv, &code_buffer, .{ + const res = try codegen.generateSymbol(&macho_file.base, src_loc, val, &code_buffer, .{ .none = {}, }, .{ .parent_atom_index = sym_index, @@ -1580,5 +1574,4 @@ const Symbol = @import("Symbol.zig"); const StringTable = @import("../StringTable.zig"); const Type = @import("../../type.zig").Type; const Value = @import("../../Value.zig"); -const TypedValue = @import("../../TypedValue.zig"); const ZigObject = @This(); diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index d092351c471a..d5900d2b16a1 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -15,7 +15,6 @@ const Air = @import("../Air.zig"); const Liveness = @import("../Liveness.zig"); const Type = @import("../type.zig").Type; const Value = @import("../Value.zig"); -const TypedValue = @import("../TypedValue.zig"); const std = @import("std"); const builtin = @import("builtin"); @@ -463,7 +462,7 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air: return self.updateFinish(decl_index); } -pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 { +pub fn lowerUnnamedConst(self: *Plan9, val: Value, decl_index: InternPool.DeclIndex) !u32 { const gpa = self.base.comp.gpa; _ = try self.seeDecl(decl_index); var code_buffer = std.ArrayList(u8).init(gpa); @@ -500,7 +499,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.De }; self.syms.items[info.sym_index.?] = sym; - const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), tv, &code_buffer, .{ + const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), val, &code_buffer, .{ .none = {}, }, .{ .parent_atom_index = new_atom_idx, @@ -539,10 +538,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: InternPool.DeclIndex) defer code_buffer.deinit(); const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val; // TODO we need the symbol index for symbol in the table of locals for the containing atom - const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ - .ty = decl.typeOf(mod), - .val = decl_val, - }, &code_buffer, .{ .none = {} }, .{ + const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), decl_val, &code_buffer, .{ .none = {} }, .{ .parent_atom_index = @as(Atom.Index, @intCast(atom_idx)), }); const code = switch (res) { @@ -1545,11 +1541,8 @@ pub fn lowerAnonDecl( // ... const gpa = self.base.comp.gpa; const gop = try self.anon_decls.getOrPut(gpa, decl_val); - const mod = self.base.comp.module.?; if (!gop.found_existing) { - const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); const val = Value.fromInterned(decl_val); - const tv = TypedValue{ .ty = ty, .val = val }; const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)}); const index = try self.createAtom(); @@ -1557,7 +1550,7 @@ pub fn lowerAnonDecl( gop.value_ptr.* = index; // we need to free name latex var code_buffer = std.ArrayList(u8).init(gpa); - const res = try codegen.generateSymbol(&self.base, src_loc, tv, &code_buffer, .{ .none = {} }, .{ .parent_atom_index = index }); + const res = try codegen.generateSymbol(&self.base, src_loc, val, &code_buffer, .{ .none = {} }, .{ .parent_atom_index = index }); const code = switch (res) { .ok => code_buffer.items, .fail => |em| return .{ .fail = em }, diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index c8fea56c1630..ce91beedae72 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -32,7 +32,7 @@ const Module = @import("../Module.zig"); const Object = @import("Wasm/Object.zig"); const Symbol = @import("Wasm/Symbol.zig"); const Type = @import("../type.zig").Type; -const TypedValue = @import("../TypedValue.zig"); +const Value = @import("../Value.zig"); const ZigObject = @import("Wasm/ZigObject.zig"); pub const Atom = @import("Wasm/Atom.zig"); @@ -1504,8 +1504,8 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { /// Lowers a constant typed value to a local symbol and atom. /// Returns the symbol index of the local /// The given `decl` is the parent decl whom owns the constant. -pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 { - return wasm.zigObjectPtr().?.lowerUnnamedConst(wasm, tv, decl_index); +pub fn lowerUnnamedConst(wasm: *Wasm, val: Value, decl_index: InternPool.DeclIndex) !u32 { + return wasm.zigObjectPtr().?.lowerUnnamedConst(wasm, val, decl_index); } /// Returns the symbol index from a symbol of which its flag is set global, diff --git a/src/link/Wasm/ZigObject.zig b/src/link/Wasm/ZigObject.zig index 293c088c669c..9bf7718d2b35 100644 --- a/src/link/Wasm/ZigObject.zig +++ b/src/link/Wasm/ZigObject.zig @@ -270,7 +270,7 @@ pub fn updateDecl( const res = try codegen.generateSymbol( &wasm_file.base, decl.srcLoc(mod), - .{ .ty = decl.typeOf(mod), .val = val }, + val, &code_writer, .none, .{ .parent_atom_index = @intFromEnum(atom.sym_index) }, @@ -444,15 +444,12 @@ pub fn lowerAnonDecl( const gpa = wasm_file.base.comp.gpa; const gop = try zig_object.anon_decls.getOrPut(gpa, decl_val); if (!gop.found_existing) { - const mod = wasm_file.base.comp.module.?; - const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); - const tv: TypedValue = .{ .ty = ty, .val = Value.fromInterned(decl_val) }; var name_buf: [32]u8 = undefined; const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ @intFromEnum(decl_val), }) catch unreachable; - switch (try zig_object.lowerConst(wasm_file, name, tv, src_loc)) { + switch (try zig_object.lowerConst(wasm_file, name, Value.fromInterned(decl_val), src_loc)) { .ok => |atom_index| zig_object.anon_decls.values()[gop.index] = atom_index, .fail => |em| return .{ .fail = em }, } @@ -472,10 +469,10 @@ pub fn lowerAnonDecl( /// Lowers a constant typed value to a local symbol and atom. /// Returns the symbol index of the local /// The given `decl` is the parent decl whom owns the constant. -pub fn lowerUnnamedConst(zig_object: *ZigObject, wasm_file: *Wasm, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 { +pub fn lowerUnnamedConst(zig_object: *ZigObject, wasm_file: *Wasm, val: Value, decl_index: InternPool.DeclIndex) !u32 { const gpa = wasm_file.base.comp.gpa; const mod = wasm_file.base.comp.module.?; - std.debug.assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions + std.debug.assert(val.typeOf(mod).zigTypeTag(mod) != .Fn); // cannot create local symbols for functions const decl = mod.declPtr(decl_index); const parent_atom_index = try zig_object.getOrCreateAtomForDecl(wasm_file, decl_index); @@ -487,7 +484,7 @@ pub fn lowerUnnamedConst(zig_object: *ZigObject, wasm_file: *Wasm, tv: TypedValu }); defer gpa.free(name); - switch (try zig_object.lowerConst(wasm_file, name, tv, decl.srcLoc(mod))) { + switch (try zig_object.lowerConst(wasm_file, name, val, decl.srcLoc(mod))) { .ok => |atom_index| { try wasm_file.getAtomPtr(parent_atom_index).locals.append(gpa, atom_index); return @intFromEnum(wasm_file.getAtom(atom_index).sym_index); @@ -505,10 +502,12 @@ const LowerConstResult = union(enum) { fail: *Module.ErrorMsg, }; -fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.SrcLoc) !LowerConstResult { +fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, val: Value, src_loc: Module.SrcLoc) !LowerConstResult { const gpa = wasm_file.base.comp.gpa; const mod = wasm_file.base.comp.module.?; + const ty = val.typeOf(mod); + // Create and initialize a new local symbol and atom const sym_index = try zig_object.allocateSymbol(gpa); const atom_index = try wasm_file.createAtom(sym_index, zig_object.index); @@ -517,7 +516,7 @@ fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, tv: Ty const code = code: { const atom = wasm_file.getAtomPtr(atom_index); - atom.alignment = tv.ty.abiAlignment(mod); + atom.alignment = ty.abiAlignment(mod); const segment_name = try std.mem.concat(gpa, u8, &.{ ".rodata.", name }); errdefer gpa.free(segment_name); zig_object.symbol(sym_index).* = .{ @@ -527,7 +526,7 @@ fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, tv: Ty .index = try zig_object.createDataSegment( gpa, segment_name, - tv.ty.abiAlignment(mod), + ty.abiAlignment(mod), ), .virtual_address = undefined, }; @@ -535,7 +534,7 @@ fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, tv: Ty const result = try codegen.generateSymbol( &wasm_file.base, src_loc, - tv, + val, &value_bytes, .none, .{ @@ -1242,7 +1241,6 @@ const Module = @import("../../Module.zig"); const StringTable = @import("../StringTable.zig"); const Symbol = @import("Symbol.zig"); const Type = @import("../../type.zig").Type; -const TypedValue = @import("../../TypedValue.zig"); const Value = @import("../../Value.zig"); const Wasm = @import("../Wasm.zig"); const ZigObject = @This(); diff --git a/src/type.zig b/src/type.zig index a382a5ad97bc..5d67f13cbd16 100644 --- a/src/type.zig +++ b/src/type.zig @@ -7,7 +7,6 @@ const Module = @import("Module.zig"); const Zcu = Module; const log = std.log.scoped(.Type); const target_util = @import("target.zig"); -const TypedValue = @import("TypedValue.zig"); const Sema = @import("Sema.zig"); const InternPool = @import("InternPool.zig"); const Alignment = InternPool.Alignment; From 2a245e3b78890e5d1b65492e51d9fe509ec35b3c Mon Sep 17 00:00:00 2001 From: mlugg Date: Tue, 26 Mar 2024 05:51:34 +0000 Subject: [PATCH 10/14] compiler: eliminate TypedValue The only logic which remained in this file was the Value printing logic. This has been moved into a new `print_value.zig`. --- CMakeLists.txt | 3 +- src/Sema.zig | 106 ++++++++++++------------ src/Value.zig | 6 +- src/arch/x86_64/CodeGen.zig | 7 +- src/codegen.zig | 10 +-- src/codegen/spirv.zig | 2 +- src/print_air.zig | 2 +- src/{TypedValue.zig => print_value.zig} | 80 ++++-------------- src/type.zig | 8 +- 9 files changed, 86 insertions(+), 138 deletions(-) rename src/{TypedValue.zig => print_value.zig} (81%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2722acf0a4a5..081872fbdfbc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -526,7 +526,6 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/src/Package/Fetch.zig" "${CMAKE_SOURCE_DIR}/src/RangeSet.zig" "${CMAKE_SOURCE_DIR}/src/Sema.zig" - "${CMAKE_SOURCE_DIR}/src/TypedValue.zig" "${CMAKE_SOURCE_DIR}/src/Value.zig" "${CMAKE_SOURCE_DIR}/src/arch/aarch64/CodeGen.zig" "${CMAKE_SOURCE_DIR}/src/arch/aarch64/Emit.zig" @@ -634,9 +633,11 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/src/main.zig" "${CMAKE_SOURCE_DIR}/src/mingw.zig" "${CMAKE_SOURCE_DIR}/src/musl.zig" + "${CMAKE_SOURCE_DIR}/src/mutable_value.zig" "${CMAKE_SOURCE_DIR}/src/print_air.zig" "${CMAKE_SOURCE_DIR}/src/print_env.zig" "${CMAKE_SOURCE_DIR}/src/print_targets.zig" + "${CMAKE_SOURCE_DIR}/src/print_value.zig" "${CMAKE_SOURCE_DIR}/src/print_zir.zig" "${CMAKE_SOURCE_DIR}/src/register_manager.zig" "${CMAKE_SOURCE_DIR}/src/target.zig" diff --git a/src/Sema.zig b/src/Sema.zig index 18f4e01dd248..d21fed6910ed 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2272,7 +2272,7 @@ fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: if (int_ty.zigTypeTag(mod) == .Vector) { const msg = msg: { const msg = try sema.errMsg(block, src, "overflow of vector type '{}' with value '{}'", .{ - int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod), + int_ty.fmt(sema.mod), val.fmtValue(sema.mod), }); errdefer msg.destroy(sema.gpa); try sema.errNote(block, src, msg, "when computing vector element at index '{d}'", .{vector_index}); @@ -2281,7 +2281,7 @@ fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: return sema.failWithOwnedErrorMsg(block, msg); } return sema.fail(block, src, "overflow of integer type '{}' with value '{}'", .{ - int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod), + int_ty.fmt(sema.mod), val.fmtValue(sema.mod), }); } @@ -2914,7 +2914,7 @@ fn createAnonymousDeclTypeNamed( return sema.createAnonymousDeclTypeNamed(block, src, val, .anon, anon_prefix, null); if (arg_i != 0) try writer.writeByte(','); - try writer.print("{}", .{arg_val.fmtValue(sema.typeOf(arg), sema.mod)}); + try writer.print("{}", .{arg_val.fmtValue(sema.mod)}); arg_i += 1; continue; @@ -3186,7 +3186,7 @@ fn zirEnumDecl( }).lazy; const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = conflict.prev_field_idx }).lazy; const msg = msg: { - const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(int_tag_ty, sema.mod)}); + const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(sema.mod)}); errdefer msg.destroy(gpa); try sema.errNote(block, other_field_src, msg, "other occurrence here", .{}); break :msg msg; @@ -3206,7 +3206,7 @@ fn zirEnumDecl( const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy; const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = conflict.prev_field_idx }).lazy; const msg = msg: { - const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(int_tag_ty, sema.mod)}); + const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(sema.mod)}); errdefer msg.destroy(gpa); try sema.errNote(block, other_field_src, msg, "other occurrence here", .{}); break :msg msg; @@ -3228,7 +3228,7 @@ fn zirEnumDecl( .range = if (has_tag_value) .value else .name, }).lazy; const msg = try sema.errMsg(block, value_src, "enumeration value '{}' too large for type '{}'", .{ - last_tag_val.?.fmtValue(int_tag_ty, mod), int_tag_ty.fmt(mod), + last_tag_val.?.fmtValue(mod), int_tag_ty.fmt(mod), }); return sema.failWithOwnedErrorMsg(block, msg); } @@ -4381,10 +4381,10 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. .input_index = len_idx, } }; try sema.errNote(block, a_src, msg, "length {} here", .{ - v.fmtValue(Type.usize, sema.mod), + v.fmtValue(sema.mod), }); try sema.errNote(block, arg_src, msg, "length {} here", .{ - arg_val.fmtValue(Type.usize, sema.mod), + arg_val.fmtValue(sema.mod), }); break :msg msg; }; @@ -5794,7 +5794,7 @@ fn zirCompileLog( const arg_ty = sema.typeOf(arg); if (try sema.resolveValueResolveLazy(arg)) |val| { try writer.print("@as({}, {})", .{ - arg_ty.fmt(mod), val.fmtValue(arg_ty, mod), + arg_ty.fmt(mod), val.fmtValue(mod), }); } else { try writer.print("@as({}, [runtime value])", .{arg_ty.fmt(mod)}); @@ -8880,7 +8880,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError return Air.internedToRef((try mod.getCoerced(int_val, dest_ty)).toIntern()); } return sema.fail(block, src, "int value '{}' out of range of non-exhaustive enum '{}'", .{ - int_val.fmtValue(sema.typeOf(operand), mod), dest_ty.fmt(mod), + int_val.fmtValue(mod), dest_ty.fmt(mod), }); } if (int_val.isUndef(mod)) { @@ -8888,7 +8888,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } if (!(try sema.enumHasInt(dest_ty, int_val))) { return sema.fail(block, src, "enum '{}' has no tag with value '{}'", .{ - dest_ty.fmt(mod), int_val.fmtValue(sema.typeOf(operand), mod), + dest_ty.fmt(mod), int_val.fmtValue(mod), }); } return Air.internedToRef((try mod.getCoerced(int_val, dest_ty)).toIntern()); @@ -13934,7 +13934,7 @@ fn zirShl( const rhs_elem = try rhs_val.elemValue(mod, i); if (rhs_elem.compareHetero(.gte, bit_value, mod)) { return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{ - rhs_elem.fmtValue(scalar_ty, mod), + rhs_elem.fmtValue(mod), i, scalar_ty.fmt(mod), }); @@ -13942,7 +13942,7 @@ fn zirShl( } } else if (rhs_val.compareHetero(.gte, bit_value, mod)) { return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ - rhs_val.fmtValue(scalar_ty, mod), + rhs_val.fmtValue(mod), scalar_ty.fmt(mod), }); } @@ -13953,14 +13953,14 @@ fn zirShl( const rhs_elem = try rhs_val.elemValue(mod, i); if (rhs_elem.compareHetero(.lt, try mod.intValue(scalar_rhs_ty, 0), mod)) { return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{ - rhs_elem.fmtValue(scalar_ty, mod), + rhs_elem.fmtValue(mod), i, }); } } } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) { return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{ - rhs_val.fmtValue(scalar_ty, mod), + rhs_val.fmtValue(mod), }); } } @@ -14099,7 +14099,7 @@ fn zirShr( const rhs_elem = try rhs_val.elemValue(mod, i); if (rhs_elem.compareHetero(.gte, bit_value, mod)) { return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{ - rhs_elem.fmtValue(scalar_ty, mod), + rhs_elem.fmtValue(mod), i, scalar_ty.fmt(mod), }); @@ -14107,7 +14107,7 @@ fn zirShr( } } else if (rhs_val.compareHetero(.gte, bit_value, mod)) { return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ - rhs_val.fmtValue(scalar_ty, mod), + rhs_val.fmtValue(mod), scalar_ty.fmt(mod), }); } @@ -14118,14 +14118,14 @@ fn zirShr( const rhs_elem = try rhs_val.elemValue(mod, i); if (rhs_elem.compareHetero(.lt, try mod.intValue(rhs_ty.childType(mod), 0), mod)) { return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{ - rhs_elem.fmtValue(scalar_ty, mod), + rhs_elem.fmtValue(mod), i, }); } } } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) { return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{ - rhs_val.fmtValue(scalar_ty, mod), + rhs_val.fmtValue(mod), }); } if (maybe_lhs_val) |lhs_val| { @@ -15046,7 +15046,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins block, src, "ambiguous coercion of division operands '{}' and '{}'; non-zero remainder '{}'", - .{ lhs_ty.fmt(mod), rhs_ty.fmt(mod), rem.fmtValue(resolved_type, mod) }, + .{ lhs_ty.fmt(mod), rhs_ty.fmt(mod), rem.fmtValue(mod) }, ); } } @@ -21094,7 +21094,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const enum_decl = mod.declPtr(enum_decl_index); const msg = msg: { const msg = try sema.errMsg(block, src, "no field with value '{}' in enum '{}'", .{ - val.fmtValue(enum_ty, sema.mod), enum_decl.name.fmt(ip), + val.fmtValue(sema.mod), enum_decl.name.fmt(ip), }); errdefer msg.destroy(sema.gpa); try mod.errNoteNonLazy(enum_decl.srcLoc(mod), msg, "declared here", .{}); @@ -21729,7 +21729,7 @@ fn reifyEnum( // TODO: better source location return sema.fail(block, src, "field '{}' with enumeration value '{}' is too large for backing int type '{}'", .{ field_name.fmt(ip), - field_value_val.fmtValue(Type.comptime_int, mod), + field_value_val.fmtValue(mod), tag_ty.fmt(mod), }); } @@ -21745,7 +21745,7 @@ fn reifyEnum( break :msg msg; }, .value => msg: { - const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{field_value_val.fmtValue(Type.comptime_int, mod)}); + const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{field_value_val.fmtValue(mod)}); errdefer msg.destroy(gpa); _ = conflict.prev_field_idx; // TODO: this note is incorrect try sema.errNote(block, src, msg, "other enum tag value here", .{}); @@ -22883,12 +22883,12 @@ fn ptrCastFull( return sema.failWithOwnedErrorMsg(block, msg: { const msg = if (src_info.sentinel == .none) blk: { break :blk try sema.errMsg(block, src, "destination pointer requires '{}' sentinel", .{ - Value.fromInterned(dest_info.sentinel).fmtValue(Type.fromInterned(dest_info.child), mod), + Value.fromInterned(dest_info.sentinel).fmtValue(mod), }); } else blk: { break :blk try sema.errMsg(block, src, "pointer sentinel '{}' cannot coerce into pointer sentinel '{}'", .{ - Value.fromInterned(src_info.sentinel).fmtValue(Type.fromInterned(src_info.child), mod), - Value.fromInterned(dest_info.sentinel).fmtValue(Type.fromInterned(dest_info.child), mod), + Value.fromInterned(src_info.sentinel).fmtValue(mod), + Value.fromInterned(dest_info.sentinel).fmtValue(mod), }); }; errdefer msg.destroy(sema.gpa); @@ -25285,10 +25285,10 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void const msg = try sema.errMsg(block, src, "non-matching @memcpy lengths", .{}); errdefer msg.destroy(sema.gpa); try sema.errNote(block, dest_src, msg, "length {} here", .{ - dest_len_val.fmtValue(Type.usize, sema.mod), + dest_len_val.fmtValue(sema.mod), }); try sema.errNote(block, src_src, msg, "length {} here", .{ - src_len_val.fmtValue(Type.usize, sema.mod), + src_len_val.fmtValue(sema.mod), }); break :msg msg; }; @@ -29162,7 +29162,7 @@ fn coerceExtra( // comptime-known integer to other number if (!(try sema.intFitsInType(val, dest_ty, null))) { if (!opts.report_err) return error.NotCoercible; - return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(mod), val.fmtValue(inst_ty, mod) }); + return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(mod), val.fmtValue(mod) }); } return switch (mod.intern_pool.indexToKey(val.toIntern())) { .undef => try mod.undefRef(dest_ty), @@ -29207,7 +29207,7 @@ fn coerceExtra( block, inst_src, "type '{}' cannot represent float value '{}'", - .{ dest_ty.fmt(mod), val.fmtValue(inst_ty, mod) }, + .{ dest_ty.fmt(mod), val.fmtValue(mod) }, ); } return Air.internedToRef(result_val.toIntern()); @@ -29578,11 +29578,11 @@ const InMemoryCoercionResult = union(enum) { .array_sentinel => |sentinel| { if (sentinel.actual.toIntern() != .unreachable_value) { try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{ - sentinel.actual.fmtValue(sentinel.ty, mod), sentinel.wanted.fmtValue(sentinel.ty, mod), + sentinel.actual.fmtValue(mod), sentinel.wanted.fmtValue(mod), }); } else { try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{ - sentinel.wanted.fmtValue(sentinel.ty, mod), + sentinel.wanted.fmtValue(mod), }); } break; @@ -29704,11 +29704,11 @@ const InMemoryCoercionResult = union(enum) { .ptr_sentinel => |sentinel| { if (sentinel.actual.toIntern() != .unreachable_value) { try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{ - sentinel.actual.fmtValue(sentinel.ty, mod), sentinel.wanted.fmtValue(sentinel.ty, mod), + sentinel.actual.fmtValue(mod), sentinel.wanted.fmtValue(mod), }); } else { try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{ - sentinel.wanted.fmtValue(sentinel.ty, mod), + sentinel.wanted.fmtValue(mod), }); } break; @@ -31708,7 +31708,7 @@ fn coerceEnumToUnion( if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| { const field_index = union_ty.unionTagFieldIndex(val, sema.mod) orelse { return sema.fail(block, inst_src, "union '{}' has no tag with value '{}'", .{ - union_ty.fmt(sema.mod), val.fmtValue(tag_ty, sema.mod), + union_ty.fmt(sema.mod), val.fmtValue(sema.mod), }); }; @@ -32928,8 +32928,8 @@ fn analyzeSlice( msg, "expected '{}', found '{}'", .{ - Value.zero_comptime_int.fmtValue(Type.comptime_int, mod), - start_value.fmtValue(Type.comptime_int, mod), + Value.zero_comptime_int.fmtValue(mod), + start_value.fmtValue(mod), }, ); break :msg msg; @@ -32945,8 +32945,8 @@ fn analyzeSlice( msg, "expected '{}', found '{}'", .{ - Value.one_comptime_int.fmtValue(Type.comptime_int, mod), - end_value.fmtValue(Type.comptime_int, mod), + Value.one_comptime_int.fmtValue(mod), + end_value.fmtValue(mod), }, ); break :msg msg; @@ -32959,7 +32959,7 @@ fn analyzeSlice( block, end_src, "end index {} out of bounds for slice of single-item pointer", - .{end_value.fmtValue(Type.comptime_int, mod)}, + .{end_value.fmtValue(mod)}, ); } } @@ -33054,8 +33054,8 @@ fn analyzeSlice( end_src, "end index {} out of bounds for array of length {}{s}", .{ - end_val.fmtValue(Type.usize, mod), - len_val.fmtValue(Type.usize, mod), + end_val.fmtValue(mod), + len_val.fmtValue(mod), sentinel_label, }, ); @@ -33099,7 +33099,7 @@ fn analyzeSlice( end_src, "end index {} out of bounds for slice of length {d}{s}", .{ - end_val.fmtValue(Type.usize, mod), + end_val.fmtValue(mod), try slice_val.sliceLen(sema), sentinel_label, }, @@ -33159,8 +33159,8 @@ fn analyzeSlice( start_src, "start index {} is larger than end index {}", .{ - start_val.fmtValue(Type.usize, mod), - end_val.fmtValue(Type.usize, mod), + start_val.fmtValue(mod), + end_val.fmtValue(mod), }, ); } @@ -33198,8 +33198,8 @@ fn analyzeSlice( const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); errdefer msg.destroy(sema.gpa); try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ - expected_sentinel.fmtValue(elem_ty, mod), - actual_sentinel.fmtValue(elem_ty, mod), + expected_sentinel.fmtValue(mod), + actual_sentinel.fmtValue(mod), }); break :msg msg; @@ -37213,7 +37213,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded const field_src = mod.fieldSrcLoc(union_type.decl, .{ .index = field_i }).lazy; const other_field_src = mod.fieldSrcLoc(union_type.decl, .{ .index = gop.index }).lazy; const msg = msg: { - const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{enum_tag_val.fmtValue(int_tag_ty, mod)}); + const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{enum_tag_val.fmtValue(mod)}); errdefer msg.destroy(gpa); try sema.errNote(&block_scope, other_field_src, msg, "other occurrence here", .{}); break :msg msg; @@ -38566,18 +38566,17 @@ fn intFromFloat( ) CompileError!Value { const mod = sema.mod; if (float_ty.zigTypeTag(mod) == .Vector) { - const elem_ty = float_ty.scalarType(mod); const result_data = try sema.arena.alloc(InternPool.Index, float_ty.vectorLen(mod)); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(sema.mod, i); - scalar.* = (try sema.intFromFloatScalar(block, src, elem_val, elem_ty, int_ty.scalarType(mod), mode)).toIntern(); + scalar.* = (try sema.intFromFloatScalar(block, src, elem_val, int_ty.scalarType(mod), mode)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = int_ty.toIntern(), .storage = .{ .elems = result_data }, } }))); } - return sema.intFromFloatScalar(block, src, val, float_ty, int_ty, mode); + return sema.intFromFloatScalar(block, src, val, int_ty, mode); } // float is expected to be finite and non-NaN @@ -38610,7 +38609,6 @@ fn intFromFloatScalar( block: *Block, src: LazySrcLoc, val: Value, - float_ty: Type, int_ty: Type, mode: IntFromFloatMode, ) CompileError!Value { @@ -38622,7 +38620,7 @@ fn intFromFloatScalar( block, src, "fractional component prevents float value '{}' from coercion to type '{}'", - .{ val.fmtValue(float_ty, mod), int_ty.fmt(mod) }, + .{ val.fmtValue(mod), int_ty.fmt(mod) }, ); const float = val.toFloat(f128, mod); @@ -38644,7 +38642,7 @@ fn intFromFloatScalar( if (!(try sema.intFitsInType(cti_result, int_ty, null))) { return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{ - val.fmtValue(float_ty, sema.mod), int_ty.fmt(sema.mod), + val.fmtValue(sema.mod), int_ty.fmt(sema.mod), }); } return mod.getCoerced(cti_result, int_ty); diff --git a/src/Value.zig b/src/Value.zig index 81b8583a84e4..b1230954ede5 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -8,9 +8,9 @@ const Target = std.Target; const Allocator = std.mem.Allocator; const Zcu = @import("Module.zig"); const Module = Zcu; -const TypedValue = @import("TypedValue.zig"); const Sema = @import("Sema.zig"); const InternPool = @import("InternPool.zig"); +const print_value = @import("print_value.zig"); const Value = @This(); ip_index: InternPool.Index, @@ -39,9 +39,9 @@ pub fn fmtDebug(val: Value) std.fmt.Formatter(dump) { return .{ .data = val }; } -pub fn fmtValue(val: Value, ty: Type, mod: *Module) std.fmt.Formatter(TypedValue.format) { +pub fn fmtValue(val: Value, mod: *Module) std.fmt.Formatter(print_value.format) { return .{ .data = .{ - .tv = .{ .ty = ty, .val = val }, + .val = val, .mod = mod, } }; } diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 680dce0b4868..1b584bfe53c1 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -17876,11 +17876,8 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { break :result null; }) orelse return self.fail("TODO implement airShuffle from {} and {} to {} with {}", .{ - lhs_ty.fmt(mod), rhs_ty.fmt(mod), dst_ty.fmt(mod), - Value.fromInterned(extra.mask).fmtValue( - Type.fromInterned(mod.intern_pool.typeOf(extra.mask)), - mod, - ), + lhs_ty.fmt(mod), rhs_ty.fmt(mod), dst_ty.fmt(mod), + Value.fromInterned(extra.mask).fmtValue(mod), }); return self.finishAir(inst, result, .{ extra.a, extra.b, .none }); } diff --git a/src/codegen.zig b/src/codegen.zig index 049b10b3082d..c5da0ebcb75c 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -185,9 +185,7 @@ pub fn generateSymbol( const target = mod.getTarget(); const endian = target.cpu.arch.endian(); - log.debug("generateSymbol: val = {}", .{ - val.fmtValue(ty, mod), - }); + log.debug("generateSymbol: val = {}", .{val.fmtValue(mod)}); if (val.isUndefDeep(mod)) { const abi_size = math.cast(usize, ty.abiSize(mod)) orelse return error.Overflow; @@ -862,7 +860,7 @@ fn genDeclRef( ) CodeGenError!GenResult { const zcu = lf.comp.module.?; const ty = val.typeOf(zcu); - log.debug("genDeclRef: val = {}", .{val.fmtValue(ty, zcu)}); + log.debug("genDeclRef: val = {}", .{val.fmtValue(zcu)}); const ptr_decl = zcu.declPtr(ptr_decl_index); const namespace = zcu.namespacePtr(ptr_decl.src_namespace); @@ -976,7 +974,7 @@ fn genUnnamedConst( ) CodeGenError!GenResult { const zcu = lf.comp.module.?; const gpa = lf.comp.gpa; - log.debug("genUnnamedConst: val = {}", .{val.fmtValue(val.typeOf(zcu), zcu)}); + log.debug("genUnnamedConst: val = {}", .{val.fmtValue(zcu)}); const local_sym_index = lf.lowerUnnamedConst(val, owner_decl_index) catch |err| { return GenResult.fail(gpa, src_loc, "lowering unnamed constant failed: {s}", .{@errorName(err)}); @@ -1016,7 +1014,7 @@ pub fn genTypedValue( const zcu = lf.comp.module.?; const ty = val.typeOf(zcu); - log.debug("genTypedValue: val = {}", .{val.fmtValue(ty, zcu)}); + log.debug("genTypedValue: val = {}", .{val.fmtValue(zcu)}); if (val.isUndef(zcu)) return GenResult.mcv(.undef); diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 3e560b0918e8..6b13f2623aa3 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -860,7 +860,7 @@ const DeclGen = struct { const val = arg_val; - log.debug("constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(ty, mod) }); + log.debug("constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(mod) }); if (val.isUndefDeep(mod)) { return self.spv.constUndef(result_ty_ref); } diff --git a/src/print_air.zig b/src/print_air.zig index 0c1beac3a85e..12e2825d4ef0 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -951,7 +951,7 @@ const Writer = struct { const ty = Type.fromInterned(mod.intern_pool.indexToKey(ip_index).typeOf()); try s.print("<{}, {}>", .{ ty.fmt(mod), - Value.fromInterned(ip_index).fmtValue(ty, mod), + Value.fromInterned(ip_index).fmtValue(mod), }); } else { return w.writeInstIndex(s, operand.toIndex().?, dies); diff --git a/src/TypedValue.zig b/src/print_value.zig similarity index 81% rename from src/TypedValue.zig rename to src/print_value.zig index 6947e4cad22a..f10fbbc2920f 100644 --- a/src/TypedValue.zig +++ b/src/print_value.zig @@ -9,17 +9,13 @@ const Module = Zcu; const Sema = @import("Sema.zig"); const InternPool = @import("InternPool.zig"); const Allocator = std.mem.Allocator; -const TypedValue = @This(); const Target = std.Target; -ty: Type, -val: Value, - const max_aggregate_items = 100; const max_string_len = 256; const FormatContext = struct { - tv: TypedValue, + val: Value, mod: *Module, }; @@ -31,7 +27,7 @@ pub fn format( ) !void { _ = options; comptime std.debug.assert(fmt.len == 0); - return ctx.tv.print(writer, 3, ctx.mod, null) catch |err| switch (err) { + return print(ctx.val, writer, 3, ctx.mod, null) catch |err| switch (err) { error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function error.ComptimeBreak, error.ComptimeReturn => unreachable, error.AnalysisFail, error.NeededSourceLocation => unreachable, // TODO: re-evaluate when we actually pass `opt_sema` @@ -40,7 +36,7 @@ pub fn format( } pub fn print( - tv: TypedValue, + val: Value, writer: anytype, level: u8, mod: *Module, @@ -48,7 +44,6 @@ pub fn print( opt_sema: ?*Sema, ) (@TypeOf(writer).Error || Module.CompileError)!void { const ip = &mod.intern_pool; - const val = tv.val; switch (ip.indexToKey(val.toIntern())) { .int_type, .ptr_type, @@ -99,10 +94,7 @@ pub fn print( .err_name => |err_name| try writer.print("error.{}", .{ err_name.fmt(ip), }), - .payload => |payload| try print(.{ - .ty = tv.ty.errorUnionPayload(mod), - .val = Value.fromInterned(payload), - }, writer, level, mod, opt_sema), + .payload => |payload| try print(Value.fromInterned(payload), writer, level, mod, opt_sema), }, .enum_literal => |enum_literal| try writer.print(".{}", .{ enum_literal.fmt(ip), @@ -117,10 +109,7 @@ pub fn print( try writer.writeAll("@enumFromInt(...)"); } try writer.writeAll("@enumFromInt("); - try print(.{ - .ty = Type.fromInterned(ip.typeOf(enum_tag.int)), - .val = Value.fromInterned(enum_tag.int), - }, writer, level - 1, mod, opt_sema); + try print(Value.fromInterned(enum_tag.int), writer, level - 1, mod, opt_sema); try writer.writeAll(")"); }, .empty_enum_value => try writer.writeAll("(empty enum value)"), @@ -139,10 +128,7 @@ pub fn print( } try printPtr(slice.ptr, writer, false, false, 0, level, mod, opt_sema); try writer.writeAll("[0.."); - try print(.{ - .ty = Type.usize, - .val = Value.fromInterned(slice.len), - }, writer, level - 1, mod, opt_sema); + try print(Value.fromInterned(slice.len), writer, level - 1, mod, opt_sema); try writer.writeAll("]"); }, .ptr => { @@ -159,10 +145,7 @@ pub fn print( }, .opt => |opt| switch (opt.val) { .none => try writer.writeAll("null"), - else => |payload| try print(.{ - .ty = tv.ty.childType(mod), - .val = Value.fromInterned(payload), - }, writer, level, mod, opt_sema), + else => |payload| try print(Value.fromInterned(payload), writer, level, mod, opt_sema), }, .aggregate => |aggregate| try printAggregate(val, aggregate, writer, level, mod, opt_sema), .un => |un| { @@ -171,25 +154,15 @@ pub fn print( return; } if (un.tag == .none) { - const backing_ty = try tv.ty.unionBackingType(mod); + const backing_ty = try val.typeOf(mod).unionBackingType(mod); try writer.print("@bitCast(@as({}, ", .{backing_ty.fmt(mod)}); - try print(.{ - .ty = backing_ty, - .val = Value.fromInterned(un.val), - }, writer, level - 1, mod, opt_sema); + try print(Value.fromInterned(un.val), writer, level - 1, mod, opt_sema); try writer.writeAll("))"); } else { try writer.writeAll(".{ "); - try print(.{ - .ty = tv.ty.unionTagTypeHypothetical(mod), - .val = Value.fromInterned(un.tag), - }, writer, level - 1, mod, opt_sema); + try print(Value.fromInterned(un.tag), writer, level - 1, mod, opt_sema); try writer.writeAll(" = "); - const field_ty = tv.ty.unionFieldType(Value.fromInterned(un.tag), mod).?; - try print(.{ - .ty = field_ty, - .val = Value.fromInterned(un.val), - }, writer, level - 1, mod, opt_sema); + try print(Value.fromInterned(un.val), writer, level - 1, mod, opt_sema); try writer.writeAll(" }"); } }, @@ -221,10 +194,7 @@ fn printAggregate( if (i != 0) try writer.writeAll(", "); const field_name = ty.structFieldName(@intCast(i), zcu).unwrap().?; try writer.print(".{i} = ", .{field_name.fmt(ip)}); - try print(.{ - .ty = ty.structFieldType(i, zcu), - .val = try val.fieldValue(zcu, i), - }, writer, level - 1, zcu, opt_sema); + try print(try val.fieldValue(zcu, i), writer, level - 1, zcu, opt_sema); } try writer.writeAll(" }"); return; @@ -240,7 +210,6 @@ fn printAggregate( else => unreachable, } - const elem_ty = ty.childType(zcu); const len = ty.arrayLen(zcu); try writer.writeAll(".{ "); @@ -248,10 +217,7 @@ fn printAggregate( const max_len = @min(len, max_aggregate_items); for (0..max_len) |i| { if (i != 0) try writer.writeAll(", "); - try print(.{ - .ty = elem_ty, - .val = try val.fieldValue(zcu, i), - }, writer, level - 1, zcu, opt_sema); + try print(try val.fieldValue(zcu, i), writer, level - 1, zcu, opt_sema); } if (len > max_aggregate_items) { try writer.writeAll(", ..."); @@ -286,17 +252,11 @@ fn printPtr( try writer.writeByteNTimes('(', leading_parens); if (force_type) { try writer.print("@as({}, @ptrFromInt(", .{Type.fromInterned(ptr.ty).fmt(zcu)}); - try print(.{ - .ty = Type.usize, - .val = Value.fromInterned(int), - }, writer, level - 1, zcu, opt_sema); + try print(Value.fromInterned(int), writer, level - 1, zcu, opt_sema); try writer.writeAll("))"); } else { try writer.writeAll("@ptrFromInt("); - try print(.{ - .ty = Type.usize, - .val = Value.fromInterned(int), - }, writer, level - 1, zcu, opt_sema); + try print(Value.fromInterned(int), writer, level - 1, zcu, opt_sema); try writer.writeAll(")"); } }, @@ -308,19 +268,13 @@ fn printPtr( .anon_decl => |anon| { const ty = Type.fromInterned(ip.typeOf(anon.val)); try writer.print("&@as({}, ", .{ty.fmt(zcu)}); - try print(.{ - .ty = ty, - .val = Value.fromInterned(anon.val), - }, writer, level - 1, zcu, opt_sema); + try print(Value.fromInterned(anon.val), writer, level - 1, zcu, opt_sema); try writer.writeAll(")"); }, .comptime_field => |val| { const ty = Type.fromInterned(ip.typeOf(val)); try writer.print("&@as({}, ", .{ty.fmt(zcu)}); - try print(.{ - .ty = ty, - .val = Value.fromInterned(val), - }, writer, level - 1, zcu, opt_sema); + try print(Value.fromInterned(val), writer, level - 1, zcu, opt_sema); try writer.writeAll(")"); }, .eu_payload => |base| { diff --git a/src/type.zig b/src/type.zig index 5d67f13cbd16..203ab4f63e68 100644 --- a/src/type.zig +++ b/src/type.zig @@ -187,8 +187,8 @@ pub const Type = struct { if (info.sentinel != .none) switch (info.flags.size) { .One, .C => unreachable, - .Many => try writer.print("[*:{}]", .{Value.fromInterned(info.sentinel).fmtValue(Type.fromInterned(info.child), mod)}), - .Slice => try writer.print("[:{}]", .{Value.fromInterned(info.sentinel).fmtValue(Type.fromInterned(info.child), mod)}), + .Many => try writer.print("[*:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod)}), + .Slice => try writer.print("[:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod)}), } else switch (info.flags.size) { .One => try writer.writeAll("*"), .Many => try writer.writeAll("[*]"), @@ -234,7 +234,7 @@ pub const Type = struct { } else { try writer.print("[{d}:{}]", .{ array_type.len, - Value.fromInterned(array_type.sentinel).fmtValue(Type.fromInterned(array_type.child), mod), + Value.fromInterned(array_type.sentinel).fmtValue(mod), }); try print(Type.fromInterned(array_type.child), writer, mod); } @@ -352,7 +352,7 @@ pub const Type = struct { try print(Type.fromInterned(field_ty), writer, mod); if (val != .none) { - try writer.print(" = {}", .{Value.fromInterned(val).fmtValue(Type.fromInterned(field_ty), mod)}); + try writer.print(" = {}", .{Value.fromInterned(val).fmtValue(mod)}); } } try writer.writeAll("}"); From 951fc09a7e174f8f7cb7384d1fd56dcae9ac73da Mon Sep 17 00:00:00 2001 From: mlugg Date: Tue, 26 Mar 2024 07:06:00 +0000 Subject: [PATCH 11/14] print_value: improve value printing Notably, this improves string printing from `@as(*[5:0]u8, &@as([5:0]u8, "hello".*))` to `@as(*[5:0]u8, "hello")`, omitting the pointless ref-deref pair. --- src/print_value.zig | 61 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/src/print_value.zig b/src/print_value.zig index f10fbbc2920f..25c20bbbbd10 100644 --- a/src/print_value.zig +++ b/src/print_value.zig @@ -102,11 +102,10 @@ pub fn print( .enum_tag => |enum_tag| { const enum_type = ip.loadEnumType(val.typeOf(mod).toIntern()); if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| { - try writer.print(".{i}", .{enum_type.names.get(ip)[tag_index].fmt(ip)}); - return; + return writer.print(".{i}", .{enum_type.names.get(ip)[tag_index].fmt(ip)}); } if (level == 0) { - try writer.writeAll("@enumFromInt(...)"); + return writer.writeAll("@enumFromInt(...)"); } try writer.writeAll("@enumFromInt("); try print(Value.fromInterned(enum_tag.int), writer, level - 1, mod, opt_sema); @@ -128,7 +127,11 @@ pub fn print( } try printPtr(slice.ptr, writer, false, false, 0, level, mod, opt_sema); try writer.writeAll("[0.."); - try print(Value.fromInterned(slice.len), writer, level - 1, mod, opt_sema); + if (level == 0) { + try writer.writeAll("(...)"); + } else { + try print(Value.fromInterned(slice.len), writer, level - 1, mod, opt_sema); + } try writer.writeAll("]"); }, .ptr => { @@ -147,7 +150,7 @@ pub fn print( .none => try writer.writeAll("null"), else => |payload| try print(Value.fromInterned(payload), writer, level, mod, opt_sema), }, - .aggregate => |aggregate| try printAggregate(val, aggregate, writer, level, mod, opt_sema), + .aggregate => |aggregate| try printAggregate(val, aggregate, writer, level, false, mod, opt_sema), .un => |un| { if (level == 0) { try writer.writeAll(".{ ... }"); @@ -175,6 +178,7 @@ fn printAggregate( aggregate: InternPool.Key.Aggregate, writer: anytype, level: u8, + is_ref: bool, zcu: *Zcu, opt_sema: ?*Sema, ) (@TypeOf(writer).Error || Module.CompileError)!void { @@ -185,6 +189,7 @@ fn printAggregate( const ty = Type.fromInterned(aggregate.ty); switch (ty.zigTypeTag(zcu)) { .Struct => if (!ty.isTuple(zcu)) { + if (is_ref) try writer.writeByte('&'); if (ty.structFieldCount(zcu) == 0) { return writer.writeAll(".{}"); } @@ -199,12 +204,29 @@ fn printAggregate( try writer.writeAll(" }"); return; }, - .Array => if (aggregate.storage == .bytes) { - return writer.print("\"{}\".*", .{std.zig.fmtEscapes(aggregate.storage.bytes)}); + .Array => if (aggregate.storage == .bytes and aggregate.storage.bytes.len > 0) { + const skip_terminator = aggregate.storage.bytes[aggregate.storage.bytes.len - 1] == 0; + const bytes = if (skip_terminator) b: { + break :b aggregate.storage.bytes[0 .. aggregate.storage.bytes.len - 1]; + } else aggregate.storage.bytes; + try writer.print("\"{}\"", .{std.zig.fmtEscapes(bytes)}); + if (!is_ref) try writer.writeAll(".*"); + return; } else if (ty.arrayLen(zcu) == 0) { + if (is_ref) try writer.writeByte('&'); return writer.writeAll(".{}"); + } else if (ty.arrayLen(zcu) == 1) one_byte_str: { + // The repr isn't `bytes`, but we might still be able to print this as a string + if (ty.childType(zcu).toIntern() != .u8_type) break :one_byte_str; + const elem_val = Value.fromInterned(aggregate.storage.values()[0]); + if (elem_val.isUndef(zcu)) break :one_byte_str; + const byte = elem_val.toUnsignedInt(zcu); + try writer.print("\"{}\"", .{std.zig.fmtEscapes(&.{@intCast(byte)})}); + if (!is_ref) try writer.writeAll(".*"); + return; }, .Vector => if (ty.arrayLen(zcu) == 0) { + if (is_ref) try writer.writeByte('&'); return writer.writeAll(".{}"); }, else => unreachable, @@ -212,6 +234,7 @@ fn printAggregate( const len = ty.arrayLen(zcu); + if (is_ref) try writer.writeByte('&'); try writer.writeAll(".{ "); const max_len = @min(len, max_aggregate_items); @@ -246,6 +269,9 @@ fn printPtr( .ptr => |ptr| ptr, else => unreachable, }; + if (level == 0) { + return writer.writeAll("&..."); + } switch (ptr.addr) { .int => |int| { if (force_addrof) try writer.writeAll("&"); @@ -265,11 +291,22 @@ fn printPtr( try zcu.declPtr(index).renderFullyQualifiedName(zcu, writer); }, .comptime_alloc => try writer.writeAll("&(comptime alloc)"), - .anon_decl => |anon| { - const ty = Type.fromInterned(ip.typeOf(anon.val)); - try writer.print("&@as({}, ", .{ty.fmt(zcu)}); - try print(Value.fromInterned(anon.val), writer, level - 1, zcu, opt_sema); - try writer.writeAll(")"); + .anon_decl => |anon| switch (ip.indexToKey(anon.val)) { + .aggregate => |aggregate| try printAggregate( + Value.fromInterned(anon.val), + aggregate, + writer, + level - 1, + true, + zcu, + opt_sema, + ), + else => { + const ty = Type.fromInterned(ip.typeOf(anon.val)); + try writer.print("&@as({}, ", .{ty.fmt(zcu)}); + try print(Value.fromInterned(anon.val), writer, level - 1, zcu, opt_sema); + try writer.writeAll(")"); + }, }, .comptime_field => |val| { const ty = Type.fromInterned(ip.typeOf(val)); From bfc0c35689cd5781a3493bdd9c9b8d527847c7a2 Mon Sep 17 00:00:00 2001 From: mlugg Date: Tue, 26 Mar 2024 14:10:35 +0000 Subject: [PATCH 12/14] Value: fix underflow reading large `u64` values from packed memory --- src/Value.zig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Value.zig b/src/Value.zig index b1230954ede5..f8f23667e252 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -787,12 +787,12 @@ pub fn readFromPackedMemory( if (bits == 0) return mod.intValue(ty, 0); // Fast path for integers <= u64 - if (bits <= 64) { - return mod.intValue( - ty, - std.mem.readVarPackedInt(i64, buffer, bit_offset, bits, endian, int_info.signedness), - ); - } + if (bits <= 64) switch (int_info.signedness) { + // Use different backing types for unsigned vs signed to avoid the need to go via + // a larger type like `i128`. + .unsigned => return mod.intValue(ty, std.mem.readVarPackedInt(u64, buffer, bit_offset, bits, endian, .unsigned)), + .signed => return mod.intValue(ty, std.mem.readVarPackedInt(i64, buffer, bit_offset, bits, endian, .signed)), + }; // Slow path, we have to construct a big-int const abi_size = @as(usize, @intCast(ty.abiSize(mod))); From 845226a7c92edc4d6c35727023c63e4cbcf20bbb Mon Sep 17 00:00:00 2001 From: mlugg Date: Tue, 26 Mar 2024 07:07:17 +0000 Subject: [PATCH 13/14] cases: necessary changes from branch --- test/cases/compile_errors/compile_log.zig | 2 +- .../compile_log_a_pointer_to_an_opaque_value.zig | 2 +- ...ify_type_for_exhaustive_enum_with_undefined_tag_type.zig | 2 +- .../reify_type_union_payload_is_undefined.zig | 2 +- test/cases/compile_errors/reify_type_with_undefined.zig | 6 +++--- test/cases/comptime_aggregate_print.zig | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/cases/compile_errors/compile_log.zig b/test/cases/compile_errors/compile_log.zig index 444d09101797..6a14b78b173a 100644 --- a/test/cases/compile_errors/compile_log.zig +++ b/test/cases/compile_errors/compile_log.zig @@ -21,7 +21,7 @@ export fn baz() void { // // Compile Log Output: // @as(*const [5:0]u8, "begin") -// @as(*const [1:0]u8, "a"), @as(i32, 12), @as(*const [1:0]u8, "b"), @as([]const u8, "hi") +// @as(*const [1:0]u8, "a"), @as(i32, 12), @as(*const [1:0]u8, "b"), @as([]const u8, "hi"[0..2]) // @as(*const [3:0]u8, "end") // @as(comptime_int, 4) // @as(*const [5:0]u8, "begin") diff --git a/test/cases/compile_errors/compile_log_a_pointer_to_an_opaque_value.zig b/test/cases/compile_errors/compile_log_a_pointer_to_an_opaque_value.zig index 4f79da9fb1af..32076d3705e1 100644 --- a/test/cases/compile_errors/compile_log_a_pointer_to_an_opaque_value.zig +++ b/test/cases/compile_errors/compile_log_a_pointer_to_an_opaque_value.zig @@ -9,4 +9,4 @@ export fn entry() void { // :2:5: error: found compile log statement // // Compile Log Output: -// @as(*const anyopaque, (function 'entry')) +// @as(*const anyopaque, &tmp.entry) diff --git a/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig index 5d5294ba301e..fc8f3e1797e8 100644 --- a/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig +++ b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig @@ -14,4 +14,4 @@ export fn entry() void { // backend=stage2 // target=native // -// :1:13: error: use of undefined value here causes undefined behavior +// :1:20: error: use of undefined value here causes undefined behavior diff --git a/test/cases/compile_errors/reify_type_union_payload_is_undefined.zig b/test/cases/compile_errors/reify_type_union_payload_is_undefined.zig index 886d443a00c0..d9eea7dcd416 100644 --- a/test/cases/compile_errors/reify_type_union_payload_is_undefined.zig +++ b/test/cases/compile_errors/reify_type_union_payload_is_undefined.zig @@ -9,4 +9,4 @@ comptime { // backend=stage2 // target=native // -// :1:13: error: use of undefined value here causes undefined behavior +// :1:20: error: use of undefined value here causes undefined behavior diff --git a/test/cases/compile_errors/reify_type_with_undefined.zig b/test/cases/compile_errors/reify_type_with_undefined.zig index e3daa316e313..4d5f18419499 100644 --- a/test/cases/compile_errors/reify_type_with_undefined.zig +++ b/test/cases/compile_errors/reify_type_with_undefined.zig @@ -28,6 +28,6 @@ comptime { // backend=stage2 // target=native // -// :2:9: error: use of undefined value here causes undefined behavior -// :5:9: error: use of undefined value here causes undefined behavior -// :17:9: error: use of undefined value here causes undefined behavior +// :2:16: error: use of undefined value here causes undefined behavior +// :5:16: error: use of undefined value here causes undefined behavior +// :17:16: error: use of undefined value here causes undefined behavior diff --git a/test/cases/comptime_aggregate_print.zig b/test/cases/comptime_aggregate_print.zig index d8bb049a0063..88206398b030 100644 --- a/test/cases/comptime_aggregate_print.zig +++ b/test/cases/comptime_aggregate_print.zig @@ -31,5 +31,5 @@ pub fn main() !void {} // :20:5: error: found compile log statement // // Compile Log Output: -// @as([]i32, .{ (reinterpreted data) }) -// @as([]i32, .{ (reinterpreted data) }) +// @as([]i32, &(comptime alloc).buf[0..2]) +// @as([]i32, &(comptime alloc).buf[0..2]) From 513254956525f8f970e972f6973ab4df0b19d06a Mon Sep 17 00:00:00 2001 From: mlugg Date: Tue, 26 Mar 2024 21:35:21 +0000 Subject: [PATCH 14/14] Zcu: remove some unused functions --- src/Module.zig | 50 -------------------------------------------------- 1 file changed, 50 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index df39a2a869f9..d4a4522441cd 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -425,14 +425,6 @@ pub const Decl = struct { return @as(i32, @bitCast(node_index)) - @as(i32, @bitCast(decl.src_node)); } - pub fn tokSrcLoc(decl: Decl, token_index: Ast.TokenIndex) LazySrcLoc { - return .{ .token_offset = token_index - decl.srcToken() }; - } - - pub fn nodeSrcLoc(decl: Decl, node_index: Ast.Node.Index) LazySrcLoc { - return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(node_index)); - } - pub fn srcLoc(decl: Decl, zcu: *Zcu) SrcLoc { return decl.nodeOffsetSrcLoc(0, zcu); } @@ -445,16 +437,6 @@ pub const Decl = struct { }; } - pub fn srcToken(decl: Decl, zcu: *Zcu) Ast.TokenIndex { - const tree = &decl.getFileScope(zcu).tree; - return tree.firstToken(decl.src_node); - } - - pub fn srcByteOffset(decl: Decl, zcu: *Zcu) u32 { - const tree = &decl.getFileScope(zcu).tree; - return tree.tokens.items(.start)[decl.srcToken()]; - } - pub fn renderFullyQualifiedName(decl: Decl, zcu: *Zcu, writer: anytype) !void { if (decl.name_fully_qualified) { try writer.print("{}", .{decl.name.fmt(&zcu.intern_pool)}); @@ -486,22 +468,6 @@ pub const Decl = struct { return decl.val; } - /// If the Decl owns its value and it is a struct, return it, - /// otherwise null. - pub fn getOwnedStruct(decl: Decl, zcu: *Zcu) ?InternPool.Key.StructType { - if (!decl.owns_tv) return null; - if (decl.val.ip_index == .none) return null; - return zcu.typeToStruct(decl.val.toType()); - } - - /// If the Decl owns its value and it is a union, return it, - /// otherwise null. - pub fn getOwnedUnion(decl: Decl, zcu: *Zcu) ?InternPool.LoadedUnionType { - if (!decl.owns_tv) return null; - if (decl.val.ip_index == .none) return null; - return zcu.typeToUnion(decl.val.toType()); - } - pub fn getOwnedFunction(decl: Decl, zcu: *Zcu) ?InternPool.Key.Func { const i = decl.getOwnedFunctionIndex(); if (i == .none) return null; @@ -4427,22 +4393,6 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void } } -/// This function is exclusively called for anonymous decls. -/// All resources referenced by anonymous decls are owned by InternPool -/// so there is no cleanup to do here. -pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void { - const gpa = mod.gpa; - const ip = &mod.intern_pool; - - ip.destroyDecl(gpa, decl_index); - - if (mod.emit_h) |mod_emit_h| { - const decl_emit_h = mod_emit_h.declPtr(decl_index); - decl_emit_h.fwd_decl.deinit(gpa); - decl_emit_h.* = undefined; - } -} - /// Cancel the creation of an anon decl and delete any references to it. /// If other decls depend on this decl, they must be aborted first. pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void {