From 593130ce0a4b06185fcb4806f8330857a1da9f92 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 22 Mar 2022 00:23:54 -0700 Subject: [PATCH 1/3] stage2: lazy `@alignOf` Add a `target` parameter to every function that deals with Type and Value. --- src/Compilation.zig | 4 +- src/Module.zig | 52 +-- src/RangeSet.zig | 31 +- src/Sema.zig | 848 +++++++++++++++++++++-------------- src/TypedValue.zig | 57 ++- src/arch/aarch64/CodeGen.zig | 33 +- src/arch/arm/CodeGen.zig | 24 +- src/arch/arm/Emit.zig | 5 +- src/arch/riscv64/CodeGen.zig | 25 +- src/arch/wasm/CodeGen.zig | 35 +- src/arch/x86_64/CodeGen.zig | 20 +- src/arch/x86_64/Emit.zig | 4 +- src/codegen.zig | 35 +- src/codegen/c.zig | 57 ++- src/codegen/llvm.zig | 106 ++--- src/codegen/spirv.zig | 18 +- src/link.zig | 4 +- src/link/C.zig | 8 +- src/link/Dwarf.zig | 24 +- src/link/MachO.zig | 19 +- src/print_air.zig | 12 +- src/type.zig | 746 +++++++++++++++++++----------- src/value.zig | 464 ++++++++++--------- test/behavior.zig | 2 +- 24 files changed, 1575 insertions(+), 1058 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 64848659a7..e8b1ebb145 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2781,7 +2781,9 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress .error_msg = null, .decl = decl, .fwd_decl = fwd_decl.toManaged(gpa), - .typedefs = c_codegen.TypedefMap.init(gpa), + .typedefs = c_codegen.TypedefMap.initContext(gpa, .{ + .target = comp.getTarget(), + }), .typedefs_arena = typedefs_arena.allocator(), }; defer dg.fwd_decl.deinit(); diff --git a/src/Module.zig b/src/Module.zig index d537a4cf5a..4164c2659c 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -146,6 +146,8 @@ const MonomorphedFuncsSet = std.HashMapUnmanaged( ); const MonomorphedFuncsContext = struct { + target: Target, + pub fn eql(ctx: @This(), a: *Fn, b: *Fn) bool { _ = ctx; return a == b; @@ -153,7 +155,6 @@ const MonomorphedFuncsContext = struct { /// Must match `Sema.GenericCallAdapter.hash`. pub fn hash(ctx: @This(), key: *Fn) u64 { - _ = ctx; var hasher = std.hash.Wyhash.init(0); // The generic function Decl is guaranteed to be the first dependency @@ -168,7 +169,7 @@ const MonomorphedFuncsContext = struct { const generic_ty_info = generic_owner_decl.ty.fnInfo(); for (generic_ty_info.param_types) |param_ty, i| { if (generic_ty_info.paramIsComptime(i) and param_ty.tag() != .generic_poison) { - comptime_args[i].val.hash(param_ty, &hasher); + comptime_args[i].val.hash(param_ty, &hasher, ctx.target); } } @@ -184,6 +185,8 @@ pub const MemoizedCallSet = std.HashMapUnmanaged( ); pub const MemoizedCall = struct { + target: std.Target, + pub const Key = struct { func: *Fn, args: []TypedValue, @@ -195,14 +198,12 @@ pub const MemoizedCall = struct { }; pub fn eql(ctx: @This(), a: Key, b: Key) bool { - _ = ctx; - if (a.func != b.func) return false; assert(a.args.len == b.args.len); for (a.args) |a_arg, arg_i| { const b_arg = b.args[arg_i]; - if (!a_arg.eql(b_arg)) { + if (!a_arg.eql(b_arg, ctx.target)) { return false; } } @@ -212,8 +213,6 @@ pub const MemoizedCall = struct { /// Must match `Sema.GenericCallAdapter.hash`. pub fn hash(ctx: @This(), key: Key) u64 { - _ = ctx; - var hasher = std.hash.Wyhash.init(0); // The generic function Decl is guaranteed to be the first dependency @@ -223,7 +222,7 @@ pub const MemoizedCall = struct { // This logic must be kept in sync with the logic in `analyzeCall` that // computes the hash. for (key.args) |arg| { - arg.hash(&hasher); + arg.hash(&hasher, ctx.target); } return hasher.final(); @@ -1230,7 +1229,7 @@ pub const Union = struct { if (field.abi_align == 0) { break :a field.ty.abiAlignment(target); } else { - break :a @intCast(u32, field.abi_align.toUnsignedInt()); + break :a field.abi_align; } }; if (field_align > most_alignment) { @@ -3877,6 +3876,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { const bytes = try sema.resolveConstString(&block_scope, src, linksection_ref); break :blk (try decl_arena_allocator.dupeZ(u8, bytes)).ptr; }; + const target = sema.mod.getTarget(); const address_space = blk: { const addrspace_ctx: Sema.AddressSpaceContext = switch (decl_tv.val.tag()) { .function, .extern_fn => .function, @@ -3886,9 +3886,9 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { break :blk switch (decl.zirAddrspaceRef()) { .none => switch (addrspace_ctx) { - .function => target_util.defaultAddressSpace(sema.mod.getTarget(), .function), - .variable => target_util.defaultAddressSpace(sema.mod.getTarget(), .global_mutable), - .constant => target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant), + .function => target_util.defaultAddressSpace(target, .function), + .variable => target_util.defaultAddressSpace(target, .global_mutable), + .constant => target_util.defaultAddressSpace(target, .global_constant), else => unreachable, }, else => |addrspace_ref| try sema.analyzeAddrspace(&block_scope, src, addrspace_ref, addrspace_ctx), @@ -3904,13 +3904,15 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { if (decl.is_usingnamespace) { const ty_ty = Type.initTag(.type); - if (!decl_tv.ty.eql(ty_ty)) { - return sema.fail(&block_scope, src, "expected type, found {}", .{decl_tv.ty}); + if (!decl_tv.ty.eql(ty_ty, target)) { + return sema.fail(&block_scope, src, "expected type, found {}", .{ + decl_tv.ty.fmt(target), + }); } var buffer: Value.ToTypeBuffer = undefined; const ty = decl_tv.val.toType(&buffer); if (ty.getNamespace() == null) { - return sema.fail(&block_scope, src, "type {} has no namespace", .{ty}); + return sema.fail(&block_scope, src, "type {} has no namespace", .{ty.fmt(target)}); } decl.ty = ty_ty; @@ -3937,7 +3939,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { if (decl.has_tv) { prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits(); - type_changed = !decl.ty.eql(decl_tv.ty); + type_changed = !decl.ty.eql(decl_tv.ty, target); if (decl.getFunction()) |prev_func| { prev_is_inline = prev_func.state == .inline_only; } @@ -3986,7 +3988,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { } var type_changed = true; if (decl.has_tv) { - type_changed = !decl.ty.eql(decl_tv.ty); + type_changed = !decl.ty.eql(decl_tv.ty, target); decl.clearValues(gpa); } @@ -5054,22 +5056,6 @@ pub fn errNoteNonLazy( }; } -pub fn errorUnionType( - arena: Allocator, - error_set: Type, - payload: Type, -) Allocator.Error!Type { - assert(error_set.zigTypeTag() == .ErrorSet); - if (error_set.eql(Type.initTag(.anyerror)) and payload.eql(Type.initTag(.void))) { - return Type.initTag(.anyerror_void_error_union); - } - - return Type.Tag.error_union.create(arena, .{ - .error_set = error_set, - .payload = payload, - }); -} - pub fn getTarget(mod: Module) Target { return mod.comp.bin_file.options.target; } diff --git a/src/RangeSet.zig b/src/RangeSet.zig index e4d65353a9..79bd22fd7f 100644 --- a/src/RangeSet.zig +++ b/src/RangeSet.zig @@ -6,6 +6,7 @@ const RangeSet = @This(); const SwitchProngSrc = @import("Module.zig").SwitchProngSrc; ranges: std.ArrayList(Range), +target: std.Target, pub const Range = struct { first: Value, @@ -13,9 +14,10 @@ pub const Range = struct { src: SwitchProngSrc, }; -pub fn init(allocator: std.mem.Allocator) RangeSet { +pub fn init(allocator: std.mem.Allocator, target: std.Target) RangeSet { return .{ .ranges = std.ArrayList(Range).init(allocator), + .target = target, }; } @@ -30,8 +32,12 @@ pub fn add( ty: Type, src: SwitchProngSrc, ) !?SwitchProngSrc { + const target = self.target; + for (self.ranges.items) |range| { - if (last.compare(.gte, range.first, ty) and first.compare(.lte, range.last, ty)) { + if (last.compare(.gte, range.first, ty, target) and + first.compare(.lte, range.last, ty, target)) + { return range.src; // They overlap. } } @@ -43,19 +49,26 @@ pub fn add( return null; } +const LessThanContext = struct { ty: Type, target: std.Target }; + /// Assumes a and b do not overlap -fn lessThan(ty: Type, a: Range, b: Range) bool { - return a.first.compare(.lt, b.first, ty); +fn lessThan(ctx: LessThanContext, a: Range, b: Range) bool { + return a.first.compare(.lt, b.first, ctx.ty, ctx.target); } pub fn spans(self: *RangeSet, first: Value, last: Value, ty: Type) !bool { if (self.ranges.items.len == 0) return false; - std.sort.sort(Range, self.ranges.items, ty, lessThan); + const target = self.target; - if (!self.ranges.items[0].first.eql(first, ty) or - !self.ranges.items[self.ranges.items.len - 1].last.eql(last, ty)) + std.sort.sort(Range, self.ranges.items, LessThanContext{ + .ty = ty, + .target = target, + }, lessThan); + + if (!self.ranges.items[0].first.eql(first, ty, target) or + !self.ranges.items[self.ranges.items.len - 1].last.eql(last, ty, target)) { return false; } @@ -71,10 +84,10 @@ pub fn spans(self: *RangeSet, first: Value, last: Value, ty: Type) !bool { const prev = self.ranges.items[i]; // prev.last + 1 == cur.first - try counter.copy(prev.last.toBigInt(&space)); + try counter.copy(prev.last.toBigInt(&space, target)); try counter.addScalar(counter.toConst(), 1); - const cur_start_int = cur.first.toBigInt(&space); + const cur_start_int = cur.first.toBigInt(&space, target); if (!cur_start_int.eq(counter.toConst())) { return false; } diff --git a/src/Sema.zig b/src/Sema.zig index 2a3eff928b..5e344bb7d0 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1303,7 +1303,8 @@ pub fn resolveConstString( const wanted_type = Type.initTag(.const_slice_u8); const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); const val = try sema.resolveConstValue(block, src, coerced_inst); - return val.toAllocatedBytes(wanted_type, sema.arena); + const target = sema.mod.getTarget(); + return val.toAllocatedBytes(wanted_type, sema.arena, target); } pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type { @@ -1457,19 +1458,29 @@ fn failWithDivideByZero(sema: *Sema, block: *Block, src: LazySrcLoc) CompileErro } fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: Type, rhs_ty: Type) CompileError { - return sema.fail(block, src, "remainder division with '{}' and '{}': signed integers and floats must use @rem or @mod", .{ lhs_ty, rhs_ty }); + const target = sema.mod.getTarget(); + return sema.fail(block, src, "remainder division with '{}' and '{}': signed integers and floats must use @rem or @mod", .{ + lhs_ty.fmt(target), rhs_ty.fmt(target), + }); } fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, optional_ty: Type) CompileError { - return sema.fail(block, src, "expected optional type, found {}", .{optional_ty}); + const target = sema.mod.getTarget(); + return sema.fail(block, src, "expected optional type, found {}", .{optional_ty.fmt(target)}); } fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { - return sema.fail(block, src, "type '{}' does not support array initialization syntax", .{ty}); + const target = sema.mod.getTarget(); + return sema.fail(block, src, "type '{}' does not support array initialization syntax", .{ + ty.fmt(target), + }); } fn failWithStructInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { - return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{ty}); + const target = sema.mod.getTarget(); + return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{ + ty.fmt(target), + }); } fn failWithErrorSetCodeMissing( @@ -1479,8 +1490,9 @@ fn failWithErrorSetCodeMissing( dest_err_set_ty: Type, src_err_set_ty: Type, ) CompileError { + const target = sema.mod.getTarget(); return sema.fail(block, src, "expected type '{}', found type '{}'", .{ - dest_err_set_ty, src_err_set_ty, + dest_err_set_ty.fmt(target), src_err_set_ty.fmt(target), }); } @@ -1578,8 +1590,8 @@ fn resolveInt( const air_inst = sema.resolveInst(zir_ref); const coerced = try sema.coerce(block, dest_ty, air_inst, src); const val = try sema.resolveConstValue(block, src, coerced); - - return val.toUnsignedInt(); + const target = sema.mod.getTarget(); + return val.toUnsignedInt(target); } // Returns a compile error if the value has tag `variable`. See `resolveInstValue` for @@ -1864,6 +1876,7 @@ fn createTypeName( }, .parent => return sema.gpa.dupeZ(u8, mem.sliceTo(block.src_decl.name, 0)), .func => { + const target = sema.mod.getTarget(); const fn_info = sema.code.getFnInfo(sema.func.?.zir_body_inst); const zir_tags = sema.code.instructions.items(.tag); @@ -1881,7 +1894,7 @@ fn createTypeName( const arg_val = sema.resolveConstMaybeUndefVal(block, .unneeded, arg) catch unreachable; if (arg_i != 0) try buf.appendSlice(","); - try buf.writer().print("{}", .{arg_val.fmtValue(sema.typeOf(arg))}); + try buf.writer().print("{}", .{arg_val.fmtValue(sema.typeOf(arg), target)}); arg_i += 1; continue; @@ -2045,6 +2058,7 @@ fn zirEnumDecl( enum_obj.tag_ty_inferred = true; } } + const target = mod.getTarget(); try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| { @@ -2053,6 +2067,7 @@ fn zirEnumDecl( if (any_values) { try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{ .ty = enum_obj.tag_ty, + .target = target, }); } @@ -2102,16 +2117,18 @@ fn zirEnumDecl( const copied_tag_val = try tag_val.copy(new_decl_arena_allocator); enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{ .ty = enum_obj.tag_ty, + .target = target, }); } else if (any_values) { const tag_val = if (last_tag_val) |val| - try val.intAdd(Value.one, enum_obj.tag_ty, sema.arena) + try val.intAdd(Value.one, enum_obj.tag_ty, sema.arena, target) else Value.zero; last_tag_val = tag_val; const copied_tag_val = try tag_val.copy(new_decl_arena_allocator); enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{ .ty = enum_obj.tag_ty, + .target = target, }); } } @@ -2417,13 +2434,14 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE else object_ty; + const target = sema.mod.getTarget(); if (!array_ty.isIndexable()) { const msg = msg: { const msg = try sema.errMsg( block, src, "type '{}' does not support indexing", - .{array_ty}, + .{array_ty.fmt(target)}, ); errdefer msg.destroy(sema.gpa); try sema.errNote( @@ -3346,8 +3364,9 @@ fn failWithBadMemberAccess( else => unreachable, }; const msg = msg: { + const target = sema.mod.getTarget(); const msg = try sema.errMsg(block, field_src, "{s} '{}' has no member named '{s}'", .{ - kw_name, agg_ty, field_name, + kw_name, agg_ty.fmt(target), field_name, }); errdefer msg.destroy(sema.gpa); try sema.addDeclaredHereNote(msg, agg_ty); @@ -3680,6 +3699,7 @@ fn zirCompileLog( const src_node = extra.data.src_node; const src: LazySrcLoc = .{ .node_offset = src_node }; const args = sema.code.refSlice(extra.end, extended.small); + const target = sema.mod.getTarget(); for (args) |arg_ref, i| { if (i != 0) try writer.print(", ", .{}); @@ -3687,9 +3707,11 @@ fn zirCompileLog( const arg = sema.resolveInst(arg_ref); const arg_ty = sema.typeOf(arg); if (try sema.resolveMaybeUndefVal(block, src, arg)) |val| { - try writer.print("@as({}, {})", .{ arg_ty, val.fmtValue(arg_ty) }); + try writer.print("@as({}, {})", .{ + arg_ty.fmt(target), val.fmtValue(arg_ty, target), + }); } else { - try writer.print("@as({}, [runtime value])", .{arg_ty}); + try writer.print("@as({}, [runtime value])", .{arg_ty.fmt(target)}); } } try writer.print("\n", .{}); @@ -3982,9 +4004,10 @@ fn analyzeBlockBody( const type_src = src; // TODO: better source location const valid_rt = try sema.validateRunTimeType(child_block, type_src, resolved_ty, false); + const target = sema.mod.getTarget(); if (!valid_rt) { const msg = msg: { - const msg = try sema.errMsg(child_block, type_src, "value with comptime only type '{}' depends on runtime control flow", .{resolved_ty}); + const msg = try sema.errMsg(child_block, type_src, "value with comptime only type '{}' depends on runtime control flow", .{resolved_ty.fmt(target)}); errdefer msg.destroy(sema.gpa); const runtime_src = child_block.runtime_cond orelse child_block.runtime_loop.?; @@ -4012,7 +4035,7 @@ fn analyzeBlockBody( const br_operand = sema.air_instructions.items(.data)[br].br.operand; const br_operand_src = src; const br_operand_ty = sema.typeOf(br_operand); - if (br_operand_ty.eql(resolved_ty)) { + if (br_operand_ty.eql(resolved_ty, target)) { // No type coercion needed. continue; } @@ -4102,12 +4125,15 @@ pub fn analyzeExport( ) !void { const Export = Module.Export; const mod = sema.mod; + const target = mod.getTarget(); try mod.ensureDeclAnalyzed(exported_decl); // TODO run the same checks as we do for C ABI struct fields switch (exported_decl.ty.zigTypeTag()) { .Fn, .Int, .Enum, .Struct, .Union, .Array, .Float => {}, - else => return sema.fail(block, src, "unable to export type '{}'", .{exported_decl.ty}), + else => return sema.fail(block, src, "unable to export type '{}'", .{ + exported_decl.ty.fmt(target), + }), } const gpa = mod.gpa; @@ -4520,6 +4546,7 @@ const GenericCallAdapter = struct { precomputed_hash: u64, func_ty_info: Type.Payload.Function.Data, comptime_tvs: []const TypedValue, + target: std.Target, pub fn eql(ctx: @This(), adapted_key: void, other_key: *Module.Fn) bool { _ = adapted_key; @@ -4532,7 +4559,7 @@ const GenericCallAdapter = struct { for (other_comptime_args[0..ctx.func_ty_info.param_types.len]) |other_arg, i| { if (other_arg.ty.tag() != .generic_poison) { // anytype parameter - if (!other_arg.ty.eql(ctx.comptime_tvs[i].ty)) { + if (!other_arg.ty.eql(ctx.comptime_tvs[i].ty, ctx.target)) { return false; } } @@ -4543,7 +4570,7 @@ const GenericCallAdapter = struct { // but the callsite does not. return false; } - if (!other_arg.val.eql(ctx.comptime_tvs[i].val, other_arg.ty)) { + if (!other_arg.val.eql(ctx.comptime_tvs[i].val, other_arg.ty, ctx.target)) { return false; } } @@ -4588,6 +4615,7 @@ fn analyzeCall( const mod = sema.mod; const callee_ty = sema.typeOf(func); + const target = sema.mod.getTarget(); const func_ty = func_ty: { switch (callee_ty.zigTypeTag()) { .Fn => break :func_ty callee_ty, @@ -4599,7 +4627,7 @@ fn analyzeCall( }, else => {}, } - return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty}); + return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(target)}); }; const func_ty_info = func_ty.fnInfo(); @@ -4873,7 +4901,7 @@ fn analyzeCall( // bug generating invalid LLVM IR. const res2: Air.Inst.Ref = res2: { if (should_memoize and is_comptime_call) { - if (mod.memoized_calls.get(memoized_call_key)) |result| { + if (mod.memoized_calls.getContext(memoized_call_key, .{ .target = target })) |result| { const ty_inst = try sema.addType(fn_ret_ty); try sema.air_values.append(gpa, result.val); sema.air_instructions.set(block_inst, .{ @@ -4945,10 +4973,10 @@ fn analyzeCall( arg.* = try arg.*.copy(arena); } - try mod.memoized_calls.put(gpa, memoized_call_key, .{ + try mod.memoized_calls.putContext(gpa, memoized_call_key, .{ .val = try result_val.copy(arena), .arena = arena_allocator.state, - }); + }, .{ .target = sema.mod.getTarget() }); delete_memoized_call_key = false; } } @@ -5037,6 +5065,7 @@ fn instantiateGenericCall( std.hash.autoHash(&hasher, @ptrToInt(module_fn)); const comptime_tvs = try sema.arena.alloc(TypedValue, func_ty_info.param_types.len); + const target = sema.mod.getTarget(); for (func_ty_info.param_types) |param_ty, i| { const is_comptime = func_ty_info.paramIsComptime(i); @@ -5045,7 +5074,7 @@ fn instantiateGenericCall( const casted_arg = try sema.coerce(block, param_ty, uncasted_args[i], arg_src); if (try sema.resolveMaybeUndefVal(block, arg_src, casted_arg)) |arg_val| { if (param_ty.tag() != .generic_poison) { - arg_val.hash(param_ty, &hasher); + arg_val.hash(param_ty, &hasher, target); } comptime_tvs[i] = .{ // This will be different than `param_ty` in the case of `generic_poison`. @@ -5070,8 +5099,9 @@ fn instantiateGenericCall( .precomputed_hash = precomputed_hash, .func_ty_info = func_ty_info, .comptime_tvs = comptime_tvs, + .target = target, }; - const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter); + const gop = try mod.monomorphed_funcs.getOrPutContextAdapted(gpa, {}, adapter, .{ .target = target }); if (!gop.found_existing) { const new_module_func = try gpa.create(Module.Fn); gop.key_ptr.* = new_module_func; @@ -5255,7 +5285,7 @@ fn instantiateGenericCall( new_decl.analysis = .complete; log.debug("generic function '{s}' instantiated with type {}", .{ - new_decl.name, new_decl.ty, + new_decl.name, new_decl.ty.fmtDebug(), }); // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field @@ -5410,7 +5440,8 @@ fn zirArrayType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const bin_inst = sema.code.instructions.items(.data)[inst].bin; const len = try sema.resolveInt(block, .unneeded, bin_inst.lhs, Type.usize); const elem_type = try sema.resolveType(block, .unneeded, bin_inst.rhs); - const array_ty = try Type.array(sema.arena, len, null, elem_type); + const target = sema.mod.getTarget(); + const array_ty = try Type.array(sema.arena, len, null, elem_type, target); return sema.addType(array_ty); } @@ -5429,7 +5460,8 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil const uncasted_sentinel = sema.resolveInst(extra.sentinel); const sentinel = try sema.coerce(block, elem_type, uncasted_sentinel, sentinel_src); const sentinel_val = try sema.resolveConstValue(block, sentinel_src, sentinel); - const array_ty = try Type.array(sema.arena, len, sentinel_val, elem_type); + const target = sema.mod.getTarget(); + const array_ty = try Type.array(sema.arena, len, sentinel_val, elem_type, target); return sema.addType(array_ty); } @@ -5456,13 +5488,14 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; const error_set = try sema.resolveType(block, lhs_src, extra.lhs); const payload = try sema.resolveType(block, rhs_src, extra.rhs); + const target = sema.mod.getTarget(); if (error_set.zigTypeTag() != .ErrorSet) { return sema.fail(block, lhs_src, "expected error set type, found {}", .{ - error_set, + error_set.fmt(target), }); } - const err_union_ty = try Module.errorUnionType(sema.arena, error_set, payload); + const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, target); return sema.addType(err_union_ty); } @@ -5520,9 +5553,10 @@ fn zirIntToError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; const op = sema.resolveInst(inst_data.operand); + const target = sema.mod.getTarget(); if (try sema.resolveDefinedValue(block, operand_src, op)) |value| { - const int = value.toUnsignedInt(); + const int = value.toUnsignedInt(target); if (int > sema.mod.global_error_set.count() or int == 0) return sema.fail(block, operand_src, "integer value {d} represents no error", .{int}); const payload = try sema.arena.create(Value.Payload.Error); @@ -5569,10 +5603,11 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr } const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs); const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs); + const target = sema.mod.getTarget(); if (lhs_ty.zigTypeTag() != .ErrorSet) - return sema.fail(block, lhs_src, "expected error set type, found {}", .{lhs_ty}); + return sema.fail(block, lhs_src, "expected error set type, found {}", .{lhs_ty.fmt(target)}); if (rhs_ty.zigTypeTag() != .ErrorSet) - return sema.fail(block, rhs_src, "expected error set type, found {}", .{rhs_ty}); + return sema.fail(block, rhs_src, "expected error set type, found {}", .{rhs_ty.fmt(target)}); // Anything merged with anyerror is anyerror. if (lhs_ty.tag() == .anyerror or rhs_ty.tag() == .anyerror) { @@ -5618,6 +5653,7 @@ fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; const operand = sema.resolveInst(inst_data.operand); const operand_ty = sema.typeOf(operand); + const target = sema.mod.getTarget(); const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag()) { .Enum => operand, @@ -5634,7 +5670,7 @@ fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A }, else => { return sema.fail(block, operand_src, "expected enum or tagged union, found {}", .{ - operand_ty, + operand_ty.fmt(target), }); }, }; @@ -5668,7 +5704,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const operand = sema.resolveInst(extra.rhs); if (dest_ty.zigTypeTag() != .Enum) { - return sema.fail(block, dest_ty_src, "expected enum, found {}", .{dest_ty}); + return sema.fail(block, dest_ty_src, "expected enum, found {}", .{dest_ty.fmt(target)}); } if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |int_val| { @@ -5684,7 +5720,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A block, src, "enum '{}' has no tag with value {}", - .{ dest_ty, int_val.fmtValue(sema.typeOf(operand)) }, + .{ dest_ty.fmt(target), int_val.fmtValue(sema.typeOf(operand), target) }, ); errdefer msg.destroy(sema.gpa); try sema.mod.errNoteNonLazy( @@ -5733,13 +5769,13 @@ fn analyzeOptionalPayloadPtr( const optional_ptr_ty = sema.typeOf(optional_ptr); assert(optional_ptr_ty.zigTypeTag() == .Pointer); + const target = sema.mod.getTarget(); const opt_type = optional_ptr_ty.elemType(); if (opt_type.zigTypeTag() != .Optional) { - return sema.fail(block, src, "expected optional type, found {}", .{opt_type}); + return sema.fail(block, src, "expected optional type, found {}", .{opt_type.fmt(target)}); } const child_type = try opt_type.optionalChildAlloc(sema.arena); - const target = sema.mod.getTarget(); const child_pointer = try Type.ptr(sema.arena, target, .{ .pointee_type = child_type, .mutable = !optional_ptr_ty.isConstPtr(), @@ -5858,8 +5894,12 @@ fn zirErrUnionPayload( const operand = sema.resolveInst(inst_data.operand); const operand_src = src; const operand_ty = sema.typeOf(operand); - if (operand_ty.zigTypeTag() != .ErrorUnion) - return sema.fail(block, operand_src, "expected error union type, found '{}'", .{operand_ty}); + if (operand_ty.zigTypeTag() != .ErrorUnion) { + const target = sema.mod.getTarget(); + return sema.fail(block, operand_src, "expected error union type, found '{}'", .{ + operand_ty.fmt(target), + }); + } if (try sema.resolveDefinedValue(block, src, operand)) |val| { if (val.getError()) |name| { @@ -5906,11 +5946,14 @@ fn analyzeErrUnionPayloadPtr( const operand_ty = sema.typeOf(operand); assert(operand_ty.zigTypeTag() == .Pointer); - if (operand_ty.elemType().zigTypeTag() != .ErrorUnion) - return sema.fail(block, src, "expected error union type, found {}", .{operand_ty.elemType()}); + const target = sema.mod.getTarget(); + if (operand_ty.elemType().zigTypeTag() != .ErrorUnion) { + return sema.fail(block, src, "expected error union type, found {}", .{ + operand_ty.elemType().fmt(target), + }); + } const payload_ty = operand_ty.elemType().errorUnionPayload(); - const target = sema.mod.getTarget(); const operand_pointer_ty = try Type.ptr(sema.arena, target, .{ .pointee_type = payload_ty, .mutable = !operand_ty.isConstPtr(), @@ -5970,8 +6013,12 @@ fn zirErrUnionCode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro const src = inst_data.src(); const operand = sema.resolveInst(inst_data.operand); const operand_ty = sema.typeOf(operand); - if (operand_ty.zigTypeTag() != .ErrorUnion) - return sema.fail(block, src, "expected error union type, found '{}'", .{operand_ty}); + const target = sema.mod.getTarget(); + if (operand_ty.zigTypeTag() != .ErrorUnion) { + return sema.fail(block, src, "expected error union type, found '{}'", .{ + operand_ty.fmt(target), + }); + } const result_ty = operand_ty.errorUnionSet(); @@ -5995,8 +6042,12 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE const operand_ty = sema.typeOf(operand); assert(operand_ty.zigTypeTag() == .Pointer); - if (operand_ty.elemType().zigTypeTag() != .ErrorUnion) - return sema.fail(block, src, "expected error union type, found {}", .{operand_ty.elemType()}); + if (operand_ty.elemType().zigTypeTag() != .ErrorUnion) { + const target = sema.mod.getTarget(); + return sema.fail(block, src, "expected error union type, found {}", .{ + operand_ty.elemType().fmt(target), + }); + } const result_ty = operand_ty.elemType().errorUnionSet(); @@ -6019,8 +6070,12 @@ fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com const src = inst_data.src(); const operand = sema.resolveInst(inst_data.operand); const operand_ty = sema.typeOf(operand); - if (operand_ty.zigTypeTag() != .ErrorUnion) - return sema.fail(block, src, "expected error union type, found '{}'", .{operand_ty}); + const target = sema.mod.getTarget(); + if (operand_ty.zigTypeTag() != .ErrorUnion) { + return sema.fail(block, src, "expected error union type, found '{}'", .{ + operand_ty.fmt(target), + }); + } if (operand_ty.errorUnionPayload().zigTypeTag() != .Void) { return sema.fail(block, src, "expression value is ignored", .{}); } @@ -6205,7 +6260,7 @@ fn funcCommon( const fn_ty: Type = fn_ty: { const alignment: u32 = if (align_val.tag() == .null_value) 0 else a: { - const alignment = @intCast(u32, align_val.toUnsignedInt()); + const alignment = @intCast(u32, align_val.toUnsignedInt(target)); if (alignment == target_util.defaultFunctionAlignment(target)) { break :a 0; } else { @@ -6494,7 +6549,8 @@ fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const ptr = sema.resolveInst(inst_data.operand); const ptr_ty = sema.typeOf(ptr); if (!ptr_ty.isPtrAtRuntime()) { - return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty}); + const target = sema.mod.getTarget(); + return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(target)}); } if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |ptr_val| { return sema.addConstant(Type.usize, ptr_val); @@ -6652,6 +6708,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); const operand = sema.resolveInst(extra.rhs); + const target = sema.mod.getTarget(); const dest_is_comptime_float = switch (dest_ty.zigTypeTag()) { .ComptimeFloat => true, .Float => false, @@ -6659,7 +6716,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A block, dest_ty_src, "expected float type, found '{}'", - .{dest_ty}, + .{dest_ty.fmt(target)}, ), }; @@ -6670,7 +6727,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A block, operand_src, "expected float type, found '{}'", - .{operand_ty}, + .{operand_ty.fmt(target)}, ), } @@ -6680,7 +6737,6 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A if (dest_is_comptime_float) { return sema.fail(block, src, "unable to cast runtime value to 'comptime_float'", .{}); } - const target = sema.mod.getTarget(); const src_bits = operand_ty.floatBits(target); const dst_bits = dest_ty.floatBits(target); if (dst_bits >= src_bits) { @@ -6839,13 +6895,14 @@ fn zirSwitchCapture( const item = sema.resolveInst(scalar_prong.item); // Previous switch validation ensured this will succeed const item_val = sema.resolveConstValue(block, .unneeded, item) catch unreachable; + const target = sema.mod.getTarget(); switch (operand_ty.zigTypeTag()) { .Union => { const union_obj = operand_ty.cast(Type.Payload.Union).?.data; const enum_ty = union_obj.tag_ty; - const field_index_usize = enum_ty.enumTagFieldIndex(item_val).?; + const field_index_usize = enum_ty.enumTagFieldIndex(item_val, target).?; const field_index = @intCast(u32, field_index_usize); const field = union_obj.fields.values()[field_index]; @@ -6854,7 +6911,6 @@ fn zirSwitchCapture( if (is_ref) { assert(operand_is_ref); - const target = sema.mod.getTarget(); const field_ty_ptr = try Type.ptr(sema.arena, target, .{ .pointee_type = field.ty, .@"addrspace" = .generic, @@ -6894,7 +6950,7 @@ fn zirSwitchCapture( }, else => { return sema.fail(block, operand_src, "switch on type '{}' provides no capture value", .{ - operand_ty, + operand_ty.fmt(target), }); }, } @@ -6915,6 +6971,7 @@ fn zirSwitchCond( else operand_ptr; const operand_ty = sema.typeOf(operand); + const target = sema.mod.getTarget(); switch (operand_ty.zigTypeTag()) { .Type, @@ -6962,7 +7019,7 @@ fn zirSwitchCond( .Vector, .Frame, .AnyFrame, - => return sema.fail(block, src, "switch on type '{}'", .{operand_ty}), + => return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(target)}), } } @@ -7030,6 +7087,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError return sema.failWithOwnedErrorMsg(block, msg); } + const target = sema.mod.getTarget(); + // Validate for duplicate items, missing else prong, and invalid range. switch (operand_ty.zigTypeTag()) { .Enum => { @@ -7115,7 +7174,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError operand_ty.declSrcLoc(), msg, "enum '{}' declared here", - .{operand_ty}, + .{operand_ty.fmt(target)}, ); break :msg msg; }; @@ -7232,7 +7291,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError operand_ty.declSrcLoc(), msg, "error set '{}' declared here", - .{operand_ty}, + .{operand_ty.fmt(target)}, ); return sema.failWithOwnedErrorMsg(block, msg); } @@ -7260,7 +7319,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError }, .Union => return sema.fail(block, src, "TODO validate switch .Union", .{}), .Int, .ComptimeInt => { - var range_set = RangeSet.init(gpa); + var range_set = RangeSet.init(gpa, target); defer range_set.deinit(); var extra_index: usize = special.end; @@ -7333,7 +7392,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError var arena = std.heap.ArenaAllocator.init(gpa); defer arena.deinit(); - const target = sema.mod.getTarget(); const min_int = try operand_ty.minInt(arena.allocator(), target); const max_int = try operand_ty.maxInt(arena.allocator(), target); if (try range_set.spans(min_int, max_int, operand_ty)) { @@ -7437,11 +7495,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError block, src, "else prong required when switching on type '{}'", - .{operand_ty}, + .{operand_ty.fmt(target)}, ); } - var seen_values = ValueSrcMap.initContext(gpa, .{ .ty = operand_ty }); + var seen_values = ValueSrcMap.initContext(gpa, .{ + .ty = operand_ty, + .target = target, + }); defer seen_values.deinit(); var extra_index: usize = special.end; @@ -7505,7 +7566,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError .ComptimeFloat, .Float, => return sema.fail(block, operand_src, "invalid switch operand type '{}'", .{ - operand_ty, + operand_ty.fmt(target), }), } @@ -7555,7 +7616,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const item = sema.resolveInst(item_ref); // Validation above ensured these will succeed. const item_val = sema.resolveConstValue(&child_block, .unneeded, item) catch unreachable; - if (operand_val.eql(item_val, operand_ty)) { + if (operand_val.eql(item_val, operand_ty, target)) { return sema.resolveBlockBody(block, src, &child_block, body, inst, merges); } } @@ -7577,7 +7638,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const item = sema.resolveInst(item_ref); // Validation above ensured these will succeed. const item_val = sema.resolveConstValue(&child_block, .unneeded, item) catch unreachable; - if (operand_val.eql(item_val, operand_ty)) { + if (operand_val.eql(item_val, operand_ty, target)) { return sema.resolveBlockBody(block, src, &child_block, body, inst, merges); } } @@ -7592,8 +7653,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError // Validation above ensured these will succeed. const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first) catch unreachable; const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last) catch unreachable; - if (Value.compare(operand_val, .gte, first_tv.val, operand_ty) and - Value.compare(operand_val, .lte, last_tv.val, operand_ty)) + if (Value.compare(operand_val, .gte, first_tv.val, operand_ty, target) and + Value.compare(operand_val, .lte, last_tv.val, operand_ty, target)) { return sema.resolveBlockBody(block, src, &child_block, body, inst, merges); } @@ -7907,14 +7968,15 @@ fn validateSwitchItemEnum( switch_prong_src: Module.SwitchProngSrc, ) CompileError!void { const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); - const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val) orelse { + const target = sema.mod.getTarget(); + const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val, target) orelse { const msg = msg: { const src = switch_prong_src.resolve(sema.gpa, block.src_decl, src_node_offset, .none); const msg = try sema.errMsg( block, src, "enum '{}' has no tag with value '{}'", - .{ item_tv.ty, item_tv.val.fmtValue(item_tv.ty) }, + .{ item_tv.ty.fmt(target), item_tv.val.fmtValue(item_tv.ty, target) }, ); errdefer msg.destroy(sema.gpa); try sema.mod.errNoteNonLazy( @@ -8030,12 +8092,13 @@ fn validateSwitchNoRange( const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset }; const range_src: LazySrcLoc = .{ .node_offset_switch_range = src_node_offset }; + const target = sema.mod.getTarget(); const msg = msg: { const msg = try sema.errMsg( block, operand_src, "ranges not allowed when switching on type '{}'", - .{operand_ty}, + .{operand_ty.fmt(target)}, ); errdefer msg.destroy(sema.gpa); try sema.errNote( @@ -8058,6 +8121,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs); const field_name = try sema.resolveConstString(block, name_src, extra.rhs); const ty = try sema.resolveTypeFields(block, ty_src, unresolved_ty); + const target = sema.mod.getTarget(); const has_field = hf: { if (ty.isSlice()) { @@ -8080,7 +8144,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .Enum => ty.enumFields().contains(field_name), .Array => mem.eql(u8, field_name, "len"), else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{ - ty, + ty.fmt(target), }), }; }; @@ -8227,25 +8291,25 @@ fn zirShl( const val = switch (air_tag) { .shl_exact => val: { - const shifted = try lhs_val.shl(rhs_val, lhs_ty, sema.arena); + const shifted = try lhs_val.shl(rhs_val, lhs_ty, sema.arena, target); if (scalar_ty.zigTypeTag() == .ComptimeInt) { break :val shifted; } const int_info = scalar_ty.intInfo(target); - const truncated = try shifted.intTrunc(lhs_ty, sema.arena, int_info.signedness, int_info.bits); - if (truncated.compare(.eq, shifted, lhs_ty)) { + const truncated = try shifted.intTrunc(lhs_ty, sema.arena, int_info.signedness, int_info.bits, target); + if (truncated.compare(.eq, shifted, lhs_ty, target)) { break :val shifted; } return sema.addConstUndef(lhs_ty); }, .shl_sat => if (scalar_ty.zigTypeTag() == .ComptimeInt) - try lhs_val.shl(rhs_val, lhs_ty, sema.arena) + try lhs_val.shl(rhs_val, lhs_ty, sema.arena, target) else try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, target), .shl => if (scalar_ty.zigTypeTag() == .ComptimeInt) - try lhs_val.shl(rhs_val, lhs_ty, sema.arena) + try lhs_val.shl(rhs_val, lhs_ty, sema.arena, target) else try lhs_val.shlTrunc(rhs_val, lhs_ty, sema.arena, target), @@ -8296,6 +8360,7 @@ fn zirShr( const lhs_ty = sema.typeOf(lhs); const rhs_ty = sema.typeOf(rhs); try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); + const target = sema.mod.getTarget(); const runtime_src = if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| rs: { if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| { @@ -8308,12 +8373,12 @@ fn zirShr( } if (air_tag == .shr_exact) { // Detect if any ones would be shifted out. - const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val); + const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, target); if (!truncated.compareWithZero(.eq)) { return sema.addConstUndef(lhs_ty); } } - const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena); + const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, target); return sema.addConstant(lhs_ty, val); } else { // Even if lhs is not comptime known, we can still deduce certain things based @@ -8359,6 +8424,7 @@ fn zirBitwise( const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; + const target = sema.mod.getTarget(); if (!is_int) { return sema.fail(block, src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag()), @tagName(rhs_ty.zigTypeTag()) }); @@ -8367,9 +8433,9 @@ fn zirBitwise( if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| { if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| { const result_val = switch (air_tag) { - .bit_and => try lhs_val.bitwiseAnd(rhs_val, resolved_type, sema.arena), - .bit_or => try lhs_val.bitwiseOr(rhs_val, resolved_type, sema.arena), - .xor => try lhs_val.bitwiseXor(rhs_val, resolved_type, sema.arena), + .bit_and => try lhs_val.bitwiseAnd(rhs_val, resolved_type, sema.arena, target), + .bit_or => try lhs_val.bitwiseOr(rhs_val, resolved_type, sema.arena, target), + .xor => try lhs_val.bitwiseXor(rhs_val, resolved_type, sema.arena, target), else => unreachable, }; return sema.addConstant(resolved_type, result_val); @@ -8391,13 +8457,15 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. const operand = sema.resolveInst(inst_data.operand); const operand_type = sema.typeOf(operand); const scalar_type = operand_type.scalarType(); + const target = sema.mod.getTarget(); if (scalar_type.zigTypeTag() != .Int) { - return sema.fail(block, src, "unable to perform binary not operation on type '{}'", .{operand_type}); + return sema.fail(block, src, "unable to perform binary not operation on type '{}'", .{ + operand_type.fmt(target), + }); } if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { - const target = sema.mod.getTarget(); if (val.isUndef()) { return sema.addConstUndef(operand_type); } else if (operand_type.zigTypeTag() == .Vector) { @@ -8513,19 +8581,22 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; + const target = sema.mod.getTarget(); const lhs_info = (try sema.getArrayCatInfo(block, lhs_src, lhs)) orelse - return sema.fail(block, lhs_src, "expected array, found '{}'", .{lhs_ty}); + return sema.fail(block, lhs_src, "expected array, found '{}'", .{lhs_ty.fmt(target)}); const rhs_info = (try sema.getArrayCatInfo(block, rhs_src, rhs)) orelse - return sema.fail(block, rhs_src, "expected array, found '{}'", .{rhs_ty}); - if (!lhs_info.elem_type.eql(rhs_info.elem_type)) { - return sema.fail(block, rhs_src, "expected array of type '{}', found '{}'", .{ lhs_info.elem_type, rhs_ty }); + return sema.fail(block, rhs_src, "expected array, found '{}'", .{rhs_ty.fmt(target)}); + if (!lhs_info.elem_type.eql(rhs_info.elem_type, target)) { + return sema.fail(block, rhs_src, "expected array of type '{}', found '{}'", .{ + lhs_info.elem_type.fmt(target), rhs_ty.fmt(target), + }); } // When there is a sentinel mismatch, no sentinel on the result. The type system // will catch this if it is a problem. var res_sent: ?Value = null; if (rhs_info.sentinel != null and lhs_info.sentinel != null) { - if (rhs_info.sentinel.?.eql(lhs_info.sentinel.?, lhs_info.elem_type)) { + if (rhs_info.sentinel.?.eql(lhs_info.sentinel.?, lhs_info.elem_type, target)) { res_sent = lhs_info.sentinel.?; } } @@ -8586,6 +8657,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, inst: Air.Inst.Ref) !?Type.ArrayInfo { const t = sema.typeOf(inst); + const target = sema.mod.getTarget(); return switch (t.zigTypeTag()) { .Array => t.arrayInfo(), .Pointer => blk: { @@ -8595,7 +8667,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, inst: Air.Inst.R return Type.ArrayInfo{ .elem_type = t.childType(), .sentinel = t.sentinel(), - .len = val.sliceLen(), + .len = val.sliceLen(target), }; } if (ptrinfo.pointee_type.zigTypeTag() != .Array) return null; @@ -8691,9 +8763,10 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai if (lhs_ty.isTuple()) { return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor); } + const target = sema.mod.getTarget(); const mulinfo = (try sema.getArrayCatInfo(block, lhs_src, lhs)) orelse - return sema.fail(block, lhs_src, "expected array, found '{}'", .{lhs_ty}); + return sema.fail(block, lhs_src, "expected array, found '{}'", .{lhs_ty.fmt(target)}); const final_len_u64 = std.math.mul(u64, mulinfo.len, factor) catch return sema.fail(block, rhs_src, "operation results in overflow", .{}); @@ -8771,8 +8844,9 @@ fn zirNegate( const rhs_ty = sema.typeOf(rhs); const rhs_scalar_ty = rhs_ty.scalarType(); + const target = sema.mod.getTarget(); if (tag_override == .sub and rhs_scalar_ty.isUnsignedInt()) { - return sema.fail(block, src, "negation of type '{}'", .{rhs_ty}); + return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(target)}); } const lhs = if (rhs_ty.zigTypeTag() == .Vector) @@ -8824,15 +8898,14 @@ fn zirOverflowArithmetic( const ptr = sema.resolveInst(extra.ptr); const lhs_ty = sema.typeOf(lhs); + const target = sema.mod.getTarget(); // Note, the types of lhs/rhs (also for shifting)/ptr are already correct as ensured by astgen. const dest_ty = lhs_ty; if (dest_ty.zigTypeTag() != .Int) { - return sema.fail(block, src, "expected integer type, found '{}'", .{dest_ty}); + return sema.fail(block, src, "expected integer type, found '{}'", .{dest_ty.fmt(target)}); } - const target = sema.mod.getTarget(); - const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs); const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs); @@ -8894,7 +8967,7 @@ fn zirOverflowArithmetic( if (!lhs_val.isUndef()) { if (lhs_val.compareWithZero(.eq)) { break :result .{ .overflowed = .no, .wrapped = lhs }; - } else if (lhs_val.compare(.eq, Value.one, dest_ty)) { + } else if (lhs_val.compare(.eq, Value.one, dest_ty, target)) { break :result .{ .overflowed = .no, .wrapped = rhs }; } } @@ -8904,7 +8977,7 @@ fn zirOverflowArithmetic( if (!rhs_val.isUndef()) { if (rhs_val.compareWithZero(.eq)) { break :result .{ .overflowed = .no, .wrapped = rhs }; - } else if (rhs_val.compare(.eq, Value.one, dest_ty)) { + } else if (rhs_val.compare(.eq, Value.one, dest_ty, target)) { break :result .{ .overflowed = .no, .wrapped = lhs }; } } @@ -9079,7 +9152,7 @@ fn analyzeArithmetic( if (is_int) { return sema.addConstant( resolved_type, - try lhs_val.intAdd(rhs_val, resolved_type, sema.arena), + try lhs_val.intAdd(rhs_val, resolved_type, sema.arena, target), ); } else { return sema.addConstant( @@ -9132,7 +9205,7 @@ fn analyzeArithmetic( } if (maybe_lhs_val) |lhs_val| { const val = if (scalar_tag == .ComptimeInt) - try lhs_val.intAdd(rhs_val, resolved_type, sema.arena) + try lhs_val.intAdd(rhs_val, resolved_type, sema.arena, target) else try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, target); @@ -9172,7 +9245,7 @@ fn analyzeArithmetic( if (is_int) { return sema.addConstant( resolved_type, - try lhs_val.intSub(rhs_val, resolved_type, sema.arena), + try lhs_val.intSub(rhs_val, resolved_type, sema.arena, target), ); } else { return sema.addConstant( @@ -9225,7 +9298,7 @@ fn analyzeArithmetic( } if (maybe_rhs_val) |rhs_val| { const val = if (scalar_tag == .ComptimeInt) - try lhs_val.intSub(rhs_val, resolved_type, sema.arena) + try lhs_val.intSub(rhs_val, resolved_type, sema.arena, target) else try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, target); @@ -9275,7 +9348,7 @@ fn analyzeArithmetic( if (lhs_val.isUndef()) { if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { if (maybe_rhs_val) |rhs_val| { - if (rhs_val.compare(.neq, Value.negative_one, rhs_ty)) { + if (rhs_val.compare(.neq, Value.negative_one, rhs_ty, target)) { return sema.addConstUndef(resolved_type); } } @@ -9288,7 +9361,7 @@ fn analyzeArithmetic( if (is_int) { return sema.addConstant( resolved_type, - try lhs_val.intDiv(rhs_val, resolved_type, sema.arena), + try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), ); } else { return sema.addConstant( @@ -9350,7 +9423,7 @@ fn analyzeArithmetic( if (lhs_val.isUndef()) { if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { if (maybe_rhs_val) |rhs_val| { - if (rhs_val.compare(.neq, Value.negative_one, rhs_ty)) { + if (rhs_val.compare(.neq, Value.negative_one, rhs_ty, target)) { return sema.addConstUndef(resolved_type); } } @@ -9363,7 +9436,7 @@ fn analyzeArithmetic( if (is_int) { return sema.addConstant( resolved_type, - try lhs_val.intDiv(rhs_val, resolved_type, sema.arena), + try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), ); } else { return sema.addConstant( @@ -9413,7 +9486,7 @@ fn analyzeArithmetic( if (lhs_val.isUndef()) { if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { if (maybe_rhs_val) |rhs_val| { - if (rhs_val.compare(.neq, Value.negative_one, rhs_ty)) { + if (rhs_val.compare(.neq, Value.negative_one, rhs_ty, target)) { return sema.addConstUndef(resolved_type); } } @@ -9426,7 +9499,7 @@ fn analyzeArithmetic( if (is_int) { return sema.addConstant( resolved_type, - try lhs_val.intDivFloor(rhs_val, resolved_type, sema.arena), + try lhs_val.intDivFloor(rhs_val, resolved_type, sema.arena, target), ); } else { return sema.addConstant( @@ -9477,7 +9550,7 @@ fn analyzeArithmetic( // TODO: emit compile error if there is a remainder return sema.addConstant( resolved_type, - try lhs_val.intDiv(rhs_val, resolved_type, sema.arena), + try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), ); } else { // TODO: emit compile error if there is a remainder @@ -9503,7 +9576,7 @@ fn analyzeArithmetic( if (lhs_val.compareWithZero(.eq)) { return sema.addConstant(resolved_type, Value.zero); } - if (lhs_val.compare(.eq, Value.one, lhs_ty)) { + if (lhs_val.compare(.eq, Value.one, lhs_ty, target)) { return casted_rhs; } } @@ -9519,7 +9592,7 @@ fn analyzeArithmetic( if (rhs_val.compareWithZero(.eq)) { return sema.addConstant(resolved_type, Value.zero); } - if (rhs_val.compare(.eq, Value.one, rhs_ty)) { + if (rhs_val.compare(.eq, Value.one, rhs_ty, target)) { return casted_lhs; } if (maybe_lhs_val) |lhs_val| { @@ -9533,7 +9606,7 @@ fn analyzeArithmetic( if (is_int) { return sema.addConstant( resolved_type, - try lhs_val.intMul(rhs_val, resolved_type, sema.arena), + try lhs_val.intMul(rhs_val, resolved_type, sema.arena, target), ); } else { return sema.addConstant( @@ -9554,7 +9627,7 @@ fn analyzeArithmetic( if (lhs_val.compareWithZero(.eq)) { return sema.addConstant(resolved_type, Value.zero); } - if (lhs_val.compare(.eq, Value.one, lhs_ty)) { + if (lhs_val.compare(.eq, Value.one, lhs_ty, target)) { return casted_rhs; } } @@ -9566,7 +9639,7 @@ fn analyzeArithmetic( if (rhs_val.compareWithZero(.eq)) { return sema.addConstant(resolved_type, Value.zero); } - if (rhs_val.compare(.eq, Value.one, rhs_ty)) { + if (rhs_val.compare(.eq, Value.one, rhs_ty, target)) { return casted_lhs; } if (maybe_lhs_val) |lhs_val| { @@ -9590,7 +9663,7 @@ fn analyzeArithmetic( if (lhs_val.compareWithZero(.eq)) { return sema.addConstant(resolved_type, Value.zero); } - if (lhs_val.compare(.eq, Value.one, lhs_ty)) { + if (lhs_val.compare(.eq, Value.one, lhs_ty, target)) { return casted_rhs; } } @@ -9602,7 +9675,7 @@ fn analyzeArithmetic( if (rhs_val.compareWithZero(.eq)) { return sema.addConstant(resolved_type, Value.zero); } - if (rhs_val.compare(.eq, Value.one, rhs_ty)) { + if (rhs_val.compare(.eq, Value.one, rhs_ty, target)) { return casted_lhs; } if (maybe_lhs_val) |lhs_val| { @@ -9611,7 +9684,7 @@ fn analyzeArithmetic( } const val = if (scalar_tag == .ComptimeInt) - try lhs_val.intMul(rhs_val, resolved_type, sema.arena) + try lhs_val.intMul(rhs_val, resolved_type, sema.arena, target) else try lhs_val.intMulSat(rhs_val, resolved_type, sema.arena, target); @@ -9652,7 +9725,7 @@ fn analyzeArithmetic( return sema.failWithDivideByZero(block, rhs_src); } if (maybe_lhs_val) |lhs_val| { - const rem_result = try lhs_val.intRem(rhs_val, resolved_type, sema.arena); + const rem_result = try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target); // If this answer could possibly be different by doing `intMod`, // we must emit a compile error. Otherwise, it's OK. if (rhs_val.compareWithZero(.lt) != lhs_val.compareWithZero(.lt) and @@ -9731,7 +9804,7 @@ fn analyzeArithmetic( if (maybe_lhs_val) |lhs_val| { return sema.addConstant( resolved_type, - try lhs_val.intRem(rhs_val, resolved_type, sema.arena), + try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target), ); } break :rs .{ .src = lhs_src, .air_tag = .rem }; @@ -9788,7 +9861,7 @@ fn analyzeArithmetic( if (maybe_lhs_val) |lhs_val| { return sema.addConstant( resolved_type, - try lhs_val.intMod(rhs_val, resolved_type, sema.arena), + try lhs_val.intMod(rhs_val, resolved_type, sema.arena, target), ); } break :rs .{ .src = lhs_src, .air_tag = .mod }; @@ -9839,6 +9912,7 @@ fn analyzePtrArithmetic( // coerce to isize instead of usize. const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src); // TODO adjust the return type according to alignment and other factors + const target = sema.mod.getTarget(); const runtime_src = rs: { if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |ptr_val| { if (try sema.resolveMaybeUndefVal(block, offset_src, offset)) |offset_val| { @@ -9849,11 +9923,10 @@ fn analyzePtrArithmetic( return sema.addConstUndef(new_ptr_ty); } - const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt()); + const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(target)); // TODO I tried to put this check earlier but it the LLVM backend generate invalid instructinons if (offset_int == 0) return ptr; - if (ptr_val.getUnsignedInt()) |addr| { - const target = sema.mod.getTarget(); + if (ptr_val.getUnsignedInt(target)) |addr| { const ptr_child_ty = ptr_ty.childType(); const elem_ty = if (ptr_ty.isSinglePointer() and ptr_child_ty.zigTypeTag() == .Array) ptr_child_ty.childType() @@ -9872,7 +9945,7 @@ fn analyzePtrArithmetic( if (air_tag == .ptr_sub) { return sema.fail(block, op_src, "TODO implement Sema comptime pointer subtraction", .{}); } - const new_ptr_val = try ptr_val.elemPtr(ptr_ty, sema.arena, offset_int); + const new_ptr_val = try ptr_val.elemPtr(ptr_ty, sema.arena, offset_int, target); return sema.addConstant(new_ptr_ty, new_ptr_val); } else break :rs offset_src; } else break :rs ptr_src; @@ -10035,6 +10108,7 @@ fn zirCmpEq( const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; const lhs = sema.resolveInst(extra.lhs); const rhs = sema.resolveInst(extra.rhs); + const target = sema.mod.getTarget(); const lhs_ty = sema.typeOf(lhs); const rhs_ty = sema.typeOf(rhs); @@ -10059,7 +10133,7 @@ fn zirCmpEq( if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) { const non_null_type = if (lhs_ty_tag == .Null) rhs_ty else lhs_ty; - return sema.fail(block, src, "comparison of '{}' with null", .{non_null_type}); + return sema.fail(block, src, "comparison of '{}' with null", .{non_null_type.fmt(target)}); } if (lhs_ty_tag == .Union and (rhs_ty_tag == .EnumLiteral or rhs_ty_tag == .Enum)) { @@ -10099,7 +10173,7 @@ fn zirCmpEq( if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) { const lhs_as_type = try sema.analyzeAsType(block, lhs_src, lhs); const rhs_as_type = try sema.analyzeAsType(block, rhs_src, rhs); - if (lhs_as_type.eql(rhs_as_type) == (op == .eq)) { + if (lhs_as_type.eql(rhs_as_type, target) == (op == .eq)) { return Air.Inst.Ref.bool_true; } else { return Air.Inst.Ref.bool_false; @@ -10176,9 +10250,10 @@ fn analyzeCmp( } const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } }); + const target = sema.mod.getTarget(); if (!resolved_type.isSelfComparable(is_equality_cmp)) { return sema.fail(block, src, "{s} operator not allowed for type '{}'", .{ - @tagName(op), resolved_type, + @tagName(op), resolved_type.fmt(target), }); } const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); @@ -10196,6 +10271,7 @@ fn cmpSelf( rhs_src: LazySrcLoc, ) CompileError!Air.Inst.Ref { const resolved_type = sema.typeOf(casted_lhs); + const target = sema.mod.getTarget(); const runtime_src: LazySrcLoc = src: { if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| { if (lhs_val.isUndef()) return sema.addConstUndef(Type.bool); @@ -10204,11 +10280,11 @@ fn cmpSelf( if (resolved_type.zigTypeTag() == .Vector) { const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.@"bool"); - const cmp_val = try lhs_val.compareVector(op, rhs_val, resolved_type, sema.arena); + const cmp_val = try lhs_val.compareVector(op, rhs_val, resolved_type, sema.arena, target); return sema.addConstant(result_ty, cmp_val); } - if (lhs_val.compare(op, rhs_val, resolved_type)) { + if (lhs_val.compare(op, rhs_val, resolved_type, target)) { return Air.Inst.Ref.bool_true; } else { return Air.Inst.Ref.bool_false; @@ -10276,7 +10352,7 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. .Null, .BoundFn, .Opaque, - => return sema.fail(block, src, "no size available for type '{}'", .{operand_ty}), + => return sema.fail(block, src, "no size available for type '{}'", .{operand_ty.fmt(target)}), .Type, .EnumLiteral, @@ -11365,11 +11441,12 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi }, else => {}, } + const target = sema.mod.getTarget(); return sema.fail( block, src, "bit shifting operation expected integer type, found '{}'", - .{operand}, + .{operand.fmt(target)}, ); } @@ -12414,6 +12491,7 @@ fn fieldType( ty_src: LazySrcLoc, ) CompileError!Air.Inst.Ref { const resolved_ty = try sema.resolveTypeFields(block, ty_src, aggregate_ty); + const target = sema.mod.getTarget(); switch (resolved_ty.zigTypeTag()) { .Struct => { const struct_obj = resolved_ty.castTag(.@"struct").?.data; @@ -12428,7 +12506,7 @@ fn fieldType( return sema.addType(field.ty); }, else => return sema.fail(block, ty_src, "expected struct or union; found '{}'", .{ - resolved_ty, + resolved_ty.fmt(target), }), } } @@ -12459,11 +12537,11 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const inst_data = sema.code.instructions.items(.data)[inst].un_node; const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; const ty = try sema.resolveType(block, operand_src, inst_data.operand); - const resolved_ty = try sema.resolveTypeFields(block, operand_src, ty); - try sema.resolveTypeLayout(block, operand_src, resolved_ty); const target = sema.mod.getTarget(); - const abi_align = resolved_ty.abiAlignment(target); - return sema.addIntUnsigned(Type.comptime_int, abi_align); + return sema.addConstant( + Type.comptime_int, + try ty.lazyAbiAlignment(target, sema.arena), + ); } fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -12509,6 +12587,7 @@ fn zirUnaryMath( const operand = sema.resolveInst(inst_data.operand); const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; const operand_ty = sema.typeOf(operand); + const target = sema.mod.getTarget(); switch (operand_ty.zigTypeTag()) { .ComptimeFloat, .Float => {}, @@ -12516,13 +12595,12 @@ fn zirUnaryMath( const scalar_ty = operand_ty.scalarType(); switch (scalar_ty.zigTypeTag()) { .ComptimeFloat, .Float => {}, - else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{scalar_ty}), + else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{scalar_ty.fmt(target)}), } }, - else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{operand_ty}), + else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{operand_ty.fmt(target)}), } - const target = sema.mod.getTarget(); switch (operand_ty.zigTypeTag()) { .Vector => { const scalar_ty = operand_ty.scalarType(); @@ -12568,6 +12646,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const src = inst_data.src(); const operand = sema.resolveInst(inst_data.operand); const operand_ty = sema.typeOf(operand); + const target = sema.mod.getTarget(); try sema.resolveTypeLayout(block, operand_src, operand_ty); const enum_ty = switch (operand_ty.zigTypeTag()) { @@ -12590,13 +12669,13 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air return sema.failWithOwnedErrorMsg(block, msg); }, else => return sema.fail(block, operand_src, "expected enum or union; found {}", .{ - operand_ty, + operand_ty.fmt(target), }), }; const enum_decl = enum_ty.getOwnerDecl(); const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src); if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| { - const field_index = enum_ty.enumTagFieldIndex(val) orelse { + const field_index = enum_ty.enumTagFieldIndex(val, target) orelse { const msg = msg: { const msg = try sema.errMsg(block, src, "no field with value {} in enum '{s}'", .{ casted_operand, enum_decl.name, @@ -12626,8 +12705,8 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const val = try sema.resolveConstValue(block, operand_src, type_info); const union_val = val.cast(Value.Payload.Union).?.data; const tag_ty = type_info_ty.unionTagType().?; - const tag_index = tag_ty.enumTagFieldIndex(union_val.tag).?; const target = sema.mod.getTarget(); + const tag_index = tag_ty.enumTagFieldIndex(union_val.tag, target).?; switch (@intToEnum(std.builtin.TypeId, tag_index)) { .Type => return Air.Inst.Ref.type_type, .Void => return Air.Inst.Ref.void_type, @@ -12646,7 +12725,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const bits_val = struct_val[1]; const signedness = signedness_val.toEnum(std.builtin.Signedness); - const bits = @intCast(u16, bits_val.toUnsignedInt()); + const bits = @intCast(u16, bits_val.toUnsignedInt(target)); const ty = switch (signedness) { .signed => try Type.Tag.int_signed.create(sema.arena, bits), .unsigned => try Type.Tag.int_unsigned.create(sema.arena, bits), @@ -12659,7 +12738,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const len_val = struct_val[0]; const child_val = struct_val[1]; - const len = len_val.toUnsignedInt(); + const len = len_val.toUnsignedInt(target); var buffer: Value.ToTypeBuffer = undefined; const child_ty = child_val.toType(&buffer); @@ -12672,7 +12751,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I // bits: comptime_int, const bits_val = struct_val[0]; - const bits = @intCast(u16, bits_val.toUnsignedInt()); + const bits = @intCast(u16, bits_val.toUnsignedInt(target)); const ty = switch (bits) { 16 => Type.@"f16", 32 => Type.@"f32", @@ -12717,7 +12796,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I .size = ptr_size, .mutable = !is_const_val.toBool(), .@"volatile" = is_volatile_val.toBool(), - .@"align" = @intCast(u16, alignment_val.toUnsignedInt()), // TODO: Validate this value. + .@"align" = @intCast(u16, alignment_val.toUnsignedInt(target)), // TODO: Validate this value. .@"addrspace" = address_space_val.toEnum(std.builtin.AddressSpace), .pointee_type = try child_ty.copy(sema.arena), .@"allowzero" = is_allowzero_val.toBool(), @@ -12735,7 +12814,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I // sentinel: ?*const anyopaque, const sentinel_val = struct_val[2]; - const len = len_val.toUnsignedInt(); + const len = len_val.toUnsignedInt(target); var buffer: Value.ToTypeBuffer = undefined; const child_ty = try child_val.toType(&buffer).copy(sema.arena); const sentinel = if (sentinel_val.castTag(.opt_payload)) |p| blk: { @@ -12746,7 +12825,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I break :blk (try sema.pointerDeref(block, src, p.data, ptr_ty)).?; } else null; - const ty = try Type.array(sema.arena, len, sentinel, child_ty); + const ty = try Type.array(sema.arena, len, sentinel, child_ty, target); return sema.addType(ty); }, .Optional => { @@ -12796,7 +12875,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const name_val = struct_val[0]; names.putAssumeCapacityNoClobber( - try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena), + try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, target), {}, ); } @@ -12817,7 +12896,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const is_tuple_val = struct_val[3]; // Decls - if (decls_val.sliceLen() > 0) { + if (decls_val.sliceLen(target) > 0) { return sema.fail(block, src, "reified structs must have no decls", .{}); } @@ -12847,7 +12926,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I } // Decls - if (decls_val.sliceLen() > 0) { + if (decls_val.sliceLen(target) > 0) { return sema.fail(block, src, "reified enums must have no decls", .{}); } @@ -12898,11 +12977,12 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I enum_obj.tag_ty = try tag_type_val.toType(&buffer).copy(new_decl_arena_allocator); // Fields - const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen()); + const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(target)); if (fields_len > 0) { try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{ .ty = enum_obj.tag_ty, + .target = target, }); var i: usize = 0; @@ -12918,6 +12998,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const field_name = try name_val.toAllocatedBytes( Type.initTag(.const_slice_u8), new_decl_arena_allocator, + target, ); const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name); @@ -12929,6 +13010,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const copied_tag_val = try value_val.copy(new_decl_arena_allocator); enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{ .ty = enum_obj.tag_ty, + .target = target, }); } } @@ -12942,7 +13024,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const decls_val = struct_val[0]; // Decls - if (decls_val.sliceLen() > 0) { + if (decls_val.sliceLen(target) > 0) { return sema.fail(block, src, "reified opaque must have no decls", .{}); } @@ -12993,7 +13075,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const decls_val = struct_val[3]; // Decls - if (decls_val.sliceLen() > 0) { + if (decls_val.sliceLen(target) > 0) { return sema.fail(block, src, "reified unions must have no decls", .{}); } @@ -13033,7 +13115,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I }; // Tag type - const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen()); + const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(target)); union_obj.tag_ty = if (tag_type_val.optionalValue()) |payload_val| blk: { var buffer: Value.ToTypeBuffer = undefined; break :blk try payload_val.toType(&buffer).copy(new_decl_arena_allocator); @@ -13058,6 +13140,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const field_name = try name_val.toAllocatedBytes( Type.initTag(.const_slice_u8), new_decl_arena_allocator, + target, ); const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); @@ -13069,7 +13152,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I var buffer: Value.ToTypeBuffer = undefined; gop.value_ptr.* = .{ .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator), - .abi_align = @intCast(u32, alignment_val.toUnsignedInt()), + .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)), }; } } @@ -13089,7 +13172,9 @@ fn reifyTuple( src: LazySrcLoc, fields_val: Value, ) CompileError!Air.Inst.Ref { - const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen()); + const target = sema.mod.getTarget(); + + const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(target)); if (fields_len == 0) return sema.addType(Type.initTag(.empty_struct_literal)); const types = try sema.arena.alloc(Type, fields_len); @@ -13114,6 +13199,7 @@ fn reifyTuple( const field_name = try name_val.toAllocatedBytes( Type.initTag(.const_slice_u8), sema.arena, + target, ); const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch |err| { @@ -13197,8 +13283,10 @@ fn reifyStruct( }, }; + const target = sema.mod.getTarget(); + // Fields - const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen()); + const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(target)); try struct_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); var i: usize = 0; while (i < fields_len) : (i += 1) { @@ -13219,6 +13307,7 @@ fn reifyStruct( const field_name = try name_val.toAllocatedBytes( Type.initTag(.const_slice_u8), new_decl_arena_allocator, + target, ); const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); @@ -13238,7 +13327,7 @@ fn reifyStruct( var buffer: Value.ToTypeBuffer = undefined; gop.value_ptr.* = .{ .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator), - .abi_align = @intCast(u32, alignment_val.toUnsignedInt()), + .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)), .default_val = default_val, .is_comptime = is_comptime_val.toBool(), .offset = undefined, @@ -13257,7 +13346,8 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded); defer anon_decl.deinit(); - const bytes = try ty.nameAllocArena(anon_decl.arena()); + const target = sema.mod.getTarget(); + const bytes = try ty.nameAllocArena(anon_decl.arena(), target); const new_decl = try anon_decl.finish( try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), @@ -13296,7 +13386,10 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! const target = sema.mod.getTarget(); const result_val = val.floatToInt(sema.arena, operand_ty, dest_ty, target) catch |err| switch (err) { error.FloatCannotFit => { - return sema.fail(block, operand_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty }); + return sema.fail(block, operand_src, "integer value {d} cannot be stored in type '{}'", .{ + std.math.floor(val.toFloat(f64)), + dest_ty.fmt(target), + }); }, else => |e| return e, }; @@ -13344,13 +13437,14 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai try sema.checkPtrType(block, type_src, type_res); try sema.resolveTypeLayout(block, src, type_res.elemType2()); const ptr_align = type_res.ptrAlignment(sema.mod.getTarget()); + const target = sema.mod.getTarget(); if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| { - const addr = val.toUnsignedInt(); + const addr = val.toUnsignedInt(target); if (!type_res.isAllowzeroPtr() and addr == 0) - return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{type_res}); + return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{type_res.fmt(target)}); if (addr != 0 and addr % ptr_align != 0) - return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{type_res}); + return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{type_res.fmt(target)}); const val_payload = try sema.arena.create(Value.Payload.U64); val_payload.* = .{ @@ -13394,6 +13488,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); const operand = sema.resolveInst(extra.rhs); const operand_ty = sema.typeOf(operand); + const target = sema.mod.getTarget(); try sema.checkErrorSetType(block, dest_ty_src, dest_ty); try sema.checkErrorSetType(block, operand_src, operand_ty); @@ -13407,7 +13502,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! block, src, "error.{s} not a member of error set '{}'", - .{ error_name, dest_ty }, + .{ error_name, dest_ty.fmt(target) }, ); } } @@ -13502,7 +13597,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai if (operand_info.signedness != dest_info.signedness) { return sema.fail(block, operand_src, "expected {s} integer type, found '{}'", .{ - @tagName(dest_info.signedness), operand_ty, + @tagName(dest_info.signedness), operand_ty.fmt(target), }); } if (operand_info.bits < dest_info.bits) { @@ -13511,7 +13606,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, "destination type '{}' has more bits than source type '{}'", - .{ dest_ty, operand_ty }, + .{ dest_ty.fmt(target), operand_ty.fmt(target) }, ); errdefer msg.destroy(sema.gpa); try sema.errNote(block, dest_ty_src, msg, "destination type has {d} bits", .{ @@ -13531,14 +13626,14 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai if (!is_vector) { return sema.addConstant( dest_ty, - try val.intTrunc(operand_ty, sema.arena, dest_info.signedness, dest_info.bits), + try val.intTrunc(operand_ty, sema.arena, dest_info.signedness, dest_info.bits, target), ); } var elem_buf: Value.ElemValueBuffer = undefined; const elems = try sema.arena.alloc(Value, operand_ty.vectorLen()); for (elems) |*elem, i| { const elem_val = val.elemValueBuffer(i, &elem_buf); - elem.* = try elem_val.intTrunc(operand_scalar_ty, sema.arena, dest_info.signedness, dest_info.bits); + elem.* = try elem_val.intTrunc(operand_scalar_ty, sema.arena, dest_info.signedness, dest_info.bits, target); } return sema.addConstant( dest_ty, @@ -13653,7 +13748,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, ty_src, "@byteSwap requires the number of bits to be evenly divisible by 8, but {} has {} bits", - .{ scalar_ty, bits }, + .{ scalar_ty.fmt(target), bits }, ); } @@ -13765,6 +13860,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 const ty = try sema.resolveType(block, lhs_src, extra.lhs); const field_name = try sema.resolveConstString(block, rhs_src, extra.rhs); + const target = sema.mod.getTarget(); try sema.resolveTypeLayout(block, lhs_src, ty); if (ty.tag() != .@"struct") { @@ -13772,7 +13868,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 block, lhs_src, "expected struct type, found '{}'", - .{ty}, + .{ty.fmt(target)}, ); } @@ -13782,11 +13878,10 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 block, rhs_src, "struct '{}' has no field '{s}'", - .{ ty, field_name }, + .{ ty.fmt(target), field_name }, ); }; - const target = sema.mod.getTarget(); switch (ty.containerLayout()) { .Packed => { var bit_sum: u64 = 0; @@ -13809,18 +13904,20 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 } fn checkNamespaceType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { + const target = sema.mod.getTarget(); switch (ty.zigTypeTag()) { .Struct, .Enum, .Union, .Opaque => return, - else => return sema.fail(block, src, "expected struct, enum, union, or opaque; found '{}'", .{ty}), + else => return sema.fail(block, src, "expected struct, enum, union, or opaque; found '{}'", .{ty.fmt(target)}), } } /// Returns `true` if the type was a comptime_int. fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool { + const target = sema.mod.getTarget(); switch (try ty.zigTypeTagOrPoison()) { .ComptimeInt => return true, .Int => return false, - else => return sema.fail(block, src, "expected integer type, found '{}'", .{ty}), + else => return sema.fail(block, src, "expected integer type, found '{}'", .{ty.fmt(target)}), } } @@ -13830,6 +13927,7 @@ fn checkPtrOperand( ty_src: LazySrcLoc, ty: Type, ) CompileError!void { + const target = sema.mod.getTarget(); switch (ty.zigTypeTag()) { .Pointer => return, .Fn => { @@ -13838,7 +13936,7 @@ fn checkPtrOperand( block, ty_src, "expected pointer, found {}", - .{ty}, + .{ty.fmt(target)}, ); errdefer msg.destroy(sema.gpa); @@ -13851,7 +13949,7 @@ fn checkPtrOperand( .Optional => if (ty.isPtrLikeOptional()) return, else => {}, } - return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty}); + return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(target)}); } fn checkPtrType( @@ -13860,6 +13958,7 @@ fn checkPtrType( ty_src: LazySrcLoc, ty: Type, ) CompileError!void { + const target = sema.mod.getTarget(); switch (ty.zigTypeTag()) { .Pointer => return, .Fn => { @@ -13868,7 +13967,7 @@ fn checkPtrType( block, ty_src, "expected pointer type, found '{}'", - .{ty}, + .{ty.fmt(target)}, ); errdefer msg.destroy(sema.gpa); @@ -13881,7 +13980,7 @@ fn checkPtrType( .Optional => if (ty.isPtrLikeOptional()) return, else => {}, } - return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty}); + return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(target)}); } fn checkVectorElemType( @@ -13894,7 +13993,8 @@ fn checkVectorElemType( .Int, .Float, .Bool => return, else => if (ty.isPtrAtRuntime()) return, } - return sema.fail(block, ty_src, "expected integer, float, bool, or pointer for the vector element type; found '{}'", .{ty}); + const target = sema.mod.getTarget(); + return sema.fail(block, ty_src, "expected integer, float, bool, or pointer for the vector element type; found '{}'", .{ty.fmt(target)}); } fn checkFloatType( @@ -13903,9 +14003,10 @@ fn checkFloatType( ty_src: LazySrcLoc, ty: Type, ) CompileError!void { + const target = sema.mod.getTarget(); switch (ty.zigTypeTag()) { .ComptimeInt, .ComptimeFloat, .Float => {}, - else => return sema.fail(block, ty_src, "expected float type, found '{}'", .{ty}), + else => return sema.fail(block, ty_src, "expected float type, found '{}'", .{ty.fmt(target)}), } } @@ -13915,13 +14016,14 @@ fn checkNumericType( ty_src: LazySrcLoc, ty: Type, ) CompileError!void { + const target = sema.mod.getTarget(); switch (ty.zigTypeTag()) { .ComptimeFloat, .Float, .ComptimeInt, .Int => {}, .Vector => switch (ty.childType().zigTypeTag()) { .ComptimeFloat, .Float, .ComptimeInt, .Int => {}, else => |t| return sema.fail(block, ty_src, "expected number, found '{}'", .{t}), }, - else => return sema.fail(block, ty_src, "expected number, found '{}'", .{ty}), + else => return sema.fail(block, ty_src, "expected number, found '{}'", .{ty.fmt(target)}), } } @@ -13957,7 +14059,7 @@ fn checkAtomicOperandType( block, ty_src, "expected bool, integer, float, enum, or pointer type; found {}", - .{ty}, + .{ty.fmt(target)}, ); }, }; @@ -14021,6 +14123,7 @@ fn checkIntOrVector( operand_src: LazySrcLoc, ) CompileError!Type { const operand_ty = sema.typeOf(operand); + const target = sema.mod.getTarget(); switch (try operand_ty.zigTypeTagOrPoison()) { .Int => return operand_ty, .Vector => { @@ -14028,12 +14131,12 @@ fn checkIntOrVector( switch (try elem_ty.zigTypeTagOrPoison()) { .Int => return elem_ty, else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{ - elem_ty, + elem_ty.fmt(target), }), } }, else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{ - operand_ty, + operand_ty.fmt(target), }), } } @@ -14045,6 +14148,7 @@ fn checkIntOrVectorAllowComptime( operand_src: LazySrcLoc, ) CompileError!Type { const operand_ty = sema.typeOf(operand); + const target = sema.mod.getTarget(); switch (try operand_ty.zigTypeTagOrPoison()) { .Int, .ComptimeInt => return operand_ty, .Vector => { @@ -14052,20 +14156,21 @@ fn checkIntOrVectorAllowComptime( switch (try elem_ty.zigTypeTagOrPoison()) { .Int, .ComptimeInt => return elem_ty, else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{ - elem_ty, + elem_ty.fmt(target), }), } }, else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{ - operand_ty, + operand_ty.fmt(target), }), } } fn checkErrorSetType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { + const target = sema.mod.getTarget(); switch (ty.zigTypeTag()) { .ErrorSet => return, - else => return sema.fail(block, src, "expected error set type, found '{}'", .{ty}), + else => return sema.fail(block, src, "expected error set type, found '{}'", .{ty.fmt(target)}), } } @@ -14138,9 +14243,10 @@ fn checkVectorizableBinaryOperands( return sema.failWithOwnedErrorMsg(block, msg); } } else if (lhs_zig_ty_tag == .Vector or rhs_zig_ty_tag == .Vector) { + const target = sema.mod.getTarget(); const msg = msg: { const msg = try sema.errMsg(block, src, "mixed scalar and vector operands: {} and {}", .{ - lhs_ty, rhs_ty, + lhs_ty.fmt(target), rhs_ty.fmt(target), }); errdefer msg.destroy(sema.gpa); if (lhs_zig_ty_tag == .Vector) { @@ -14179,8 +14285,9 @@ fn resolveExportOptions( return sema.fail(block, src, "TODO: implement exporting with linksection", .{}); } const name_ty = Type.initTag(.const_slice_u8); + const target = sema.mod.getTarget(); return std.builtin.ExportOptions{ - .name = try name_val.toAllocatedBytes(name_ty, sema.arena), + .name = try name_val.toAllocatedBytes(name_ty, sema.arena, target), .linkage = linkage_val.toEnum(std.builtin.GlobalLinkage), .section = null, // TODO }; @@ -14239,12 +14346,13 @@ fn zirCmpxchg( const ptr_ty = sema.typeOf(ptr); const elem_ty = ptr_ty.elemType(); try sema.checkAtomicOperandType(block, elem_ty_src, elem_ty); + const target = sema.mod.getTarget(); if (elem_ty.zigTypeTag() == .Float) { return sema.fail( block, elem_ty_src, "expected bool, integer, enum, or pointer type; found '{}'", - .{elem_ty}, + .{elem_ty.fmt(target)}, ); } const expected_value = try sema.coerce(block, elem_ty, sema.resolveInst(extra.expected_value), expected_src); @@ -14281,7 +14389,7 @@ fn zirCmpxchg( return sema.addConstUndef(result_ty); } const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src; - const result_val = if (stored_val.eql(expected_val, elem_ty)) blk: { + const result_val = if (stored_val.eql(expected_val, elem_ty, target)) blk: { try sema.storePtr(block, src, ptr, new_value); break :blk Value.@"null"; } else try Value.Tag.opt_payload.create(sema.arena, stored_val); @@ -14343,9 +14451,10 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. const operation = try sema.resolveBuiltinEnum(block, op_src, extra.lhs, "ReduceOp"); const operand = sema.resolveInst(extra.rhs); const operand_ty = sema.typeOf(operand); + const target = sema.mod.getTarget(); if (operand_ty.zigTypeTag() != .Vector) { - return sema.fail(block, operand_src, "expected vector, found {}", .{operand_ty}); + return sema.fail(block, operand_src, "expected vector, found {}", .{operand_ty.fmt(target)}); } const scalar_ty = operand_ty.childType(); @@ -14355,13 +14464,13 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. .And, .Or, .Xor => switch (scalar_ty.zigTypeTag()) { .Int, .Bool => {}, else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or boolean operand; found {}", .{ - @tagName(operation), operand_ty, + @tagName(operation), operand_ty.fmt(target), }), }, .Min, .Max, .Add, .Mul => switch (scalar_ty.zigTypeTag()) { .Int, .Float => {}, else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or float operand; found {}", .{ - @tagName(operation), operand_ty, + @tagName(operation), operand_ty.fmt(target), }), }, } @@ -14376,18 +14485,17 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| { if (operand_val.isUndef()) return sema.addConstUndef(scalar_ty); - const target = sema.mod.getTarget(); var accum: Value = try operand_val.elemValue(sema.arena, 0); var elem_buf: Value.ElemValueBuffer = undefined; var i: u32 = 1; while (i < vec_len) : (i += 1) { const elem_val = operand_val.elemValueBuffer(i, &elem_buf); switch (operation) { - .And => accum = try accum.bitwiseAnd(elem_val, scalar_ty, sema.arena), - .Or => accum = try accum.bitwiseOr(elem_val, scalar_ty, sema.arena), - .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena), - .Min => accum = accum.numberMin(elem_val), - .Max => accum = accum.numberMax(elem_val), + .And => accum = try accum.bitwiseAnd(elem_val, scalar_ty, sema.arena, target), + .Or => accum = try accum.bitwiseOr(elem_val, scalar_ty, sema.arena, target), + .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena, target), + .Min => accum = accum.numberMin(elem_val, target), + .Max => accum = accum.numberMax(elem_val, target), .Add => accum = try accum.numberAddWrap(elem_val, scalar_ty, sema.arena, target), .Mul => accum = try accum.numberMulWrap(elem_val, scalar_ty, sema.arena, target), } @@ -14417,10 +14525,11 @@ fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air var b = sema.resolveInst(extra.b); var mask = sema.resolveInst(extra.mask); var mask_ty = sema.typeOf(mask); + const target = sema.mod.getTarget(); const mask_len = switch (sema.typeOf(mask).zigTypeTag()) { .Array, .Vector => sema.typeOf(mask).arrayLen(), - else => return sema.fail(block, mask_src, "expected vector or array, found {}", .{sema.typeOf(mask)}), + else => return sema.fail(block, mask_src, "expected vector or array, found {}", .{sema.typeOf(mask).fmt(target)}), }; mask_ty = try Type.Tag.vector.create(sema.arena, .{ .len = mask_len, @@ -14452,20 +14561,21 @@ fn analyzeShuffle( .elem_type = elem_ty, }); + const target = sema.mod.getTarget(); var maybe_a_len = switch (sema.typeOf(a).zigTypeTag()) { .Array, .Vector => sema.typeOf(a).arrayLen(), .Undefined => null, else => return sema.fail(block, a_src, "expected vector or array with element type {}, found {}", .{ - elem_ty, - sema.typeOf(a), + elem_ty.fmt(target), + sema.typeOf(a).fmt(target), }), }; var maybe_b_len = switch (sema.typeOf(b).zigTypeTag()) { .Array, .Vector => sema.typeOf(b).arrayLen(), .Undefined => null, else => return sema.fail(block, b_src, "expected vector or array with element type {}, found {}", .{ - elem_ty, - sema.typeOf(b), + elem_ty.fmt(target), + sema.typeOf(b).fmt(target), }), }; if (maybe_a_len == null and maybe_b_len == null) { @@ -14513,7 +14623,7 @@ fn analyzeShuffle( try sema.errNote(block, operand_info[chosen][1], msg, "selected index {d} out of bounds of {}", .{ unsigned, - operand_info[chosen][2], + operand_info[chosen][2].fmt(target), }); if (chosen == 1) { @@ -14704,12 +14814,12 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A .Xchg => operand_val, .Add => try stored_val.numberAddWrap(operand_val, operand_ty, sema.arena, target), .Sub => try stored_val.numberSubWrap(operand_val, operand_ty, sema.arena, target), - .And => try stored_val.bitwiseAnd (operand_val, operand_ty, sema.arena), + .And => try stored_val.bitwiseAnd (operand_val, operand_ty, sema.arena, target), .Nand => try stored_val.bitwiseNand (operand_val, operand_ty, sema.arena, target), - .Or => try stored_val.bitwiseOr (operand_val, operand_ty, sema.arena), - .Xor => try stored_val.bitwiseXor (operand_val, operand_ty, sema.arena), - .Max => stored_val.numberMax (operand_val), - .Min => stored_val.numberMin (operand_val), + .Or => try stored_val.bitwiseOr (operand_val, operand_ty, sema.arena, target), + .Xor => try stored_val.bitwiseXor (operand_val, operand_ty, sema.arena, target), + .Max => stored_val.numberMax (operand_val, target), + .Min => stored_val.numberMin (operand_val, target), // zig fmt: on }; try sema.storePtrVal(block, src, ptr_val, new_val, operand_ty); @@ -14788,7 +14898,7 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. switch (ty.zigTypeTag()) { .ComptimeFloat, .Float, .Vector => {}, - else => return sema.fail(block, src, "expected vector of floats or float type, found '{}'", .{ty}), + else => return sema.fail(block, src, "expected vector of floats or float type, found '{}'", .{ty.fmt(target)}), } const runtime_src = if (maybe_mulend1) |mulend1_val| rs: { @@ -14814,7 +14924,7 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. const scalar_ty = ty.scalarType(); switch (scalar_ty.zigTypeTag()) { .ComptimeFloat, .Float => {}, - else => return sema.fail(block, src, "expected vector of floats, found vector of '{}'", .{scalar_ty}), + else => return sema.fail(block, src, "expected vector of floats, found vector of '{}'", .{scalar_ty.fmt(target)}), } const vec_len = ty.vectorLen(); @@ -14906,9 +15016,10 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError break :modifier modifier_val.toEnum(std.builtin.CallOptions.Modifier); }; + const target = sema.mod.getTarget(); const args_ty = sema.typeOf(args); if (!args_ty.isTuple() and args_ty.tag() != .empty_struct_literal) { - return sema.fail(block, args_src, "expected a tuple, found {}", .{args_ty}); + return sema.fail(block, args_src, "expected a tuple, found {}", .{args_ty.fmt(target)}); } var resolved_args: []Air.Inst.Ref = undefined; @@ -14945,9 +15056,10 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr const field_name = try sema.resolveConstString(block, name_src, extra.field_name); const field_ptr = sema.resolveInst(extra.field_ptr); const field_ptr_ty = sema.typeOf(field_ptr); + const target = sema.mod.getTarget(); if (struct_ty.zigTypeTag() != .Struct) { - return sema.fail(block, ty_src, "expected struct type, found '{}'", .{struct_ty}); + return sema.fail(block, ty_src, "expected struct type, found '{}'", .{struct_ty.fmt(target)}); } try sema.resolveTypeLayout(block, ty_src, struct_ty); @@ -14956,7 +15068,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr return sema.failWithBadStructFieldAccess(block, struct_obj, name_src, field_name); if (field_ptr_ty.zigTypeTag() != .Pointer) { - return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{field_ptr_ty}); + return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{field_ptr_ty.fmt(target)}); } const field = struct_obj.fields.values()[field_index]; const field_ptr_ty_info = field_ptr_ty.ptrInfo().data; @@ -14973,7 +15085,6 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr ptr_ty_data.@"align" = field.abi_align; } - const target = sema.mod.getTarget(); const actual_field_ptr_ty = try Type.ptr(sema.arena, target, ptr_ty_data); const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, ptr_src); @@ -15042,8 +15153,9 @@ fn analyzeMinMax( .max => Value.numberMax, else => unreachable, }; + const target = sema.mod.getTarget(); const vec_len = simd_op.len orelse { - const result_val = opFunc(lhs_val, rhs_val); + const result_val = opFunc(lhs_val, rhs_val, target); return sema.addConstant(simd_op.result_ty, result_val); }; var lhs_buf: Value.ElemValueBuffer = undefined; @@ -15052,7 +15164,7 @@ fn analyzeMinMax( for (elems) |*elem, i| { const lhs_elem_val = lhs_val.elemValueBuffer(i, &lhs_buf); const rhs_elem_val = rhs_val.elemValueBuffer(i, &rhs_buf); - elem.* = opFunc(lhs_elem_val, rhs_elem_val); + elem.* = opFunc(lhs_elem_val, rhs_elem_val, target); } return sema.addConstant( simd_op.result_ty, @@ -15078,17 +15190,17 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; const dest_ptr = sema.resolveInst(extra.dest); const dest_ptr_ty = sema.typeOf(dest_ptr); + const target = sema.mod.getTarget(); try sema.checkPtrOperand(block, dest_src, dest_ptr_ty); if (dest_ptr_ty.isConstPtr()) { - return sema.fail(block, dest_src, "cannot store through const pointer '{}'", .{dest_ptr_ty}); + return sema.fail(block, dest_src, "cannot store through const pointer '{}'", .{dest_ptr_ty.fmt(target)}); } const uncasted_src_ptr = sema.resolveInst(extra.source); const uncasted_src_ptr_ty = sema.typeOf(uncasted_src_ptr); try sema.checkPtrOperand(block, src_src, uncasted_src_ptr_ty); const src_ptr_info = uncasted_src_ptr_ty.ptrInfo().data; - const target = sema.mod.getTarget(); const wanted_src_ptr_ty = try Type.ptr(sema.arena, target, .{ .pointee_type = dest_ptr_ty.elemType2(), .@"align" = src_ptr_info.@"align", @@ -15136,9 +15248,10 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; const dest_ptr = sema.resolveInst(extra.dest); const dest_ptr_ty = sema.typeOf(dest_ptr); + const target = sema.mod.getTarget(); try sema.checkPtrOperand(block, dest_src, dest_ptr_ty); if (dest_ptr_ty.isConstPtr()) { - return sema.fail(block, dest_src, "cannot store through const pointer '{}'", .{dest_ptr_ty}); + return sema.fail(block, dest_src, "cannot store through const pointer '{}'", .{dest_ptr_ty.fmt(target)}); } const elem_ty = dest_ptr_ty.elemType2(); const value = try sema.coerce(block, elem_ty, sema.resolveInst(extra.byte), value_src); @@ -15452,6 +15565,7 @@ fn zirPrefetch( const ptr = sema.resolveInst(extra.lhs); try sema.checkPtrOperand(block, ptr_src, sema.typeOf(ptr)); const options = try sema.coerce(block, options_ty, sema.resolveInst(extra.rhs), opts_src); + const target = sema.mod.getTarget(); const rw = try sema.fieldVal(block, opts_src, options, "rw", opts_src); const rw_val = try sema.resolveConstValue(block, opts_src, rw); @@ -15459,7 +15573,7 @@ fn zirPrefetch( const locality = try sema.fieldVal(block, opts_src, options, "locality", opts_src); const locality_val = try sema.resolveConstValue(block, opts_src, locality); - const locality_int = @intCast(u2, locality_val.toUnsignedInt()); + const locality_int = @intCast(u2, locality_val.toUnsignedInt(target)); const cache = try sema.fieldVal(block, opts_src, options, "cache", opts_src); const cache_val = try sema.resolveConstValue(block, opts_src, cache); @@ -15492,6 +15606,7 @@ fn zirBuiltinExtern( var ty = try sema.resolveType(block, ty_src, extra.lhs); const options_inst = sema.resolveInst(extra.rhs); + const target = sema.mod.getTarget(); const options = options: { const extern_options_ty = try sema.getBuiltinType(block, options_src, "ExternOptions"); @@ -15512,11 +15627,11 @@ fn zirBuiltinExtern( var library_name: ?[]const u8 = null; if (!library_name_val.isNull()) { const payload = library_name_val.castTag(.opt_payload).?.data; - library_name = try payload.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena); + library_name = try payload.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, target); } break :options std.builtin.ExternOptions{ - .name = try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena), + .name = try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, target), .library_name = library_name, .linkage = linkage_val.toEnum(std.builtin.GlobalLinkage), .is_thread_local = is_thread_local_val.toBool(), @@ -15609,8 +15724,9 @@ fn validateVarType( ) CompileError!void { if (try sema.validateRunTimeType(block, src, var_ty, is_extern)) return; + const target = sema.mod.getTarget(); const msg = msg: { - const msg = try sema.errMsg(block, src, "variable of type '{}' must be const or comptime", .{var_ty}); + const msg = try sema.errMsg(block, src, "variable of type '{}' must be const or comptime", .{var_ty.fmt(target)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsComptime(block, src, msg, src.toSrcLoc(block.src_decl), var_ty); @@ -15685,6 +15801,7 @@ fn explainWhyTypeIsComptime( ty: Type, ) CompileError!void { const mod = sema.mod; + const target = mod.getTarget(); switch (ty.zigTypeTag()) { .Bool, .Int, @@ -15698,7 +15815,7 @@ fn explainWhyTypeIsComptime( .Fn => { try mod.errNoteNonLazy(src_loc, msg, "use '*const {}' for a function pointer type", .{ - ty, + ty.fmt(target), }); }, @@ -15941,6 +16058,8 @@ fn fieldVal( else object_ty; + const target = sema.mod.getTarget(); + switch (inner_ty.zigTypeTag()) { .Array => { if (mem.eql(u8, field_name, "len")) { @@ -15953,7 +16072,7 @@ fn fieldVal( block, field_name_src, "no member named '{s}' in '{}'", - .{ field_name, object_ty }, + .{ field_name, object_ty.fmt(target) }, ); } }, @@ -15977,7 +16096,7 @@ fn fieldVal( block, field_name_src, "no member named '{s}' in '{}'", - .{ field_name, object_ty }, + .{ field_name, object_ty.fmt(target) }, ); } } else if (ptr_info.pointee_type.zigTypeTag() == .Array) { @@ -15991,7 +16110,7 @@ fn fieldVal( block, field_name_src, "no member named '{s}' in '{}'", - .{ field_name, ptr_info.pointee_type }, + .{ field_name, ptr_info.pointee_type.fmt(target) }, ); } } @@ -16013,7 +16132,7 @@ fn fieldVal( break :blk entry.key_ptr.*; } return sema.fail(block, src, "no error named '{s}' in '{}'", .{ - field_name, child_type, + field_name, child_type.fmt(target), }); } else (try sema.mod.getErrorValue(field_name)).key; @@ -16067,10 +16186,10 @@ fn fieldVal( else => unreachable, }; return sema.fail(block, src, "{s} '{}' has no member named '{s}'", .{ - kw_name, child_type, field_name, + kw_name, child_type.fmt(target), field_name, }); }, - else => return sema.fail(block, src, "type '{}' has no members", .{child_type}), + else => return sema.fail(block, src, "type '{}' has no members", .{child_type.fmt(target)}), } }, .Struct => if (is_pointer_to) { @@ -16089,7 +16208,7 @@ fn fieldVal( }, else => {}, } - return sema.fail(block, src, "type '{}' does not support field access", .{object_ty}); + return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(target)}); } fn fieldPtr( @@ -16103,11 +16222,12 @@ fn fieldPtr( // When editing this function, note that there is corresponding logic to be edited // in `fieldVal`. This function takes a pointer and returns a pointer. + const target = sema.mod.getTarget(); const object_ptr_src = src; // TODO better source location const object_ptr_ty = sema.typeOf(object_ptr); const object_ty = switch (object_ptr_ty.zigTypeTag()) { .Pointer => object_ptr_ty.elemType(), - else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty}), + else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty.fmt(target)}), }; // Zig allows dereferencing a single pointer during field lookup. Note that @@ -16120,8 +16240,6 @@ fn fieldPtr( else object_ty; - const target = sema.mod.getTarget(); - switch (inner_ty.zigTypeTag()) { .Array => { if (mem.eql(u8, field_name, "len")) { @@ -16137,7 +16255,7 @@ fn fieldPtr( block, field_name_src, "no member named '{s}' in '{}'", - .{ field_name, object_ty }, + .{ field_name, object_ty.fmt(target) }, ); } }, @@ -16177,7 +16295,7 @@ fn fieldPtr( return sema.analyzeDeclRef(try anon_decl.finish( Type.usize, - try Value.Tag.int_u64.create(anon_decl.arena(), val.sliceLen()), + try Value.Tag.int_u64.create(anon_decl.arena(), val.sliceLen(target)), 0, // default alignment )); } @@ -16195,7 +16313,7 @@ fn fieldPtr( block, field_name_src, "no member named '{s}' in '{}'", - .{ field_name, object_ty }, + .{ field_name, object_ty.fmt(target) }, ); } }, @@ -16219,7 +16337,7 @@ fn fieldPtr( break :blk entry.key_ptr.*; } return sema.fail(block, src, "no error named '{s}' in '{}'", .{ - field_name, child_type, + field_name, child_type.fmt(target), }); } else (try sema.mod.getErrorValue(field_name)).key; @@ -16277,7 +16395,7 @@ fn fieldPtr( } return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); }, - else => return sema.fail(block, src, "type '{}' has no members", .{child_type}), + else => return sema.fail(block, src, "type '{}' has no members", .{child_type.fmt(target)}), } }, .Struct => { @@ -16296,7 +16414,7 @@ fn fieldPtr( }, else => {}, } - return sema.fail(block, src, "type '{}' does not support field access (fieldPtr, {}.{s})", .{ object_ty, object_ptr_ty, field_name }); + return sema.fail(block, src, "type '{}' does not support field access (fieldPtr, {}.{s})", .{ object_ty.fmt(target), object_ptr_ty.fmt(target), field_name }); } fn fieldCallBind( @@ -16310,12 +16428,13 @@ fn fieldCallBind( // When editing this function, note that there is corresponding logic to be edited // in `fieldVal`. This function takes a pointer and returns a pointer. + const target = sema.mod.getTarget(); const raw_ptr_src = src; // TODO better source location const raw_ptr_ty = sema.typeOf(raw_ptr); const inner_ty = if (raw_ptr_ty.zigTypeTag() == .Pointer and raw_ptr_ty.ptrSize() == .One) raw_ptr_ty.childType() else - return sema.fail(block, raw_ptr_src, "expected single pointer, found '{}'", .{raw_ptr_ty}); + return sema.fail(block, raw_ptr_src, "expected single pointer, found '{}'", .{raw_ptr_ty.fmt(target)}); // Optionally dereference a second pointer to get the concrete type. const is_double_ptr = inner_ty.zigTypeTag() == .Pointer and inner_ty.ptrSize() == .One; @@ -16375,7 +16494,7 @@ fn fieldCallBind( first_param_type.zigTypeTag() == .Pointer and (first_param_type.ptrSize() == .One or first_param_type.ptrSize() == .C) and - first_param_type.childType().eql(concrete_ty))) + first_param_type.childType().eql(concrete_ty, target))) { // zig fmt: on // TODO: bound fn calls on rvalues should probably @@ -16386,7 +16505,7 @@ fn fieldCallBind( .arg0_inst = object_ptr, }); return sema.addConstant(ty, value); - } else if (first_param_type.eql(concrete_ty)) { + } else if (first_param_type.eql(concrete_ty, target)) { var deref = try sema.analyzeLoad(block, src, object_ptr, src); const ty = Type.Tag.bound_fn.init(); const value = try Value.Tag.bound_fn.create(arena, .{ @@ -16402,7 +16521,7 @@ fn fieldCallBind( else => {}, } - return sema.fail(block, src, "type '{}' has no field or member function named '{s}'", .{ concrete_ty, field_name }); + return sema.fail(block, src, "type '{}' has no field or member function named '{s}'", .{ concrete_ty.fmt(target), field_name }); } fn finishFieldCallBind( @@ -16540,10 +16659,11 @@ fn structFieldPtrByIndex( .@"addrspace" = struct_ptr_ty_info.@"addrspace", }; + const target = sema.mod.getTarget(); + // TODO handle when the struct pointer is overaligned, we should return a potentially // over-aligned field pointer too. if (struct_obj.layout == .Packed) { - const target = sema.mod.getTarget(); comptime assert(Type.packed_struct_layout_version == 2); var running_bits: u16 = 0; @@ -16567,7 +16687,6 @@ fn structFieldPtrByIndex( ptr_ty_data.@"align" = field.abi_align; } - const target = sema.mod.getTarget(); const ptr_field_ty = try Type.ptr(sema.arena, target, ptr_ty_data); if (field.is_comptime) { @@ -16667,14 +16786,15 @@ fn tupleFieldIndex( field_name: []const u8, field_name_src: LazySrcLoc, ) CompileError!u32 { + const target = sema.mod.getTarget(); const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch |err| { return sema.fail(block, field_name_src, "tuple {} has no such field '{s}': {s}", .{ - tuple_ty, field_name, @errorName(err), + tuple_ty.fmt(target), field_name, @errorName(err), }); }; if (field_index >= tuple_ty.structFieldCount()) { return sema.fail(block, field_name_src, "tuple {} has no such field '{s}'", .{ - tuple_ty, field_name, + tuple_ty.fmt(target), field_name, }); } return field_index; @@ -16749,7 +16869,7 @@ fn unionFieldPtr( // .data = field_index, //}; //const field_tag = Value.initPayload(&field_tag_buf.base); - //const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty); + //const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, target); //if (!tag_matches) { // // TODO enhance this saying which one was active // // and which one was accessed, and showing where the union was declared. @@ -16798,7 +16918,8 @@ fn unionFieldVal( .data = field_index, }; const field_tag = Value.initPayload(&field_tag_buf.base); - const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty); + const target = sema.mod.getTarget(); + const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, target); switch (union_obj.layout) { .Auto => { if (tag_matches) { @@ -16813,7 +16934,7 @@ fn unionFieldVal( if (tag_matches) { return sema.addConstant(field.ty, tag_and_val.val); } else { - const old_ty = union_ty.unionFieldType(tag_and_val.tag); + const old_ty = union_ty.unionFieldType(tag_and_val.tag, target); const new_val = try sema.bitCastVal(block, src, tag_and_val.val, old_ty, field.ty, 0); return sema.addConstant(field.ty, new_val); } @@ -16835,19 +16956,19 @@ fn elemPtr( ) CompileError!Air.Inst.Ref { const indexable_ptr_src = src; // TODO better source location const indexable_ptr_ty = sema.typeOf(indexable_ptr); + const target = sema.mod.getTarget(); const indexable_ty = switch (indexable_ptr_ty.zigTypeTag()) { .Pointer => indexable_ptr_ty.elemType(), - else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty}), + else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(target)}), }; if (!indexable_ty.isIndexable()) { - return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty}); + return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty.fmt(target)}); } switch (indexable_ty.zigTypeTag()) { .Pointer => { // In all below cases, we have to deref the ptr operand to get the actual indexable pointer. const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); - const target = sema.mod.getTarget(); const result_ty = try indexable_ty.elemPtrType(sema.arena, target); switch (indexable_ty.ptrSize()) { .Slice => return sema.elemPtrSlice(block, indexable_ptr_src, indexable, elem_index_src, elem_index), @@ -16858,8 +16979,8 @@ fn elemPtr( const runtime_src = rs: { const ptr_val = maybe_ptr_val orelse break :rs indexable_ptr_src; const index_val = maybe_index_val orelse break :rs elem_index_src; - const index = @intCast(usize, index_val.toUnsignedInt()); - const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index); + const index = @intCast(usize, index_val.toUnsignedInt(target)); + const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index, target); return sema.addConstant(result_ty, elem_ptr); }; @@ -16876,7 +16997,7 @@ fn elemPtr( .Struct => { // Tuple field access. const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index); - const index = @intCast(u32, index_val.toUnsignedInt()); + const index = @intCast(u32, index_val.toUnsignedInt(target)); return sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index); }, else => unreachable, @@ -16893,9 +17014,10 @@ fn elemVal( ) CompileError!Air.Inst.Ref { const indexable_src = src; // TODO better source location const indexable_ty = sema.typeOf(indexable); + const target = sema.mod.getTarget(); if (!indexable_ty.isIndexable()) { - return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty}); + return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty.fmt(target)}); } // TODO in case of a vector of pointers, we need to detect whether the element @@ -16912,7 +17034,7 @@ fn elemVal( const runtime_src = rs: { const indexable_val = maybe_indexable_val orelse break :rs indexable_src; const index_val = maybe_index_val orelse break :rs elem_index_src; - const index = @intCast(usize, index_val.toUnsignedInt()); + const index = @intCast(usize, index_val.toUnsignedInt(target)); const elem_ty = indexable_ty.elemType2(); var payload: Value.Payload.ElemPtr = .{ .data = .{ @@ -16945,7 +17067,7 @@ fn elemVal( .Struct => { // Tuple field access. const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index); - const index = @intCast(u32, index_val.toUnsignedInt()); + const index = @intCast(u32, index_val.toUnsignedInt(target)); return tupleField(sema, block, indexable_src, indexable, elem_index_src, index); }, else => unreachable, @@ -17056,9 +17178,10 @@ fn elemValArray( const maybe_undef_array_val = try sema.resolveMaybeUndefVal(block, array_src, array); // index must be defined since it can access out of bounds const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); + const target = sema.mod.getTarget(); if (maybe_index_val) |index_val| { - const index = @intCast(usize, index_val.toUnsignedInt()); + const index = @intCast(usize, index_val.toUnsignedInt(target)); if (index >= array_len_s) { const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else ""; return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label }); @@ -17069,7 +17192,7 @@ fn elemValArray( return sema.addConstUndef(elem_ty); } if (maybe_index_val) |index_val| { - const index = @intCast(usize, index_val.toUnsignedInt()); + const index = @intCast(usize, index_val.toUnsignedInt(target)); const elem_val = try array_val.elemValue(sema.arena, index); return sema.addConstant(elem_ty, elem_val); } @@ -17114,7 +17237,7 @@ fn elemPtrArray( const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); if (maybe_index_val) |index_val| { - const index = @intCast(usize, index_val.toUnsignedInt()); + const index = @intCast(usize, index_val.toUnsignedInt(target)); if (index >= array_len_s) { const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else ""; return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label }); @@ -17125,8 +17248,8 @@ fn elemPtrArray( return sema.addConstUndef(elem_ptr_ty); } if (maybe_index_val) |index_val| { - const index = @intCast(usize, index_val.toUnsignedInt()); - const elem_ptr = try array_ptr_val.elemPtr(array_ptr_ty, sema.arena, index); + const index = @intCast(usize, index_val.toUnsignedInt(target)); + const elem_ptr = try array_ptr_val.elemPtr(array_ptr_ty, sema.arena, index, target); return sema.addConstant(elem_ptr_ty, elem_ptr); } } @@ -17162,16 +17285,17 @@ fn elemValSlice( const maybe_slice_val = try sema.resolveDefinedValue(block, slice_src, slice); // index must be defined since it can index out of bounds const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); + const target = sema.mod.getTarget(); if (maybe_slice_val) |slice_val| { runtime_src = elem_index_src; - const slice_len = slice_val.sliceLen(); + const slice_len = slice_val.sliceLen(target); const slice_len_s = slice_len + @boolToInt(slice_sent); if (slice_len_s == 0) { return sema.fail(block, elem_index_src, "indexing into empty slice", .{}); } if (maybe_index_val) |index_val| { - const index = @intCast(usize, index_val.toUnsignedInt()); + const index = @intCast(usize, index_val.toUnsignedInt(target)); if (index >= slice_len_s) { const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); @@ -17192,7 +17316,7 @@ fn elemValSlice( try sema.requireRuntimeBlock(block, runtime_src); if (block.wantSafety()) { const len_inst = if (maybe_slice_val) |slice_val| - try sema.addIntUnsigned(Type.usize, slice_val.sliceLen()) + try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(target)) else try block.addTyOp(.slice_len, Type.usize, slice); const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; @@ -17223,18 +17347,18 @@ fn elemPtrSlice( if (slice_val.isUndef()) { return sema.addConstUndef(elem_ptr_ty); } - const slice_len = slice_val.sliceLen(); + const slice_len = slice_val.sliceLen(target); const slice_len_s = slice_len + @boolToInt(slice_sent); if (slice_len_s == 0) { return sema.fail(block, elem_index_src, "indexing into empty slice", .{}); } if (maybe_index_val) |index_val| { - const index = @intCast(usize, index_val.toUnsignedInt()); + const index = @intCast(usize, index_val.toUnsignedInt(target)); if (index >= slice_len_s) { const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); } - const elem_ptr_val = try slice_val.elemPtr(slice_ty, sema.arena, index); + const elem_ptr_val = try slice_val.elemPtr(slice_ty, sema.arena, index, target); return sema.addConstant(elem_ptr_ty, elem_ptr_val); } } @@ -17245,7 +17369,7 @@ fn elemPtrSlice( const len_inst = len: { if (maybe_undef_slice_val) |slice_val| if (!slice_val.isUndef()) - break :len try sema.addIntUnsigned(Type.usize, slice_val.sliceLen()); + break :len try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(target)); break :len try block.addTyOp(.slice_len, Type.usize, slice); }; const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; @@ -17270,12 +17394,12 @@ fn coerce( const dest_ty_src = inst_src; // TODO better source location const dest_ty = try sema.resolveTypeFields(block, dest_ty_src, dest_ty_unresolved); const inst_ty = try sema.resolveTypeFields(block, inst_src, sema.typeOf(inst)); + const target = sema.mod.getTarget(); // If the types are the same, we can return the operand. - if (dest_ty.eql(inst_ty)) + if (dest_ty.eql(inst_ty, target)) return inst; const arena = sema.arena; - const target = sema.mod.getTarget(); const maybe_inst_val = try sema.resolveMaybeUndefVal(block, inst_src, inst); const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src); @@ -17379,7 +17503,7 @@ fn coerce( // *[N:s]T to [*]T if (dest_info.sentinel) |dst_sentinel| { if (array_ty.sentinel()) |src_sentinel| { - if (src_sentinel.eql(dst_sentinel, dst_elem_type)) { + if (src_sentinel.eql(dst_sentinel, dst_elem_type, target)) { return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); } } @@ -17448,7 +17572,7 @@ fn coerce( } if (inst_info.size == .Slice) { if (dest_info.sentinel == null or inst_info.sentinel == null or - !dest_info.sentinel.?.eql(inst_info.sentinel.?, dest_info.pointee_type)) + !dest_info.sentinel.?.eql(inst_info.sentinel.?, dest_info.pointee_type, target)) break :p; const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty); @@ -17515,7 +17639,7 @@ fn coerce( } if (dest_info.sentinel == null or inst_info.sentinel == null or - !dest_info.sentinel.?.eql(inst_info.sentinel.?, dest_info.pointee_type)) + !dest_info.sentinel.?.eql(inst_info.sentinel.?, dest_info.pointee_type, target)) break :p; const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty); @@ -17528,11 +17652,11 @@ fn coerce( const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse break :float; if (val.floatHasFraction()) { - return sema.fail(block, inst_src, "fractional component prevents float value {} from coercion to type '{}'", .{ val.fmtValue(inst_ty), dest_ty }); + return sema.fail(block, inst_src, "fractional component prevents float value {} from coercion to type '{}'", .{ val.fmtValue(inst_ty, target), dest_ty.fmt(target) }); } const result_val = val.floatToInt(sema.arena, inst_ty, dest_ty, target) catch |err| switch (err) { error.FloatCannotFit => { - return sema.fail(block, inst_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty }); + return sema.fail(block, inst_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty.fmt(target) }); }, else => |e| return e, }; @@ -17542,7 +17666,7 @@ fn coerce( if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| { // comptime known integer to other number if (!val.intFitsInType(dest_ty, target)) { - return sema.fail(block, inst_src, "type {} cannot represent integer value {}", .{ dest_ty, val.fmtValue(inst_ty) }); + return sema.fail(block, inst_src, "type {} cannot represent integer value {}", .{ dest_ty.fmt(target), val.fmtValue(inst_ty, target) }); } return try sema.addConstant(dest_ty, val); } @@ -17572,12 +17696,12 @@ fn coerce( .Float => { if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| { const result_val = try val.floatCast(sema.arena, dest_ty, target); - if (!val.eql(result_val, dest_ty)) { + if (!val.eql(result_val, dest_ty, target)) { return sema.fail( block, inst_src, "type {} cannot represent float value {}", - .{ dest_ty, val.fmtValue(inst_ty) }, + .{ dest_ty.fmt(target), val.fmtValue(inst_ty, target) }, ); } return try sema.addConstant(dest_ty, result_val); @@ -17596,12 +17720,12 @@ fn coerce( const result_val = try val.intToFloat(sema.arena, inst_ty, dest_ty, target); // TODO implement this compile error //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty); - //if (!int_again_val.eql(val, inst_ty)) { + //if (!int_again_val.eql(val, inst_ty, target)) { // return sema.fail( // block, // inst_src, // "type {} cannot represent integer value {}", - // .{ dest_ty, val }, + // .{ dest_ty.fmt(target), val }, // ); //} return try sema.addConstant(dest_ty, result_val); @@ -17622,7 +17746,7 @@ fn coerce( block, inst_src, "enum '{}' has no field named '{s}'", - .{ dest_ty, bytes }, + .{ dest_ty.fmt(target), bytes }, ); errdefer msg.destroy(sema.gpa); try sema.mod.errNoteNonLazy( @@ -17643,7 +17767,7 @@ fn coerce( .Union => blk: { // union to its own tag type const union_tag_ty = inst_ty.unionTagType() orelse break :blk; - if (union_tag_ty.eql(dest_ty)) { + if (union_tag_ty.eql(dest_ty, target)) { return sema.unionToTag(block, dest_ty, inst, inst_src); } }, @@ -17743,7 +17867,7 @@ fn coerce( return sema.addConstUndef(dest_ty); } - return sema.fail(block, inst_src, "expected {}, found {}", .{ dest_ty, inst_ty }); + return sema.fail(block, inst_src, "expected {}, found {}", .{ dest_ty.fmt(target), inst_ty.fmt(target) }); } const InMemoryCoercionResult = enum { @@ -17772,7 +17896,7 @@ fn coerceInMemoryAllowed( dest_src: LazySrcLoc, src_src: LazySrcLoc, ) CompileError!InMemoryCoercionResult { - if (dest_ty.eql(src_ty)) + if (dest_ty.eql(src_ty, target)) return .ok; // Pointers / Pointer-like Optionals @@ -17823,7 +17947,7 @@ fn coerceInMemoryAllowed( } const ok_sent = dest_info.sentinel == null or (src_info.sentinel != null and - dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type)); + dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type, target)); if (!ok_sent) { return .no_match; } @@ -18050,7 +18174,7 @@ fn coerceInMemoryAllowedPtrs( const ok_sent = dest_info.sentinel == null or src_info.size == .C or (src_info.sentinel != null and - dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type)); + dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, target)); if (!ok_sent) { return .no_match; } @@ -18091,7 +18215,7 @@ fn coerceInMemoryAllowedPtrs( // resolved and we compare the alignment numerically. alignment: { if (src_info.@"align" == 0 and dest_info.@"align" == 0 and - dest_info.pointee_type.eql(src_info.pointee_type)) + dest_info.pointee_type.eql(src_info.pointee_type, target)) { break :alignment; } @@ -18246,7 +18370,8 @@ fn obtainBitCastedVectorPtr(sema: *Sema, ptr: Air.Inst.Ref) ?Air.Inst.Ref { // We have a pointer-to-array and a pointer-to-vector. If the elements and // lengths match, return the result. const vector_ty = sema.typeOf(prev_ptr).childType(); - if (array_ty.childType().eql(vector_ty.childType()) and + const target = sema.mod.getTarget(); + if (array_ty.childType().eql(vector_ty.childType(), target) and array_ty.arrayLen() == vector_ty.vectorLen()) { return prev_ptr; @@ -18668,10 +18793,10 @@ fn beginComptimePtrLoad( 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.isArrayLike() and load_ty.childType().eql(elem_ty)) { + if (load_ty.isArrayLike() and load_ty.childType().eql(elem_ty, target)) { const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel()); deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{ - .ty = try Type.array(sema.arena, N, null, elem_ty), + .ty = try Type.array(sema.arena, N, null, elem_ty, target), .val = try array_tv.val.sliceArray(sema.arena, elem_ptr.index, elem_ptr.index + N), } else null; break :blk deref; @@ -18807,11 +18932,11 @@ pub fn bitCastVal( new_ty: Type, buffer_offset: usize, ) !Value { - if (old_ty.eql(new_ty)) return val; + const target = sema.mod.getTarget(); + if (old_ty.eql(new_ty, target)) return val; // For types with well-defined memory layouts, we serialize them a byte buffer, // then deserialize to the new type. - const target = sema.mod.getTarget(); const abi_size = try sema.usizeCast(block, src, old_ty.abiSize(target)); const buffer = try sema.gpa.alloc(u8, abi_size); defer sema.gpa.free(buffer); @@ -18864,11 +18989,12 @@ fn coerceEnumToUnion( inst_src: LazySrcLoc, ) !Air.Inst.Ref { const inst_ty = sema.typeOf(inst); + const target = sema.mod.getTarget(); const tag_ty = union_ty.unionTagType() orelse { const msg = msg: { const msg = try sema.errMsg(block, inst_src, "expected {}, found {}", .{ - union_ty, inst_ty, + union_ty.fmt(target), inst_ty.fmt(target), }); errdefer msg.destroy(sema.gpa); try sema.errNote(block, union_ty_src, msg, "cannot coerce enum to untagged union", .{}); @@ -18881,10 +19007,10 @@ fn coerceEnumToUnion( const enum_tag = try sema.coerce(block, tag_ty, inst, inst_src); if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| { const union_obj = union_ty.cast(Type.Payload.Union).?.data; - const field_index = union_obj.tag_ty.enumTagFieldIndex(val) orelse { + const field_index = union_obj.tag_ty.enumTagFieldIndex(val, target) orelse { const msg = msg: { const msg = try sema.errMsg(block, inst_src, "union {} has no tag with value {}", .{ - union_ty, val.fmtValue(tag_ty), + union_ty.fmt(target), val.fmtValue(tag_ty, target), }); errdefer msg.destroy(sema.gpa); try sema.addDeclaredHereNote(msg, union_ty); @@ -18899,7 +19025,7 @@ fn coerceEnumToUnion( // also instead of 'union declared here' make it 'field "foo" declared here'. const msg = msg: { const msg = try sema.errMsg(block, inst_src, "coercion to union {} must initialize {} field", .{ - union_ty, field_ty, + union_ty.fmt(target), field_ty.fmt(target), }); errdefer msg.destroy(sema.gpa); try sema.addDeclaredHereNote(msg, union_ty); @@ -18919,7 +19045,7 @@ fn coerceEnumToUnion( if (tag_ty.isNonexhaustiveEnum()) { const msg = msg: { const msg = try sema.errMsg(block, inst_src, "runtime coercion to union {} from non-exhaustive enum", .{ - union_ty, + union_ty.fmt(target), }); errdefer msg.destroy(sema.gpa); try sema.addDeclaredHereNote(msg, tag_ty); @@ -18937,7 +19063,7 @@ fn coerceEnumToUnion( // instead of the "union declared here" hint const msg = msg: { const msg = try sema.errMsg(block, inst_src, "runtime coercion to union {} which has non-void fields", .{ - union_ty, + union_ty.fmt(target), }); errdefer msg.destroy(sema.gpa); try sema.addDeclaredHereNote(msg, union_ty); @@ -19020,11 +19146,12 @@ fn coerceArrayLike( const inst_ty = sema.typeOf(inst); const inst_len = inst_ty.arrayLen(); const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen()); + const target = sema.mod.getTarget(); if (dest_len != inst_len) { const msg = msg: { const msg = try sema.errMsg(block, inst_src, "expected {}, found {}", .{ - dest_ty, inst_ty, + dest_ty.fmt(target), inst_ty.fmt(target), }); errdefer msg.destroy(sema.gpa); try sema.errNote(block, dest_ty_src, msg, "destination has length {d}", .{dest_len}); @@ -19034,7 +19161,6 @@ fn coerceArrayLike( return sema.failWithOwnedErrorMsg(block, msg); } - const target = sema.mod.getTarget(); const dest_elem_ty = dest_ty.childType(); const inst_elem_ty = inst_ty.childType(); const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_elem_ty, inst_elem_ty, false, target, dest_ty_src, inst_src); @@ -19092,11 +19218,12 @@ fn coerceTupleToArray( const inst_ty = sema.typeOf(inst); const inst_len = inst_ty.arrayLen(); const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen()); + const target = sema.mod.getTarget(); if (dest_len != inst_len) { const msg = msg: { const msg = try sema.errMsg(block, inst_src, "expected {}, found {}", .{ - dest_ty, inst_ty, + dest_ty.fmt(target), inst_ty.fmt(target), }); errdefer msg.destroy(sema.gpa); try sema.errNote(block, dest_ty_src, msg, "destination has length {d}", .{dest_len}); @@ -19149,7 +19276,8 @@ fn coerceTupleToSlicePtrs( const tuple_ty = sema.typeOf(ptr_tuple).childType(); const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src); const slice_info = slice_ty.ptrInfo().data; - const array_ty = try Type.array(sema.arena, tuple_ty.structFieldCount(), slice_info.sentinel, slice_info.pointee_type); + const target = sema.mod.getTarget(); + const array_ty = try Type.array(sema.arena, tuple_ty.structFieldCount(), slice_info.sentinel, slice_info.pointee_type, target); const array_inst = try sema.coerceTupleToArray(block, array_ty, slice_ty_src, tuple, tuple_src); if (slice_info.@"align" != 0) { return sema.fail(block, slice_ty_src, "TODO: override the alignment of the array decl we create here", .{}); @@ -19398,10 +19526,11 @@ fn analyzeLoad( ptr: Air.Inst.Ref, ptr_src: LazySrcLoc, ) CompileError!Air.Inst.Ref { + const target = sema.mod.getTarget(); const ptr_ty = sema.typeOf(ptr); const elem_ty = switch (ptr_ty.zigTypeTag()) { .Pointer => ptr_ty.childType(), - else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty}), + else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(target)}), }; if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { if (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) |elem_val| { @@ -19440,7 +19569,8 @@ fn analyzeSliceLen( if (slice_val.isUndef()) { return sema.addConstUndef(Type.usize); } - return sema.addIntUnsigned(Type.usize, slice_val.sliceLen()); + const target = sema.mod.getTarget(); + return sema.addIntUnsigned(Type.usize, slice_val.sliceLen(target)); } try sema.requireRuntimeBlock(block, src); return block.addTyOp(.slice_len, Type.usize, slice_inst); @@ -19522,9 +19652,10 @@ fn analyzeSlice( // Slice expressions can operate on a variable whose type is an array. This requires // the slice operand to be a pointer. In the case of a non-array, it will be a double pointer. const ptr_ptr_ty = sema.typeOf(ptr_ptr); + const target = sema.mod.getTarget(); const ptr_ptr_child_ty = switch (ptr_ptr_ty.zigTypeTag()) { .Pointer => ptr_ptr_ty.elemType(), - else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty}), + else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(target)}), }; var array_ty = ptr_ptr_child_ty; @@ -19564,7 +19695,7 @@ fn analyzeSlice( elem_ty = ptr_ptr_child_ty.childType(); }, }, - else => return sema.fail(block, ptr_src, "slice of non-array type '{}'", .{ptr_ptr_child_ty}), + else => return sema.fail(block, ptr_src, "slice of non-array type '{}'", .{ptr_ptr_child_ty.fmt(target)}), } const ptr = if (slice_ty.isSlice()) @@ -19587,7 +19718,7 @@ fn analyzeSlice( if (!end_is_len) { const end = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); if (try sema.resolveMaybeUndefVal(block, end_src, end)) |end_val| { - if (end_val.compare(.gt, len_val, Type.usize)) { + if (end_val.compare(.gt, len_val, Type.usize, target)) { return sema.fail( block, end_src, @@ -19595,7 +19726,7 @@ fn analyzeSlice( .{ end_val.fmtValue(Type.usize), len_val.fmtValue(Type.usize) }, ); } - if (end_val.eql(len_val, Type.usize)) { + if (end_val.eql(len_val, Type.usize, target)) { end_is_len = true; } } @@ -19610,10 +19741,10 @@ fn analyzeSlice( if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| { var int_payload: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, - .data = slice_val.sliceLen(), + .data = slice_val.sliceLen(target), }; const slice_len_val = Value.initPayload(&int_payload.base); - if (end_val.compare(.gt, slice_len_val, Type.usize)) { + if (end_val.compare(.gt, slice_len_val, Type.usize, target)) { return sema.fail( block, end_src, @@ -19621,7 +19752,7 @@ fn analyzeSlice( .{ end_val.fmtValue(Type.usize), slice_len_val.fmtValue(Type.usize) }, ); } - if (end_val.eql(slice_len_val, Type.usize)) { + if (end_val.eql(slice_len_val, Type.usize, target)) { end_is_len = true; } } @@ -19670,13 +19801,12 @@ fn analyzeSlice( const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data; const new_allowzero = new_ptr_ty_info.@"allowzero" and sema.typeOf(ptr).ptrSize() != .C; - const target = sema.mod.getTarget(); if (opt_new_len_val) |new_len_val| { - const new_len_int = new_len_val.toUnsignedInt(); + const new_len_int = new_len_val.toUnsignedInt(target); const return_ty = try Type.ptr(sema.arena, target, .{ - .pointee_type = try Type.array(sema.arena, new_len_int, sentinel, elem_ty), + .pointee_type = try Type.array(sema.arena, new_len_int, sentinel, elem_ty, target), .sentinel = null, .@"align" = new_ptr_ty_info.@"align", .@"addrspace" = new_ptr_ty_info.@"addrspace", @@ -19746,6 +19876,7 @@ fn cmpNumeric( const lhs_ty_tag = lhs_ty.zigTypeTag(); const rhs_ty_tag = rhs_ty.zigTypeTag(); + const target = sema.mod.getTarget(); const runtime_src: LazySrcLoc = src: { if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| { @@ -19760,7 +19891,7 @@ fn cmpNumeric( return Air.Inst.Ref.bool_false; } } - if (Value.compareHetero(lhs_val, op, rhs_val)) { + if (Value.compareHetero(lhs_val, op, rhs_val, target)) { return Air.Inst.Ref.bool_true; } else { return Air.Inst.Ref.bool_false; @@ -19789,7 +19920,6 @@ fn cmpNumeric( .Float, .ComptimeFloat => true, else => false, }; - const target = sema.mod.getTarget(); if (lhs_is_float and rhs_is_float) { // Implicit cast the smaller one to the larger one. const dest_ty = x: { @@ -19846,7 +19976,7 @@ fn cmpNumeric( } if (lhs_is_float) { var bigint_space: Value.BigIntSpace = undefined; - var bigint = try lhs_val.toBigInt(&bigint_space).toManaged(sema.gpa); + var bigint = try lhs_val.toBigInt(&bigint_space, target).toManaged(sema.gpa); defer bigint.deinit(); if (lhs_val.floatHasFraction()) { switch (op) { @@ -19892,7 +20022,7 @@ fn cmpNumeric( } if (rhs_is_float) { var bigint_space: Value.BigIntSpace = undefined; - var bigint = try rhs_val.toBigInt(&bigint_space).toManaged(sema.gpa); + var bigint = try rhs_val.toBigInt(&bigint_space, target).toManaged(sema.gpa); defer bigint.deinit(); if (rhs_val.floatHasFraction()) { switch (op) { @@ -19950,6 +20080,7 @@ fn cmpVector( try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); const result_ty = try Type.vector(sema.arena, lhs_ty.vectorLen(), Type.@"bool"); + const target = sema.mod.getTarget(); const runtime_src: LazySrcLoc = src: { if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| { @@ -19957,7 +20088,7 @@ fn cmpVector( if (lhs_val.isUndef() or rhs_val.isUndef()) { return sema.addConstUndef(result_ty); } - const cmp_val = try lhs_val.compareVector(op, rhs_val, lhs_ty, sema.arena); + const cmp_val = try lhs_val.compareVector(op, rhs_val, lhs_ty, sema.arena, target); return sema.addConstant(result_ty, cmp_val); } else { break :src rhs_src; @@ -20108,7 +20239,7 @@ fn resolvePeerTypes( const candidate_ty_tag = try candidate_ty.zigTypeTagOrPoison(); const chosen_ty_tag = try chosen_ty.zigTypeTagOrPoison(); - if (candidate_ty.eql(chosen_ty)) + if (candidate_ty.eql(chosen_ty, target)) continue; switch (candidate_ty_tag) { @@ -20522,14 +20653,17 @@ fn resolvePeerTypes( ); const msg = msg: { - const msg = try sema.errMsg(block, src, "incompatible types: '{}' and '{}'", .{ chosen_ty, candidate_ty }); + const msg = try sema.errMsg(block, src, "incompatible types: '{}' and '{}'", .{ + chosen_ty.fmt(target), + candidate_ty.fmt(target), + }); errdefer msg.destroy(sema.gpa); if (chosen_src) |src_loc| - try sema.errNote(block, src_loc, msg, "type '{}' here", .{chosen_ty}); + try sema.errNote(block, src_loc, msg, "type '{}' here", .{chosen_ty.fmt(target)}); if (candidate_src) |src_loc| - try sema.errNote(block, src_loc, msg, "type '{}' here", .{candidate_ty}); + try sema.errNote(block, src_loc, msg, "type '{}' here", .{candidate_ty.fmt(target)}); break :msg msg; }; @@ -20557,7 +20691,7 @@ fn resolvePeerTypes( else new_ptr_ty; const set_ty = err_set_ty orelse return opt_ptr_ty; - return try Module.errorUnionType(sema.arena, set_ty, opt_ptr_ty); + return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, target); } if (seen_const) { @@ -20573,7 +20707,7 @@ fn resolvePeerTypes( else new_ptr_ty; const set_ty = err_set_ty orelse chosen_ty.errorUnionSet(); - return try Module.errorUnionType(sema.arena, set_ty, opt_ptr_ty); + return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, target); }, .Pointer => { var info = chosen_ty.ptrInfo(); @@ -20584,7 +20718,7 @@ fn resolvePeerTypes( else new_ptr_ty; const set_ty = err_set_ty orelse return opt_ptr_ty; - return try Module.errorUnionType(sema.arena, set_ty, opt_ptr_ty); + return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, target); }, else => return chosen_ty, } @@ -20596,16 +20730,16 @@ fn resolvePeerTypes( else => try Type.optional(sema.arena, chosen_ty), }; const set_ty = err_set_ty orelse return opt_ty; - return try Module.errorUnionType(sema.arena, set_ty, opt_ty); + return try Type.errorUnion(sema.arena, set_ty, opt_ty, target); } if (err_set_ty) |ty| switch (chosen_ty.zigTypeTag()) { .ErrorSet => return ty, .ErrorUnion => { const payload_ty = chosen_ty.errorUnionPayload(); - return try Module.errorUnionType(sema.arena, ty, payload_ty); + return try Type.errorUnion(sema.arena, ty, payload_ty, target); }, - else => return try Module.errorUnionType(sema.arena, ty, chosen_ty), + else => return try Type.errorUnion(sema.arena, ty, chosen_ty, target), }; return chosen_ty; @@ -20662,11 +20796,12 @@ fn resolveStructLayout( ) CompileError!void { const resolved_ty = try sema.resolveTypeFields(block, src, ty); if (resolved_ty.castTag(.@"struct")) |payload| { + const target = sema.mod.getTarget(); const struct_obj = payload.data; switch (struct_obj.status) { .none, .have_field_types => {}, .field_types_wip, .layout_wip => { - return sema.fail(block, src, "struct {} depends on itself", .{ty}); + return sema.fail(block, src, "struct {} depends on itself", .{ty.fmt(target)}); }, .have_layout, .fully_resolved_wip, .fully_resolved => return, } @@ -20694,10 +20829,11 @@ fn resolveUnionLayout( ) CompileError!void { const resolved_ty = try sema.resolveTypeFields(block, src, ty); const union_obj = resolved_ty.cast(Type.Payload.Union).?.data; + const target = sema.mod.getTarget(); switch (union_obj.status) { .none, .have_field_types => {}, .field_types_wip, .layout_wip => { - return sema.fail(block, src, "union {} depends on itself", .{ty}); + return sema.fail(block, src, "union {} depends on itself", .{ty.fmt(target)}); }, .have_layout, .fully_resolved_wip, .fully_resolved => return, } @@ -20828,10 +20964,11 @@ fn resolveTypeFieldsStruct( ty: Type, struct_obj: *Module.Struct, ) CompileError!void { + const target = sema.mod.getTarget(); switch (struct_obj.status) { .none => {}, .field_types_wip => { - return sema.fail(block, src, "struct {} depends on itself", .{ty}); + return sema.fail(block, src, "struct {} depends on itself", .{ty.fmt(target)}); }, .have_field_types, .have_layout, @@ -20858,10 +20995,11 @@ fn resolveTypeFieldsUnion( ty: Type, union_obj: *Module.Union, ) CompileError!void { + const target = sema.mod.getTarget(); switch (union_obj.status) { .none => {}, .field_types_wip => { - return sema.fail(block, src, "union {} depends on itself", .{ty}); + return sema.fail(block, src, "union {} depends on itself", .{ty.fmt(target)}); }, .have_field_types, .have_layout, @@ -21218,6 +21356,8 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields; } + const target = sema.mod.getTarget(); + const bits_per_field = 4; const fields_per_u32 = 32 / bits_per_field; const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; @@ -21275,16 +21415,22 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { // This puts the memory into the union arena, not the enum arena, but // it is OK since they share the same lifetime. const copied_val = try val.copy(decl_arena_allocator); - map.putAssumeCapacityContext(copied_val, {}, .{ .ty = int_tag_ty }); + map.putAssumeCapacityContext(copied_val, {}, .{ + .ty = int_tag_ty, + .target = target, + }); } else { const val = if (last_tag_val) |val| - try val.intAdd(Value.one, int_tag_ty, sema.arena) + try val.intAdd(Value.one, int_tag_ty, sema.arena, target) else Value.zero; last_tag_val = val; const copied_val = try val.copy(decl_arena_allocator); - map.putAssumeCapacityContext(copied_val, {}, .{ .ty = int_tag_ty }); + map.putAssumeCapacityContext(copied_val, {}, .{ + .ty = int_tag_ty, + .target = target, + }); } } @@ -21359,7 +21505,10 @@ fn generateUnionTagTypeNumbered( }; // Here we pre-allocate the maps using the decl arena. try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); - try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{ .ty = int_ty }); + try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{ + .ty = int_ty, + .target = sema.mod.getTarget(), + }); try new_decl.finalizeNewArena(&new_decl_arena); return enum_ty; } @@ -21962,7 +22111,7 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr // The type is not in-memory coercible or the direct dereference failed, so it must // be bitcast according to the pointer type we are performing the load through. if (!load_ty.hasWellDefinedLayout()) - return sema.fail(block, src, "comptime dereference requires {} to have a well-defined layout, but it does not.", .{load_ty}); + return sema.fail(block, src, "comptime dereference requires {} to have a well-defined layout, but it does not.", .{load_ty.fmt(target)}); const load_sz = try sema.typeAbiSize(block, src, load_ty); @@ -21977,11 +22126,11 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr 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 sema.fail(block, src, "comptime dereference requires {} to have a well-defined layout, but it does not.", .{bad_ty}); + return sema.fail(block, src, "comptime dereference requires {} to have a well-defined layout, but it does not.", .{bad_ty.fmt(target)}); } 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 sema.fail(block, src, "dereference of {} exceeds bounds of containing decl of type {}", .{ ptr_ty, deref.parent.?.tv.ty }); + return sema.fail(block, src, "dereference of {} exceeds bounds of containing decl of type {}", .{ ptr_ty.fmt(target), deref.parent.?.tv.ty.fmt(target) }); } } @@ -22344,7 +22493,8 @@ fn anonStructFieldIndex( return @intCast(u32, i); } } + const target = sema.mod.getTarget(); return sema.fail(block, field_src, "anonymous struct {} has no such field '{s}'", .{ - struct_ty, field_name, + struct_ty.fmt(target), field_name, }); } diff --git a/src/TypedValue.zig b/src/TypedValue.zig index fc5ef45991..b4be670e19 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -3,6 +3,7 @@ const Type = @import("type.zig").Type; const Value = @import("value.zig").Value; const Allocator = std.mem.Allocator; const TypedValue = @This(); +const Target = std.Target; ty: Type, val: Value, @@ -30,13 +31,13 @@ pub fn copy(self: TypedValue, arena: Allocator) error{OutOfMemory}!TypedValue { }; } -pub fn eql(a: TypedValue, b: TypedValue) bool { - if (!a.ty.eql(b.ty)) return false; - return a.val.eql(b.val, a.ty); +pub fn eql(a: TypedValue, b: TypedValue, target: std.Target) bool { + if (!a.ty.eql(b.ty, target)) return false; + return a.val.eql(b.val, a.ty, target); } -pub fn hash(tv: TypedValue, hasher: *std.hash.Wyhash) void { - return tv.val.hash(tv.ty, hasher); +pub fn hash(tv: TypedValue, hasher: *std.hash.Wyhash, target: std.Target) void { + return tv.val.hash(tv.ty, hasher, target); } pub fn enumToInt(tv: TypedValue, buffer: *Value.Payload.U64) Value { @@ -45,21 +46,28 @@ pub fn enumToInt(tv: TypedValue, buffer: *Value.Payload.U64) Value { const max_aggregate_items = 100; -pub fn format( +const FormatContext = struct { tv: TypedValue, + target: Target, +}; + +pub fn format( + ctx: FormatContext, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype, ) !void { + _ = options; comptime std.debug.assert(fmt.len == 0); - return tv.print(options, writer, 3); + return ctx.tv.print(writer, 3, ctx.target); } +/// Prints the Value according to the Type, not according to the Value Tag. pub fn print( tv: TypedValue, - options: std.fmt.FormatOptions, writer: anytype, level: u8, + target: std.Target, ) @TypeOf(writer).Error!void { var val = tv.val; var ty = tv.ty; @@ -148,7 +156,7 @@ pub fn print( try print(.{ .ty = fields[i].ty, .val = vals[i], - }, options, writer, level - 1); + }, writer, level - 1, target); } return writer.writeAll(" }"); } else { @@ -162,7 +170,7 @@ pub fn print( try print(.{ .ty = elem_ty, .val = vals[i], - }, options, writer, level - 1); + }, writer, level - 1, target); } return writer.writeAll(" }"); } @@ -177,12 +185,12 @@ pub fn print( try print(.{ .ty = ty.unionTagType().?, .val = union_val.tag, - }, options, writer, level - 1); + }, writer, level - 1, target); try writer.writeAll(" = "); try print(.{ - .ty = ty.unionFieldType(union_val.tag), + .ty = ty.unionFieldType(union_val.tag, target), .val = union_val.val, - }, options, writer, level - 1); + }, writer, level - 1, target); return writer.writeAll(" }"); }, @@ -197,7 +205,7 @@ pub fn print( }, .bool_true => return writer.writeAll("true"), .bool_false => return writer.writeAll("false"), - .ty => return val.castTag(.ty).?.data.format("", options, writer), + .ty => return val.castTag(.ty).?.data.print(writer, target), .int_type => { const int_type = val.castTag(.int_type).?.data; return writer.print("{s}{d}", .{ @@ -205,10 +213,15 @@ pub fn print( int_type.bits, }); }, - .int_u64 => return std.fmt.formatIntValue(val.castTag(.int_u64).?.data, "", options, writer), - .int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", options, writer), + .int_u64 => return std.fmt.formatIntValue(val.castTag(.int_u64).?.data, "", .{}, writer), + .int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", .{}, writer), .int_big_positive => return writer.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}), .int_big_negative => return writer.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}), + .lazy_align => { + const sub_ty = val.castTag(.lazy_align).?.data; + const x = sub_ty.abiAlignment(target); + return writer.print("{d}", .{x}); + }, .function => return writer.print("(function '{s}')", .{val.castTag(.function).?.data.owner_decl.name}), .extern_fn => return writer.writeAll("(extern function)"), .variable => return writer.writeAll("(variable)"), @@ -220,7 +233,7 @@ pub fn print( return print(.{ .ty = decl.ty, .val = decl.val, - }, options, writer, level - 1); + }, writer, level - 1, target); }, .decl_ref => { const decl = val.castTag(.decl_ref).?.data; @@ -230,7 +243,7 @@ pub fn print( return print(.{ .ty = decl.ty, .val = decl.val, - }, options, writer, level - 1); + }, writer, level - 1, target); }, .elem_ptr => { const elem_ptr = val.castTag(.elem_ptr).?.data; @@ -238,7 +251,7 @@ pub fn print( try print(.{ .ty = elem_ptr.elem_ty, .val = elem_ptr.array_ptr, - }, options, writer, level - 1); + }, writer, level - 1, target); return writer.print("[{}]", .{elem_ptr.index}); }, .field_ptr => { @@ -247,7 +260,7 @@ pub fn print( try print(.{ .ty = field_ptr.container_ty, .val = field_ptr.container_ptr, - }, options, writer, level - 1); + }, writer, level - 1, target); if (field_ptr.container_ty.zigTypeTag() == .Struct) { const field_name = field_ptr.container_ty.structFields().keys()[field_ptr.field_index]; @@ -275,7 +288,7 @@ pub fn print( }; while (i < max_aggregate_items) : (i += 1) { if (i != 0) try writer.writeAll(", "); - try print(elem_tv, options, writer, level - 1); + try print(elem_tv, writer, level - 1, target); } return writer.writeAll(" }"); }, @@ -287,7 +300,7 @@ pub fn print( try print(.{ .ty = ty.elemType2(), .val = ty.sentinel().?, - }, options, writer, level - 1); + }, writer, level - 1, target); return writer.writeAll(" }"); }, .slice => return writer.writeAll("(slice)"), diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 9c2d5890a7..8e502e8943 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -796,7 +796,9 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { const index = dbg_out.dbg_info.items.len; try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 - const gop = try dbg_out.dbg_info_type_relocs.getOrPut(self.gpa, ty); + const gop = try dbg_out.dbg_info_type_relocs.getOrPutContext(self.gpa, ty, .{ + .target = self.target.*, + }); if (!gop.found_existing) { gop.value_ptr.* = .{ .off = undefined, @@ -835,8 +837,9 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { return self.next_stack_offset; } + const target = self.target.*; const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch { - return self.fail("type '{}' too big to fit into stack frame", .{elem_ty}); + return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(target)}); }; // TODO swap this for inst.ty.ptrAlign const abi_align = elem_ty.abiAlignment(self.target.*); @@ -845,8 +848,9 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { const elem_ty = self.air.typeOfIndex(inst); + const target = self.target.*; const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch { - return self.fail("type '{}' too big to fit into stack frame", .{elem_ty}); + return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(target)}); }; const abi_align = elem_ty.abiAlignment(self.target.*); if (abi_align > self.stack_align) @@ -1372,6 +1376,7 @@ fn binOp( lhs_ty: Type, rhs_ty: Type, ) InnerError!MCValue { + const target = self.target.*; switch (tag) { // Arithmetic operations on integers and floats .add, @@ -1381,7 +1386,7 @@ fn binOp( .Float => return self.fail("TODO binary operations on floats", .{}), .Vector => return self.fail("TODO binary operations on vectors", .{}), .Int => { - assert(lhs_ty.eql(rhs_ty)); + assert(lhs_ty.eql(rhs_ty, target)); const int_info = lhs_ty.intInfo(self.target.*); if (int_info.bits <= 64) { // Only say yes if the operation is @@ -1418,7 +1423,7 @@ fn binOp( switch (lhs_ty.zigTypeTag()) { .Vector => return self.fail("TODO binary operations on vectors", .{}), .Int => { - assert(lhs_ty.eql(rhs_ty)); + assert(lhs_ty.eql(rhs_ty, target)); const int_info = lhs_ty.intInfo(self.target.*); if (int_info.bits <= 64) { // TODO add optimisations for multiplication @@ -1440,7 +1445,7 @@ fn binOp( switch (lhs_ty.zigTypeTag()) { .Vector => return self.fail("TODO binary operations on vectors", .{}), .Int => { - assert(lhs_ty.eql(rhs_ty)); + assert(lhs_ty.eql(rhs_ty, target)); const int_info = lhs_ty.intInfo(self.target.*); if (int_info.bits <= 64) { // TODO implement bitwise operations with immediates @@ -2348,11 +2353,12 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { const ty = self.air.typeOfIndex(inst); const result = self.args[arg_index]; + const target = self.target.*; const mcv = switch (result) { // Copy registers to the stack .register => |reg| blk: { const abi_size = math.cast(u32, ty.abiSize(self.target.*)) catch { - return self.fail("type '{}' too big to fit into stack frame", .{ty}); + return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(target)}); }; const abi_align = ty.abiAlignment(self.target.*); const stack_offset = try self.allocMem(inst, abi_size, abi_align); @@ -3879,7 +3885,7 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa } fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { - log.debug("lowerUnnamedConst: ty = {}, val = {}", .{ tv.ty, tv.val.fmtDebug() }); + log.debug("lowerUnnamedConst: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| { return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); }; @@ -3907,6 +3913,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { if (typed_value.val.castTag(.decl_ref_mut)) |payload| { return self.lowerDeclRef(typed_value, payload.data.decl); } + const target = self.target.*; switch (typed_value.ty.zigTypeTag()) { .Pointer => switch (typed_value.ty.ptrSize()) { @@ -3916,7 +3923,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { else => { switch (typed_value.val.tag()) { .int_u64 => { - return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; + return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; }, .slice => { return self.lowerUnnamedConst(typed_value); @@ -3935,7 +3942,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { const signed = typed_value.val.toSignedInt(); break :blk @bitCast(u64, signed); }, - .unsigned => typed_value.val.toUnsignedInt(), + .unsigned => typed_value.val.toUnsignedInt(target), }; return MCValue{ .immediate = unsigned }; @@ -4004,20 +4011,20 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { } _ = pl; - return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty}); + return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty.fmtDebug()}); } else { if (!payload_type.hasRuntimeBits()) { // We use the error type directly as the type. return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val }); } - return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty}); + return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty.fmtDebug()}); } }, .Struct => { return self.lowerUnnamedConst(typed_value); }, - else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}), + else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty.fmtDebug()}), } } diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 0b9f9eb2e2..1654be162a 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -801,8 +801,9 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { return self.next_stack_offset; } + const target = self.target.*; const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch { - return self.fail("type '{}' too big to fit into stack frame", .{elem_ty}); + return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(target)}); }; // TODO swap this for inst.ty.ptrAlign const abi_align = elem_ty.abiAlignment(self.target.*); @@ -811,8 +812,9 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { const elem_ty = self.air.typeOfIndex(inst); + const target = self.target.*; const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch { - return self.fail("type '{}' too big to fit into stack frame", .{elem_ty}); + return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(target)}); }; const abi_align = elem_ty.abiAlignment(self.target.*); if (abi_align > self.stack_align) @@ -2195,6 +2197,7 @@ fn binOp( lhs_ty: Type, rhs_ty: Type, ) InnerError!MCValue { + const target = self.target.*; switch (tag) { .add, .sub, @@ -2204,7 +2207,7 @@ fn binOp( .Float => return self.fail("TODO ARM binary operations on floats", .{}), .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), .Int => { - assert(lhs_ty.eql(rhs_ty)); + assert(lhs_ty.eql(rhs_ty, target)); const int_info = lhs_ty.intInfo(self.target.*); if (int_info.bits <= 32) { // Only say yes if the operation is @@ -2245,7 +2248,7 @@ fn binOp( .Float => return self.fail("TODO ARM binary operations on floats", .{}), .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), .Int => { - assert(lhs_ty.eql(rhs_ty)); + assert(lhs_ty.eql(rhs_ty, target)); const int_info = lhs_ty.intInfo(self.target.*); if (int_info.bits <= 32) { // TODO add optimisations for multiplication @@ -2299,7 +2302,7 @@ fn binOp( switch (lhs_ty.zigTypeTag()) { .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), .Int => { - assert(lhs_ty.eql(rhs_ty)); + assert(lhs_ty.eql(rhs_ty, target)); const int_info = lhs_ty.intInfo(self.target.*); if (int_info.bits <= 32) { const lhs_immediate_ok = lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null; @@ -4376,6 +4379,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { if (typed_value.val.castTag(.decl_ref_mut)) |payload| { return self.lowerDeclRef(typed_value, payload.data.decl); } + const target = self.target.*; switch (typed_value.ty.zigTypeTag()) { .Array => { @@ -4388,7 +4392,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { else => { switch (typed_value.val.tag()) { .int_u64 => { - return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt()) }; + return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt(target)) }; }, .slice => { return self.lowerUnnamedConst(typed_value); @@ -4407,7 +4411,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { const signed = @intCast(i32, typed_value.val.toSignedInt()); break :blk @bitCast(u32, signed); }, - .unsigned => @intCast(u32, typed_value.val.toUnsignedInt()), + .unsigned => @intCast(u32, typed_value.val.toUnsignedInt(target)), }; return MCValue{ .immediate = unsigned }; @@ -4476,20 +4480,20 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { } _ = pl; - return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty}); + return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty.fmtDebug()}); } else { if (!payload_type.hasRuntimeBits()) { // We use the error type directly as the type. return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val }); } - return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty}); + return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty.fmtDebug()}); } }, .Struct => { return self.lowerUnnamedConst(typed_value); }, - else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}), + else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty.fmtDebug()}), } } diff --git a/src/arch/arm/Emit.zig b/src/arch/arm/Emit.zig index c5aaeb4612..1e03c4649b 100644 --- a/src/arch/arm/Emit.zig +++ b/src/arch/arm/Emit.zig @@ -384,7 +384,7 @@ fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void { const index = dbg_out.dbg_info.items.len; try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 - const gop = try dbg_out.dbg_info_type_relocs.getOrPut(self.bin_file.allocator, ty); + const gop = try dbg_out.dbg_info_type_relocs.getOrPutContext(self.bin_file.allocator, ty, .{ .target = self.target.* }); if (!gop.found_existing) { gop.value_ptr.* = .{ .off = undefined, @@ -404,6 +404,7 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void { const ty = self.function.air.instructions.items(.data)[inst].ty; const name = self.function.mod_fn.getParamName(arg_index); const name_with_null = name.ptr[0 .. name.len + 1]; + const target = self.target.*; switch (mcv) { .register => |reg| { @@ -429,7 +430,7 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void { switch (self.debug_output) { .dwarf => |dbg_out| { const abi_size = math.cast(u32, ty.abiSize(self.target.*)) catch { - return self.fail("type '{}' too big to fit into stack frame", .{ty}); + return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(target)}); }; const adjusted_stack_offset = switch (mcv) { .stack_offset => |offset| math.negateCast(offset + abi_size) catch { diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 3b73fef51f..8cbd26b7a6 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -749,7 +749,9 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { const index = dbg_out.dbg_info.items.len; try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 - const gop = try dbg_out.dbg_info_type_relocs.getOrPut(self.gpa, ty); + const gop = try dbg_out.dbg_info_type_relocs.getOrPutContext(self.gpa, ty, .{ + .target = self.target.*, + }); if (!gop.found_existing) { gop.value_ptr.* = .{ .off = undefined, @@ -781,8 +783,9 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u /// Use a pointer instruction as the basis for allocating stack memory. fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { const elem_ty = self.air.typeOfIndex(inst).elemType(); + const target = self.target.*; const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch { - return self.fail("type '{}' too big to fit into stack frame", .{elem_ty}); + return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(target)}); }; // TODO swap this for inst.ty.ptrAlign const abi_align = elem_ty.abiAlignment(self.target.*); @@ -791,8 +794,9 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { const elem_ty = self.air.typeOfIndex(inst); + const target = self.target.*; const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch { - return self.fail("type '{}' too big to fit into stack frame", .{elem_ty}); + return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(target)}); }; const abi_align = elem_ty.abiAlignment(self.target.*); if (abi_align > self.stack_align) @@ -1048,7 +1052,7 @@ fn binOp( .Float => return self.fail("TODO binary operations on floats", .{}), .Vector => return self.fail("TODO binary operations on vectors", .{}), .Int => { - assert(lhs_ty.eql(rhs_ty)); + assert(lhs_ty.eql(rhs_ty, self.target.*)); const int_info = lhs_ty.intInfo(self.target.*); if (int_info.bits <= 64) { // TODO immediate operands @@ -1778,7 +1782,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); const ty = self.air.typeOf(bin_op.lhs); - assert(ty.eql(self.air.typeOf(bin_op.rhs))); + assert(ty.eql(self.air.typeOf(bin_op.rhs), self.target.*)); if (ty.zigTypeTag() == .ErrorSet) return self.fail("TODO implement cmp for errors", .{}); @@ -2531,6 +2535,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { if (typed_value.val.castTag(.decl_ref_mut)) |payload| { return self.lowerDeclRef(typed_value, payload.data.decl); } + const target = self.target.*; const ptr_bits = self.target.cpu.arch.ptrBitWidth(); switch (typed_value.ty.zigTypeTag()) { .Pointer => switch (typed_value.ty.ptrSize()) { @@ -2538,7 +2543,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { var buf: Type.SlicePtrFieldTypeBuffer = undefined; const ptr_type = typed_value.ty.slicePtrFieldType(&buf); const ptr_mcv = try self.genTypedValue(.{ .ty = ptr_type, .val = typed_value.val }); - const slice_len = typed_value.val.sliceLen(); + const slice_len = typed_value.val.sliceLen(target); // Codegen can't handle some kinds of indirection. If the wrong union field is accessed here it may mean // the Sema code needs to use anonymous Decls or alloca instructions to store data. const ptr_imm = ptr_mcv.memory; @@ -2549,7 +2554,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { }, else => { if (typed_value.val.tag() == .int_u64) { - return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; + return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; } return self.fail("TODO codegen more kinds of const pointers", .{}); }, @@ -2559,7 +2564,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { if (info.bits > ptr_bits or info.signedness == .signed) { return self.fail("TODO const int bigger than ptr and signed int", .{}); } - return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; + return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; }, .Bool => { return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; @@ -2629,9 +2634,9 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { return self.genTypedValue(.{ .ty = error_type, .val = sub_val }); } - return self.fail("TODO implement error union const of type '{}'", .{typed_value.ty}); + return self.fail("TODO implement error union const of type '{}'", .{typed_value.ty.fmtDebug()}); }, - else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}), + else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty.fmtDebug()}), } } diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 7d55e95f23..eb4004fa2c 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1021,7 +1021,9 @@ fn allocStack(self: *Self, ty: Type) !WValue { } const abi_size = std.math.cast(u32, ty.abiSize(self.target)) catch { - return self.fail("Type {} with ABI size of {d} exceeds stack frame size", .{ ty, ty.abiSize(self.target) }); + return self.fail("Type {} with ABI size of {d} exceeds stack frame size", .{ + ty.fmt(self.target), ty.abiSize(self.target), + }); }; const abi_align = ty.abiAlignment(self.target); @@ -1053,7 +1055,9 @@ fn allocStackPtr(self: *Self, inst: Air.Inst.Index) !WValue { const abi_alignment = ptr_ty.ptrAlignment(self.target); const abi_size = std.math.cast(u32, pointee_ty.abiSize(self.target)) catch { - return self.fail("Type {} with ABI size of {d} exceeds stack frame size", .{ pointee_ty, pointee_ty.abiSize(self.target) }); + return self.fail("Type {} with ABI size of {d} exceeds stack frame size", .{ + pointee_ty.fmt(self.target), pointee_ty.abiSize(self.target), + }); }; if (abi_alignment > self.stack_alignment) { self.stack_alignment = abi_alignment; @@ -1750,7 +1754,7 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { const operand_ty = self.air.typeOfIndex(inst); if (isByRef(operand_ty, self.target)) { - return self.fail("TODO: Implement binary operation for type: {}", .{operand_ty}); + return self.fail("TODO: Implement binary operation for type: {}", .{operand_ty.fmtDebug()}); } try self.emitWValue(lhs); @@ -1918,6 +1922,8 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { return self.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl); } + const target = self.target; + switch (ty.zigTypeTag()) { .Int => { const int_info = ty.intInfo(self.target); @@ -1929,13 +1935,13 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { else => unreachable, }, .unsigned => switch (int_info.bits) { - 0...32 => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) }, - 33...64 => return WValue{ .imm64 = val.toUnsignedInt() }, + 0...32 => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(target)) }, + 33...64 => return WValue{ .imm64 = val.toUnsignedInt(target) }, else => unreachable, }, } }, - .Bool => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) }, + .Bool => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(target)) }, .Float => switch (ty.floatBits(self.target)) { 0...32 => return WValue{ .float32 = val.toFloat(f32) }, 33...64 => return WValue{ .float64 = val.toFloat(f64) }, @@ -1945,7 +1951,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { .field_ptr, .elem_ptr => { return self.lowerParentPtr(val, ty.childType()); }, - .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) }, + .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(target)) }, .zero, .null_value => return WValue{ .imm32 = 0 }, else => return self.fail("Wasm TODO: lowerConstant for other const pointer tag {s}", .{val.tag()}), }, @@ -2044,6 +2050,7 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue { /// It's illegal to provide a value with a type that cannot be represented /// as an integer value. fn valueAsI32(self: Self, val: Value, ty: Type) i32 { + const target = self.target; switch (ty.zigTypeTag()) { .Enum => { if (val.castTag(.enum_field_index)) |field_index| { @@ -2071,7 +2078,7 @@ fn valueAsI32(self: Self, val: Value, ty: Type) i32 { }, .Int => switch (ty.intInfo(self.target).signedness) { .signed => return @truncate(i32, val.toSignedInt()), - .unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt())), + .unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt(target))), }, .ErrorSet => { const kv = self.bin_file.base.options.module.?.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function @@ -2296,7 +2303,7 @@ fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { const struct_ty = self.air.typeOf(extra.data.struct_operand).childType(); const offset = std.math.cast(u32, struct_ty.structFieldOffset(extra.data.field_index, self.target)) catch { return self.fail("Field type '{}' too big to fit into stack frame", .{ - struct_ty.structFieldType(extra.data.field_index), + struct_ty.structFieldType(extra.data.field_index).fmt(self.target), }); }; return self.structFieldPtr(struct_ptr, offset); @@ -2309,7 +2316,7 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u32) InnerEr const field_ty = struct_ty.structFieldType(index); const offset = std.math.cast(u32, struct_ty.structFieldOffset(index, self.target)) catch { return self.fail("Field type '{}' too big to fit into stack frame", .{ - field_ty, + field_ty.fmt(self.target), }); }; return self.structFieldPtr(struct_ptr, offset); @@ -2335,7 +2342,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { const field_ty = struct_ty.structFieldType(field_index); if (!field_ty.hasRuntimeBits()) return WValue{ .none = {} }; const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, self.target)) catch { - return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty}); + return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty.fmt(self.target)}); }; if (isByRef(field_ty, self.target)) { @@ -2716,7 +2723,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue var buf: Type.Payload.ElemType = undefined; const payload_ty = opt_ty.optionalChild(&buf); if (!payload_ty.hasRuntimeBits()) { - return self.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty}); + return self.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty.fmtDebug()}); } if (opt_ty.isPtrLikeOptional()) { @@ -2724,7 +2731,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue } const offset = std.math.cast(u32, opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target)) catch { - return self.fail("Optional type {} too big to fit into stack frame", .{opt_ty}); + return self.fail("Optional type {} too big to fit into stack frame", .{opt_ty.fmt(self.target)}); }; try self.emitWValue(operand); @@ -2753,7 +2760,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue { return operand; } const offset = std.math.cast(u32, op_ty.abiSize(self.target) - payload_ty.abiSize(self.target)) catch { - return self.fail("Optional type {} too big to fit into stack frame", .{op_ty}); + return self.fail("Optional type {} too big to fit into stack frame", .{op_ty.fmt(self.target)}); }; // Create optional type, set the non-null bit, and store the operand inside the optional type diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 598511a631..f2977977c5 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -892,8 +892,9 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { return self.allocMem(inst, @sizeOf(usize), @alignOf(usize)); } + const target = self.target.*; const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch { - return self.fail("type '{}' too big to fit into stack frame", .{elem_ty}); + return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(target)}); }; // TODO swap this for inst.ty.ptrAlign const abi_align = ptr_ty.ptrAlignment(self.target.*); @@ -902,8 +903,9 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { const elem_ty = self.air.typeOfIndex(inst); + const target = self.target.*; const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch { - return self.fail("type '{}' too big to fit into stack frame", .{elem_ty}); + return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(target)}); }; const abi_align = elem_ty.abiAlignment(self.target.*); if (abi_align > self.stack_align) @@ -1142,7 +1144,7 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void { const ty = self.air.typeOfIndex(inst); if (ty.zigTypeTag() != .Int) { - return self.fail("TODO implement min for type {}", .{ty}); + return self.fail("TODO implement min for type {}", .{ty.fmtDebug()}); } const signedness = ty.intInfo(self.target.*).signedness; const result: MCValue = result: { @@ -1676,13 +1678,13 @@ fn airShl(self: *Self, inst: Air.Inst.Index) !void { const ty = self.air.typeOfIndex(inst); const tag = self.air.instructions.items(.tag)[inst]; switch (tag) { - .shl_exact => return self.fail("TODO implement {} for type {}", .{ tag, ty }), + .shl_exact => return self.fail("TODO implement {} for type {}", .{ tag, ty.fmtDebug() }), .shl => {}, else => unreachable, } if (ty.zigTypeTag() != .Int) { - return self.fail("TODO implement .shl for type {}", .{ty}); + return self.fail("TODO implement .shl for type {}", .{ty.fmtDebug()}); } if (ty.abiSize(self.target.*) > 8) { return self.fail("TODO implement .shl for integers larger than 8 bytes", .{}); @@ -5820,7 +5822,7 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa } fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { - log.debug("lowerUnnamedConst: ty = {}, val = {}", .{ tv.ty, tv.val.fmtDebug() }); + log.debug("lowerUnnamedConst: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| { return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); }; @@ -5850,13 +5852,15 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { return self.lowerDeclRef(typed_value, payload.data.decl); } + const target = self.target.*; + switch (typed_value.ty.zigTypeTag()) { .Pointer => switch (typed_value.ty.ptrSize()) { .Slice => {}, else => { switch (typed_value.val.tag()) { .int_u64 => { - return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; + return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; }, else => {}, } @@ -5868,7 +5872,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt()) }; } if (!(info.bits > ptr_bits or info.signedness == .signed)) { - return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; + return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; } }, .Bool => { diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 0543496750..3ce77ffb73 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -1118,7 +1118,9 @@ fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void { const index = dbg_out.dbg_info.items.len; try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 - const gop = try dbg_out.dbg_info_type_relocs.getOrPut(emit.bin_file.allocator, ty); + const gop = try dbg_out.dbg_info_type_relocs.getOrPutContext(emit.bin_file.allocator, ty, .{ + .target = emit.target.*, + }); if (!gop.found_existing) { gop.value_ptr.* = .{ .off = undefined, diff --git a/src/codegen.zig b/src/codegen.zig index 9861dfc06c..20599f3eb6 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -165,7 +165,10 @@ pub fn generateSymbol( const target = bin_file.options.target; const endian = target.cpu.arch.endian(); - log.debug("generateSymbol: ty = {}, val = {}", .{ typed_value.ty, typed_value.val.fmtDebug() }); + log.debug("generateSymbol: ty = {}, val = {}", .{ + typed_value.ty.fmtDebug(), + typed_value.val.fmtDebug(), + }); if (typed_value.val.isUndefDeep()) { const abi_size = try math.cast(usize, typed_value.ty.abiSize(target)); @@ -295,11 +298,11 @@ pub fn generateSymbol( .zero, .one, .int_u64, .int_big_positive => { switch (target.cpu.arch.ptrBitWidth()) { 32 => { - const x = typed_value.val.toUnsignedInt(); + const x = typed_value.val.toUnsignedInt(target); mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, x), endian); }, 64 => { - const x = typed_value.val.toUnsignedInt(); + const x = typed_value.val.toUnsignedInt(target); mem.writeInt(u64, try code.addManyAsArray(8), x, endian); }, else => unreachable, @@ -433,7 +436,7 @@ pub fn generateSymbol( // TODO populate .debug_info for the integer const info = typed_value.ty.intInfo(bin_file.options.target); if (info.bits <= 8) { - const x = @intCast(u8, typed_value.val.toUnsignedInt()); + const x = @intCast(u8, typed_value.val.toUnsignedInt(target)); try code.append(x); return Result{ .appended = {} }; } @@ -443,20 +446,20 @@ pub fn generateSymbol( bin_file.allocator, src_loc, "TODO implement generateSymbol for big ints ('{}')", - .{typed_value.ty}, + .{typed_value.ty.fmtDebug()}, ), }; } switch (info.signedness) { .unsigned => { if (info.bits <= 16) { - const x = @intCast(u16, typed_value.val.toUnsignedInt()); + const x = @intCast(u16, typed_value.val.toUnsignedInt(target)); mem.writeInt(u16, try code.addManyAsArray(2), x, endian); } else if (info.bits <= 32) { - const x = @intCast(u32, typed_value.val.toUnsignedInt()); + const x = @intCast(u32, typed_value.val.toUnsignedInt(target)); mem.writeInt(u32, try code.addManyAsArray(4), x, endian); } else { - const x = typed_value.val.toUnsignedInt(); + const x = typed_value.val.toUnsignedInt(target); mem.writeInt(u64, try code.addManyAsArray(8), x, endian); } }, @@ -482,7 +485,7 @@ pub fn generateSymbol( const info = typed_value.ty.intInfo(target); if (info.bits <= 8) { - const x = @intCast(u8, int_val.toUnsignedInt()); + const x = @intCast(u8, int_val.toUnsignedInt(target)); try code.append(x); return Result{ .appended = {} }; } @@ -492,20 +495,20 @@ pub fn generateSymbol( bin_file.allocator, src_loc, "TODO implement generateSymbol for big int enums ('{}')", - .{typed_value.ty}, + .{typed_value.ty.fmtDebug()}, ), }; } switch (info.signedness) { .unsigned => { if (info.bits <= 16) { - const x = @intCast(u16, int_val.toUnsignedInt()); + const x = @intCast(u16, int_val.toUnsignedInt(target)); mem.writeInt(u16, try code.addManyAsArray(2), x, endian); } else if (info.bits <= 32) { - const x = @intCast(u32, int_val.toUnsignedInt()); + const x = @intCast(u32, int_val.toUnsignedInt(target)); mem.writeInt(u32, try code.addManyAsArray(4), x, endian); } else { - const x = int_val.toUnsignedInt(); + const x = int_val.toUnsignedInt(target); mem.writeInt(u64, try code.addManyAsArray(8), x, endian); } }, @@ -597,7 +600,7 @@ pub fn generateSymbol( } const union_ty = typed_value.ty.cast(Type.Payload.Union).?.data; - const field_index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag).?; + const field_index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag, target).?; assert(union_ty.haveFieldTypes()); const field_ty = union_ty.fields.values()[field_index].ty; if (!field_ty.hasRuntimeBits()) { @@ -787,6 +790,7 @@ fn lowerDeclRef( debug_output: DebugInfoOutput, reloc_info: RelocInfo, ) GenerateSymbolError!Result { + const target = bin_file.options.target; if (typed_value.ty.isSlice()) { // generate ptr var buf: Type.SlicePtrFieldTypeBuffer = undefined; @@ -805,7 +809,7 @@ fn lowerDeclRef( // generate length var slice_len: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, - .data = typed_value.val.sliceLen(), + .data = typed_value.val.sliceLen(target), }; switch (try generateSymbol(bin_file, src_loc, .{ .ty = Type.usize, @@ -821,7 +825,6 @@ fn lowerDeclRef( return Result{ .appended = {} }; } - const target = bin_file.options.target; const ptr_width = target.cpu.arch.ptrBitWidth(); const is_fn_body = decl.ty.zigTypeTag() == .Fn; if (!is_fn_body and !decl.ty.hasRuntimeBits()) { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index f5a1036479..c62abdb3f6 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -56,8 +56,14 @@ pub const TypedefMap = std.ArrayHashMap( true, ); +const FormatTypeAsCIdentContext = struct { + ty: Type, + target: std.Target, +}; + +/// TODO make this not cut off at 128 bytes fn formatTypeAsCIdentifier( - data: Type, + data: FormatTypeAsCIdentContext, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype, @@ -65,13 +71,15 @@ fn formatTypeAsCIdentifier( _ = fmt; _ = options; var buffer = [1]u8{0} ** 128; - // We don't care if it gets cut off, it's still more unique than a number - var buf = std.fmt.bufPrint(&buffer, "{}", .{data}) catch &buffer; + var buf = std.fmt.bufPrint(&buffer, "{}", .{data.ty.fmt(data.target)}) catch &buffer; return formatIdent(buf, "", .{}, writer); } -pub fn typeToCIdentifier(t: Type) std.fmt.Formatter(formatTypeAsCIdentifier) { - return .{ .data = t }; +pub fn typeToCIdentifier(ty: Type, target: std.Target) std.fmt.Formatter(formatTypeAsCIdentifier) { + return .{ .data = .{ + .ty = ty, + .target = target, + } }; } const reserved_idents = std.ComptimeStringMap(void, .{ @@ -369,6 +377,8 @@ pub const DeclGen = struct { ) error{ OutOfMemory, AnalysisFail }!void { decl.markAlive(); + const target = dg.module.getTarget(); + if (ty.isSlice()) { try writer.writeByte('('); try dg.renderTypecast(writer, ty); @@ -376,7 +386,7 @@ pub const DeclGen = struct { var buf: Type.SlicePtrFieldTypeBuffer = undefined; try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr()); try writer.writeAll(", "); - try writer.print("{d}", .{val.sliceLen()}); + try writer.print("{d}", .{val.sliceLen(target)}); try writer.writeAll("}"); return; } @@ -388,7 +398,7 @@ pub const DeclGen = struct { // somewhere and we should let the C compiler tell us about it. if (ty.castPtrToFn() == null) { // Determine if we must pointer cast. - if (ty.eql(decl.ty)) { + if (ty.eql(decl.ty, target)) { try writer.writeByte('&'); try dg.renderDeclName(writer, decl); return; @@ -508,6 +518,7 @@ pub const DeclGen = struct { ty: Type, val: Value, ) error{ OutOfMemory, AnalysisFail }!void { + const target = dg.module.getTarget(); if (val.isUndefDeep()) { switch (ty.zigTypeTag()) { // Using '{}' for integer and floats seemed to error C compilers (both GCC and Clang) @@ -551,7 +562,7 @@ pub const DeclGen = struct { else => { if (ty.isSignedInt()) return writer.print("{d}", .{val.toSignedInt()}); - return writer.print("{d}u", .{val.toUnsignedInt()}); + return writer.print("{d}u", .{val.toUnsignedInt(target)}); }, }, .Float => { @@ -609,7 +620,7 @@ pub const DeclGen = struct { .int_u64, .one => { try writer.writeAll("(("); try dg.renderTypecast(writer, ty); - try writer.print(")0x{x}u)", .{val.toUnsignedInt()}); + try writer.print(")0x{x}u)", .{val.toUnsignedInt(target)}); }, else => unreachable, }, @@ -653,7 +664,6 @@ pub const DeclGen = struct { if (ty.isPtrLikeOptional()) { return dg.renderValue(writer, payload_type, val); } - const target = dg.module.getTarget(); if (payload_type.abiSize(target) == 0) { const is_null = val.castTag(.opt_payload) == null; return writer.print("{}", .{is_null}); @@ -773,7 +783,6 @@ pub const DeclGen = struct { .Union => { const union_obj = val.castTag(.@"union").?.data; const union_ty = ty.cast(Type.Payload.Union).?.data; - const target = dg.module.getTarget(); const layout = ty.unionGetLayout(target); try writer.writeAll("("); @@ -789,7 +798,7 @@ pub const DeclGen = struct { try writer.writeAll(".payload = {"); } - const index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag).?; + const index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag, target).?; const field_ty = ty.unionFields().values()[index].ty; const field_name = ty.unionFields().keys()[index]; if (field_ty.hasRuntimeBits()) { @@ -879,8 +888,8 @@ pub const DeclGen = struct { try bw.writeAll(" (*"); const name_start = buffer.items.len; - // TODO: typeToCIdentifier truncates to 128 bytes, we probably don't want to do this - try bw.print("zig_F_{s})(", .{typeToCIdentifier(t)}); + const target = dg.module.getTarget(); + try bw.print("zig_F_{s})(", .{typeToCIdentifier(t, target)}); const name_end = buffer.items.len - 2; const param_len = fn_info.param_types.len; @@ -934,10 +943,11 @@ pub const DeclGen = struct { try bw.writeAll("; size_t len; } "); const name_index = buffer.items.len; + const target = dg.module.getTarget(); if (t.isConstPtr()) { - try bw.print("zig_L_{s}", .{typeToCIdentifier(child_type)}); + try bw.print("zig_L_{s}", .{typeToCIdentifier(child_type, target)}); } else { - try bw.print("zig_M_{s}", .{typeToCIdentifier(child_type)}); + try bw.print("zig_M_{s}", .{typeToCIdentifier(child_type, target)}); } if (ptr_sentinel) |s| { try bw.writeAll("_s_"); @@ -1023,7 +1033,8 @@ pub const DeclGen = struct { try buffer.appendSlice("} "); const name_start = buffer.items.len; - try writer.print("zig_T_{};\n", .{typeToCIdentifier(t)}); + const target = dg.module.getTarget(); + try writer.print("zig_T_{};\n", .{typeToCIdentifier(t, target)}); const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); @@ -1107,6 +1118,7 @@ pub const DeclGen = struct { try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0); try bw.writeAll("; uint16_t error; } "); const name_index = buffer.items.len; + const target = dg.module.getTarget(); if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| { const func = inf_err_set_payload.data.func; try bw.writeAll("zig_E_"); @@ -1114,7 +1126,7 @@ pub const DeclGen = struct { try bw.writeAll(";\n"); } else { try bw.print("zig_E_{s}_{s};\n", .{ - typeToCIdentifier(err_set_type), typeToCIdentifier(child_type), + typeToCIdentifier(err_set_type, target), typeToCIdentifier(child_type, target), }); } @@ -1144,7 +1156,8 @@ pub const DeclGen = struct { try dg.renderType(bw, elem_type); const name_start = buffer.items.len + 1; - try bw.print(" zig_A_{s}_{d}", .{ typeToCIdentifier(elem_type), c_len }); + const target = dg.module.getTarget(); + try bw.print(" zig_A_{s}_{d}", .{ typeToCIdentifier(elem_type, target), c_len }); const name_end = buffer.items.len; try bw.print("[{d}];\n", .{c_len}); @@ -1172,7 +1185,8 @@ pub const DeclGen = struct { try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0); try bw.writeAll("; bool is_null; } "); const name_index = buffer.items.len; - try bw.print("zig_Q_{s};\n", .{typeToCIdentifier(child_type)}); + const target = dg.module.getTarget(); + try bw.print("zig_Q_{s};\n", .{typeToCIdentifier(child_type, target)}); const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); @@ -2177,12 +2191,13 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { if (src_val_is_undefined) return try airStoreUndefined(f, dest_ptr); + const target = f.object.dg.module.getTarget(); const writer = f.object.writer(); if (lhs_child_type.zigTypeTag() == .Array) { // For this memcpy to safely work we need the rhs to have the same // underlying type as the lhs (i.e. they must both be arrays of the same underlying type). const rhs_type = f.air.typeOf(bin_op.rhs); - assert(rhs_type.eql(lhs_child_type)); + assert(rhs_type.eql(lhs_child_type, target)); // If the source is a constant, writeCValue will emit a brace initialization // so work around this by initializing into new local. diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 107b059765..c8ca540f59 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -812,7 +812,7 @@ pub const Object = struct { const gpa = o.gpa; // Be careful not to reference this `gop` variable after any recursive calls // to `lowerDebugType`. - const gop = try o.di_type_map.getOrPut(gpa, ty); + const gop = try o.di_type_map.getOrPutContext(gpa, ty, .{ .target = o.target }); if (gop.found_existing) { const annotated = gop.value_ptr.*; const di_type = annotated.toDIType(); @@ -825,7 +825,7 @@ pub const Object = struct { }; return o.lowerDebugTypeImpl(entry, resolve, di_type); } - errdefer assert(o.di_type_map.orderedRemove(ty)); + errdefer assert(o.di_type_map.orderedRemoveContext(ty, .{ .target = o.target })); // The Type memory is ephemeral; since we want to store a longer-lived // reference, we need to copy it here. gop.key_ptr.* = try ty.copy(o.type_map_arena.allocator()); @@ -856,7 +856,7 @@ pub const Object = struct { .Int => { const info = ty.intInfo(target); assert(info.bits != 0); - const name = try ty.nameAlloc(gpa); + const name = try ty.nameAlloc(gpa, target); defer gpa.free(name); const dwarf_encoding: c_uint = switch (info.signedness) { .signed => DW.ATE.signed, @@ -873,7 +873,7 @@ pub const Object = struct { const enum_di_ty = try o.makeEmptyNamespaceDIType(owner_decl); // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` // means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(enum_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(enum_di_ty), .{ .target = o.target }); return enum_di_ty; } @@ -903,7 +903,7 @@ pub const Object = struct { const di_file = try o.getDIFile(gpa, owner_decl.src_namespace.file_scope); const di_scope = try o.namespaceToDebugScope(owner_decl.src_namespace); - const name = try ty.nameAlloc(gpa); + const name = try ty.nameAlloc(gpa, target); defer gpa.free(name); var buffer: Type.Payload.Bits = undefined; const int_ty = ty.intTagType(&buffer); @@ -921,12 +921,12 @@ pub const Object = struct { "", ); // The recursive call to `lowerDebugType` means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(enum_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(enum_di_ty), .{ .target = o.target }); return enum_di_ty; }, .Float => { const bits = ty.floatBits(target); - const name = try ty.nameAlloc(gpa); + const name = try ty.nameAlloc(gpa, target); defer gpa.free(name); const di_type = dib.createBasicType(name, bits, DW.ATE.float); gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type); @@ -974,7 +974,7 @@ pub const Object = struct { const bland_ptr_ty = Type.initPayload(&payload.base); const ptr_di_ty = try o.lowerDebugType(bland_ptr_ty, resolve); // The recursive call to `lowerDebugType` means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.init(ptr_di_ty, resolve)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.init(ptr_di_ty, resolve), .{ .target = o.target }); return ptr_di_ty; } @@ -983,7 +983,7 @@ pub const Object = struct { const ptr_ty = ty.slicePtrFieldType(&buf); const len_ty = Type.usize; - const name = try ty.nameAlloc(gpa); + const name = try ty.nameAlloc(gpa, target); defer gpa.free(name); const di_file: ?*llvm.DIFile = null; const line = 0; @@ -1054,12 +1054,12 @@ pub const Object = struct { ); dib.replaceTemporary(fwd_decl, full_di_ty); // The recursive call to `lowerDebugType` means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .target = o.target }); return full_di_ty; } const elem_di_ty = try o.lowerDebugType(ptr_info.pointee_type, .fwd); - const name = try ty.nameAlloc(gpa); + const name = try ty.nameAlloc(gpa, target); defer gpa.free(name); const ptr_di_ty = dib.createPointerType( elem_di_ty, @@ -1068,7 +1068,7 @@ pub const Object = struct { name, ); // The recursive call to `lowerDebugType` means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(ptr_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(ptr_di_ty), .{ .target = o.target }); return ptr_di_ty; }, .Opaque => { @@ -1077,7 +1077,7 @@ pub const Object = struct { gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty); return di_ty; } - const name = try ty.nameAlloc(gpa); + const name = try ty.nameAlloc(gpa, target); defer gpa.free(name); const owner_decl = ty.getOwnerDecl(); const opaque_di_ty = dib.createForwardDeclType( @@ -1089,7 +1089,7 @@ pub const Object = struct { ); // The recursive call to `lowerDebugType` va `namespaceToDebugScope` // means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(opaque_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(opaque_di_ty), .{ .target = o.target }); return opaque_di_ty; }, .Array => { @@ -1100,7 +1100,7 @@ pub const Object = struct { @intCast(c_int, ty.arrayLen()), ); // The recursive call to `lowerDebugType` means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(array_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(array_di_ty), .{ .target = o.target }); return array_di_ty; }, .Vector => { @@ -1111,11 +1111,11 @@ pub const Object = struct { ty.vectorLen(), ); // The recursive call to `lowerDebugType` means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(vector_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(vector_di_ty), .{ .target = o.target }); return vector_di_ty; }, .Optional => { - const name = try ty.nameAlloc(gpa); + const name = try ty.nameAlloc(gpa, target); defer gpa.free(name); var buf: Type.Payload.ElemType = undefined; const child_ty = ty.optionalChild(&buf); @@ -1127,7 +1127,7 @@ pub const Object = struct { if (ty.isPtrLikeOptional()) { const ptr_di_ty = try o.lowerDebugType(child_ty, resolve); // The recursive call to `lowerDebugType` means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(ptr_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(ptr_di_ty), .{ .target = o.target }); return ptr_di_ty; } @@ -1200,7 +1200,7 @@ pub const Object = struct { ); dib.replaceTemporary(fwd_decl, full_di_ty); // The recursive call to `lowerDebugType` means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .target = o.target }); return full_di_ty; }, .ErrorUnion => { @@ -1209,10 +1209,10 @@ pub const Object = struct { if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { const err_set_di_ty = try o.lowerDebugType(err_set_ty, .full); // The recursive call to `lowerDebugType` means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(err_set_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(err_set_di_ty), .{ .target = o.target }); return err_set_di_ty; } - const name = try ty.nameAlloc(gpa); + const name = try ty.nameAlloc(gpa, target); defer gpa.free(name); const di_file: ?*llvm.DIFile = null; const line = 0; @@ -1282,7 +1282,7 @@ pub const Object = struct { ); dib.replaceTemporary(fwd_decl, full_di_ty); // The recursive call to `lowerDebugType` means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .target = o.target }); return full_di_ty; }, .ErrorSet => { @@ -1294,7 +1294,7 @@ pub const Object = struct { }, .Struct => { const compile_unit_scope = o.di_compile_unit.?.toScope(); - const name = try ty.nameAlloc(gpa); + const name = try ty.nameAlloc(gpa, target); defer gpa.free(name); if (ty.castTag(.@"struct")) |payload| { @@ -1381,7 +1381,7 @@ pub const Object = struct { ); dib.replaceTemporary(fwd_decl, full_di_ty); // The recursive call to `lowerDebugType` means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .target = o.target }); return full_di_ty; } @@ -1395,7 +1395,7 @@ pub const Object = struct { dib.replaceTemporary(fwd_decl, struct_di_ty); // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` // means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(struct_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(struct_di_ty), .{ .target = o.target }); return struct_di_ty; } } @@ -1406,7 +1406,7 @@ pub const Object = struct { dib.replaceTemporary(fwd_decl, struct_di_ty); // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` // means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(struct_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(struct_di_ty), .{ .target = o.target }); return struct_di_ty; } @@ -1461,13 +1461,13 @@ pub const Object = struct { ); dib.replaceTemporary(fwd_decl, full_di_ty); // The recursive call to `lowerDebugType` means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .target = o.target }); return full_di_ty; }, .Union => { const owner_decl = ty.getOwnerDecl(); - const name = try ty.nameAlloc(gpa); + const name = try ty.nameAlloc(gpa, target); defer gpa.free(name); const fwd_decl = opt_fwd_decl orelse blk: { @@ -1489,7 +1489,7 @@ pub const Object = struct { dib.replaceTemporary(fwd_decl, union_di_ty); // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` // means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .target = o.target }); return union_di_ty; } @@ -1603,7 +1603,7 @@ pub const Object = struct { 0, ); // The recursive call to `lowerDebugType` means we can't use `gop` anymore. - try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(fn_di_ty)); + try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(fn_di_ty), .{ .target = o.target }); return fn_di_ty; }, .ComptimeInt => unreachable, @@ -1676,7 +1676,9 @@ pub const DeclGen = struct { const decl = dg.decl; assert(decl.has_tv); - log.debug("gen: {s} type: {}, value: {}", .{ decl.name, decl.ty, decl.val.fmtDebug() }); + log.debug("gen: {s} type: {}, value: {}", .{ + decl.name, decl.ty.fmtDebug(), decl.val.fmtDebug(), + }); if (decl.val.castTag(.function)) |func_payload| { _ = func_payload; @@ -1990,7 +1992,7 @@ pub const DeclGen = struct { }, .Opaque => switch (t.tag()) { .@"opaque" => { - const gop = try dg.object.type_map.getOrPut(gpa, t); + const gop = try dg.object.type_map.getOrPutContext(gpa, t, .{ .target = target }); if (gop.found_existing) return gop.value_ptr.*; // The Type memory is ephemeral; since we want to store a longer-lived @@ -2051,7 +2053,7 @@ pub const DeclGen = struct { return dg.context.intType(16); }, .Struct => { - const gop = try dg.object.type_map.getOrPut(gpa, t); + const gop = try dg.object.type_map.getOrPutContext(gpa, t, .{ .target = target }); if (gop.found_existing) return gop.value_ptr.*; // The Type memory is ephemeral; since we want to store a longer-lived @@ -2174,7 +2176,7 @@ pub const DeclGen = struct { return llvm_struct_ty; }, .Union => { - const gop = try dg.object.type_map.getOrPut(gpa, t); + const gop = try dg.object.type_map.getOrPutContext(gpa, t, .{ .target = target }); if (gop.found_existing) return gop.value_ptr.*; // The Type memory is ephemeral; since we want to store a longer-lived @@ -2289,6 +2291,7 @@ pub const DeclGen = struct { const llvm_type = try dg.llvmType(tv.ty); return llvm_type.getUndef(); } + const target = dg.module.getTarget(); switch (tv.ty.zigTypeTag()) { .Bool => { @@ -2302,8 +2305,7 @@ pub const DeclGen = struct { .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data), else => { var bigint_space: Value.BigIntSpace = undefined; - const bigint = tv.val.toBigInt(&bigint_space); - const target = dg.module.getTarget(); + const bigint = tv.val.toBigInt(&bigint_space, target); const int_info = tv.ty.intInfo(target); assert(int_info.bits != 0); const llvm_type = dg.context.intType(int_info.bits); @@ -2331,9 +2333,8 @@ pub const DeclGen = struct { const int_val = tv.enumToInt(&int_buffer); var bigint_space: Value.BigIntSpace = undefined; - const bigint = int_val.toBigInt(&bigint_space); + const bigint = int_val.toBigInt(&bigint_space, target); - const target = dg.module.getTarget(); const int_info = tv.ty.intInfo(target); const llvm_type = dg.context.intType(int_info.bits); @@ -2356,7 +2357,6 @@ pub const DeclGen = struct { }, .Float => { const llvm_ty = try dg.llvmType(tv.ty); - const target = dg.module.getTarget(); switch (tv.ty.floatBits(target)) { 16, 32, 64 => return llvm_ty.constReal(tv.val.toFloat(f64)), 80 => { @@ -2414,7 +2414,7 @@ pub const DeclGen = struct { }, .int_u64, .one, .int_big_positive => { const llvm_usize = try dg.llvmType(Type.usize); - const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(), .False); + const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(target), .False); return llvm_int.constIntToPtr(try dg.llvmType(tv.ty)); }, .field_ptr, .opt_payload_ptr, .eu_payload_ptr, .elem_ptr => { @@ -2424,7 +2424,9 @@ pub const DeclGen = struct { const llvm_type = try dg.llvmType(tv.ty); return llvm_type.constNull(); }, - else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{ tv.ty, tag }), + else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{ + tv.ty.fmtDebug(), tag, + }), }, .Array => switch (tv.val.tag()) { .bytes => { @@ -2592,7 +2594,6 @@ pub const DeclGen = struct { const llvm_struct_ty = try dg.llvmType(tv.ty); const field_vals = tv.val.castTag(.aggregate).?.data; const gpa = dg.gpa; - const target = dg.module.getTarget(); if (tv.ty.isTupleOrAnonStruct()) { const tuple = tv.ty.tupleFields(); @@ -2753,7 +2754,6 @@ pub const DeclGen = struct { const llvm_union_ty = try dg.llvmType(tv.ty); const tag_and_val = tv.val.castTag(.@"union").?.data; - const target = dg.module.getTarget(); const layout = tv.ty.unionGetLayout(target); if (layout.payload_size == 0) { @@ -2763,7 +2763,7 @@ pub const DeclGen = struct { }); } const union_obj = tv.ty.cast(Type.Payload.Union).?.data; - const field_index = union_obj.tag_ty.enumTagFieldIndex(tag_and_val.tag).?; + const field_index = union_obj.tag_ty.enumTagFieldIndex(tag_and_val.tag, target).?; assert(union_obj.haveFieldTypes()); const field_ty = union_obj.fields.values()[field_index].ty; const payload = p: { @@ -2892,7 +2892,7 @@ pub const DeclGen = struct { .Frame, .AnyFrame, - => return dg.todo("implement const of type '{}'", .{tv.ty}), + => return dg.todo("implement const of type '{}'", .{tv.ty.fmtDebug()}), } } @@ -2910,7 +2910,8 @@ pub const DeclGen = struct { const ptr_ty = Type.initPayload(&ptr_ty_payload.base); const llvm_ptr = try dg.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl); - if (ptr_child_ty.eql(decl.ty)) { + const target = dg.module.getTarget(); + if (ptr_child_ty.eql(decl.ty, target)) { return llvm_ptr; } else { return llvm_ptr.constBitCast((try dg.llvmType(ptr_child_ty)).pointerType(0)); @@ -2918,6 +2919,7 @@ pub const DeclGen = struct { } fn lowerParentPtr(dg: *DeclGen, ptr_val: Value, ptr_child_ty: Type) Error!*const llvm.Value { + const target = dg.module.getTarget(); var bitcast_needed: bool = undefined; const llvm_ptr = switch (ptr_val.tag()) { .decl_ref_mut => { @@ -2951,7 +2953,6 @@ pub const DeclGen = struct { const field_index = @intCast(u32, field_ptr.field_index); const llvm_u32 = dg.context.intType(32); - const target = dg.module.getTarget(); switch (parent_ty.zigTypeTag()) { .Union => { bitcast_needed = true; @@ -2974,7 +2975,7 @@ pub const DeclGen = struct { }, .Struct => { const field_ty = parent_ty.structFieldType(field_index); - bitcast_needed = !field_ty.eql(ptr_child_ty); + bitcast_needed = !field_ty.eql(ptr_child_ty, target); var ty_buf: Type.Payload.Pointer = undefined; const llvm_field_index = llvmFieldIndex(parent_ty, field_index, target, &ty_buf).?; @@ -2990,7 +2991,7 @@ pub const DeclGen = struct { .elem_ptr => blk: { const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; const parent_llvm_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr, elem_ptr.elem_ty); - bitcast_needed = !elem_ptr.elem_ty.eql(ptr_child_ty); + bitcast_needed = !elem_ptr.elem_ty.eql(ptr_child_ty, target); const llvm_usize = try dg.llvmType(Type.usize); const indices: [1]*const llvm.Value = .{ @@ -3004,7 +3005,7 @@ pub const DeclGen = struct { var buf: Type.Payload.ElemType = undefined; const payload_ty = opt_payload_ptr.container_ty.optionalChild(&buf); - bitcast_needed = !payload_ty.eql(ptr_child_ty); + bitcast_needed = !payload_ty.eql(ptr_child_ty, target); if (!payload_ty.hasRuntimeBitsIgnoreComptime() or payload_ty.isPtrLikeOptional()) { // In this case, we represent pointer to optional the same as pointer @@ -3024,7 +3025,7 @@ pub const DeclGen = struct { const parent_llvm_ptr = try dg.lowerParentPtr(eu_payload_ptr.container_ptr, eu_payload_ptr.container_ty); const payload_ty = eu_payload_ptr.container_ty.errorUnionPayload(); - bitcast_needed = !payload_ty.eql(ptr_child_ty); + bitcast_needed = !payload_ty.eql(ptr_child_ty, target); if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { // In this case, we represent pointer to error union the same as pointer @@ -3053,12 +3054,13 @@ pub const DeclGen = struct { tv: TypedValue, decl: *Module.Decl, ) Error!*const llvm.Value { + const target = self.module.getTarget(); if (tv.ty.isSlice()) { var buf: Type.SlicePtrFieldTypeBuffer = undefined; const ptr_ty = tv.ty.slicePtrFieldType(&buf); var slice_len: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, - .data = tv.val.sliceLen(), + .data = tv.val.sliceLen(target), }; const fields: [2]*const llvm.Value = .{ try self.genTypedValue(.{ diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 0d9d1ae223..6072c59845 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -313,7 +313,7 @@ pub const DeclGen = struct { // As of yet, there is no vector support in the self-hosted compiler. .Vector => self.todo("implement arithmeticTypeInfo for Vector", .{}), // TODO: For which types is this the case? - else => self.todo("implement arithmeticTypeInfo for {}", .{ty}), + else => self.todo("implement arithmeticTypeInfo for {}", .{ty.fmtDebug()}), }; } @@ -335,7 +335,7 @@ pub const DeclGen = struct { const int_info = ty.intInfo(target); const backing_bits = self.backingIntBits(int_info.bits) orelse { // Integers too big for any native type are represented as "composite integers": An array of largestSupportedIntBits. - return self.todo("implement composite int constants for {}", .{ty}); + return self.todo("implement composite int constants for {}", .{ty.fmtDebug()}); }; // We can just use toSignedInt/toUnsignedInt here as it returns u64 - a type large enough to hold any @@ -345,7 +345,7 @@ pub const DeclGen = struct { // Note, value is required to be sign-extended, so we don't need to mask off the upper bits. // See https://www.khronos.org/registry/SPIR-V/specs/unified1/SPIRV.html#Literal - var int_bits = if (ty.isSignedInt()) @bitCast(u64, val.toSignedInt()) else val.toUnsignedInt(); + var int_bits = if (ty.isSignedInt()) @bitCast(u64, val.toSignedInt()) else val.toUnsignedInt(target); const value: spec.LiteralContextDependentNumber = switch (backing_bits) { 1...32 => .{ .uint32 = @truncate(u32, int_bits) }, @@ -388,7 +388,7 @@ pub const DeclGen = struct { }); }, .Void => unreachable, - else => return self.todo("constant generation of type {}", .{ty}), + else => return self.todo("constant generation of type {}", .{ty.fmtDebug()}), } return result_id.toRef(); @@ -414,7 +414,7 @@ pub const DeclGen = struct { const backing_bits = self.backingIntBits(int_info.bits) orelse { // TODO: Integers too big for any native type are represented as "composite integers": // An array of largestSupportedIntBits. - return self.todo("Implement composite int type {}", .{ty}); + return self.todo("Implement composite int type {}", .{ty.fmtDebug()}); }; const payload = try self.spv.arena.create(SpvType.Payload.Int); @@ -644,8 +644,10 @@ pub const DeclGen = struct { const result_id = self.spv.allocId(); const result_type_id = try self.resolveTypeId(ty); - assert(self.air.typeOf(bin_op.lhs).eql(ty)); - assert(self.air.typeOf(bin_op.rhs).eql(ty)); + const target = self.getTarget(); + + assert(self.air.typeOf(bin_op.lhs).eql(ty, target)); + assert(self.air.typeOf(bin_op.rhs).eql(ty, target)); // Binary operations are generally applicable to both scalar and vector operations // in SPIR-V, but int and float versions of operations require different opcodes. @@ -692,7 +694,7 @@ pub const DeclGen = struct { const result_id = self.spv.allocId(); const result_type_id = try self.resolveTypeId(Type.initTag(.bool)); const op_ty = self.air.typeOf(bin_op.lhs); - assert(op_ty.eql(self.air.typeOf(bin_op.rhs))); + assert(op_ty.eql(self.air.typeOf(bin_op.rhs), self.getTarget())); // Comparisons are generally applicable to both scalar and vector operations in SPIR-V, // but int and float versions of operations require different opcodes. diff --git a/src/link.zig b/src/link.zig index d431e9d5f1..0fd6797153 100644 --- a/src/link.zig +++ b/src/link.zig @@ -457,7 +457,7 @@ pub const File = struct { /// May be called before or after updateDeclExports but must be called /// after allocateDeclIndexes for any given Decl. pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) UpdateDeclError!void { - log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty }); + log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty.fmtDebug() }); assert(decl.has_tv); switch (base.tag) { // zig fmt: off @@ -477,7 +477,7 @@ pub const File = struct { /// after allocateDeclIndexes for any given Decl. pub fn updateFunc(base: *File, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) UpdateDeclError!void { log.debug("updateFunc {*} ({s}), type={}", .{ - func.owner_decl, func.owner_decl.name, func.owner_decl.ty, + func.owner_decl, func.owner_decl.name, func.owner_decl.ty.fmtDebug(), }); switch (base.tag) { // zig fmt: off diff --git a/src/link/C.zig b/src/link/C.zig index 6599008c73..85b7c24487 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -127,7 +127,7 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes .error_msg = null, .decl = decl, .fwd_decl = fwd_decl.toManaged(module.gpa), - .typedefs = typedefs.promote(module.gpa), + .typedefs = typedefs.promoteContext(module.gpa, .{ .target = module.getTarget() }), .typedefs_arena = self.arena.allocator(), }, .code = code.toManaged(module.gpa), @@ -192,7 +192,7 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void { .error_msg = null, .decl = decl, .fwd_decl = fwd_decl.toManaged(module.gpa), - .typedefs = typedefs.promote(module.gpa), + .typedefs = typedefs.promoteContext(module.gpa, .{ .target = module.getTarget() }), .typedefs_arena = self.arena.allocator(), }, .code = code.toManaged(module.gpa), @@ -366,7 +366,9 @@ fn flushDecl(self: *C, f: *Flush, decl: *const Module.Decl) FlushDeclError!void try f.typedefs.ensureUnusedCapacity(gpa, @intCast(u32, decl_block.typedefs.count())); var it = decl_block.typedefs.iterator(); while (it.next()) |new| { - const gop = f.typedefs.getOrPutAssumeCapacity(new.key_ptr.*); + const gop = f.typedefs.getOrPutAssumeCapacityContext(new.key_ptr.*, .{ + .target = self.base.options.target, + }); if (!gop.found_existing) { try f.err_typedef_buf.appendSlice(gpa, new.value_ptr.rendered); } diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index fc8f1fab55..8f0eb96132 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -200,7 +200,9 @@ pub fn initDeclDebugInfo(self: *Dwarf, decl: *Module.Decl) !DeclDebugBuffers { assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len); dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4 if (fn_ret_has_bits) { - const gop = try dbg_info_type_relocs.getOrPut(gpa, fn_ret_type); + const gop = try dbg_info_type_relocs.getOrPutContext(gpa, fn_ret_type, .{ + .target = self.target, + }); if (!gop.found_existing) { gop.value_ptr.* = .{ .off = undefined, @@ -455,7 +457,9 @@ pub fn commitDeclDebugInfo( var it: usize = 0; while (it < dbg_info_type_relocs.count()) : (it += 1) { const ty = dbg_info_type_relocs.keys()[it]; - const value_ptr = dbg_info_type_relocs.getPtr(ty).?; + const value_ptr = dbg_info_type_relocs.getPtrContext(ty, .{ + .target = self.target, + }).?; value_ptr.off = @intCast(u32, dbg_info_buffer.items.len); try self.addDbgInfoType(dbg_type_arena.allocator(), ty, dbg_info_buffer, dbg_info_type_relocs); } @@ -774,7 +778,7 @@ fn addDbgInfoType( // DW.AT.byte_size, DW.FORM.data1 dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(target))); // DW.AT.name, DW.FORM.string - try dbg_info_buffer.writer().print("{}\x00", .{ty}); + try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)}); }, .Optional => { if (ty.isPtrLikeOptional()) { @@ -785,7 +789,7 @@ fn addDbgInfoType( // DW.AT.byte_size, DW.FORM.data1 dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(target))); // DW.AT.name, DW.FORM.string - try dbg_info_buffer.writer().print("{}\x00", .{ty}); + try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)}); } else { // Non-pointer optionals are structs: struct { .maybe = *, .val = * } var buf = try arena.create(Type.Payload.ElemType); @@ -796,7 +800,7 @@ fn addDbgInfoType( const abi_size = ty.abiSize(target); try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); // DW.AT.name, DW.FORM.string - try dbg_info_buffer.writer().print("{}\x00", .{ty}); + try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)}); // DW.AT.member try dbg_info_buffer.ensureUnusedCapacity(7); dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); @@ -835,7 +839,7 @@ fn addDbgInfoType( // DW.AT.byte_size, DW.FORM.sdata dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize) * 2); // DW.AT.name, DW.FORM.string - try dbg_info_buffer.writer().print("{}\x00", .{ty}); + try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)}); // DW.AT.member try dbg_info_buffer.ensureUnusedCapacity(5); dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); @@ -882,7 +886,7 @@ fn addDbgInfoType( const abi_size = ty.abiSize(target); try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); // DW.AT.name, DW.FORM.string - const struct_name = try ty.nameAllocArena(arena); + const struct_name = try ty.nameAllocArena(arena, target); try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1); dbg_info_buffer.appendSliceAssumeCapacity(struct_name); dbg_info_buffer.appendAssumeCapacity(0); @@ -915,13 +919,15 @@ fn addDbgInfoType( try dbg_info_buffer.append(0); }, else => { - log.debug("TODO implement .debug_info for type '{}'", .{ty}); + log.debug("TODO implement .debug_info for type '{}'", .{ty.fmtDebug()}); try dbg_info_buffer.append(abbrev_pad1); }, } for (relocs.items) |rel| { - const gop = try dbg_info_type_relocs.getOrPut(self.allocator, rel.ty); + const gop = try dbg_info_type_relocs.getOrPutContext(self.allocator, rel.ty, .{ + .target = self.target, + }); if (!gop.found_existing) { gop.value_ptr.* = .{ .off = undefined, diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 8bb0101301..82363c7e24 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -3874,7 +3874,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { /// Checks if the value, or any of its embedded values stores a pointer, and thus requires /// a rebase opcode for the dynamic linker. -fn needsPointerRebase(ty: Type, val: Value) bool { +fn needsPointerRebase(ty: Type, val: Value, target: std.Target) bool { if (ty.zigTypeTag() == .Fn) { return false; } @@ -3890,7 +3890,7 @@ fn needsPointerRebase(ty: Type, val: Value) bool { const elem_ty = ty.childType(); var elem_value_buf: Value.ElemValueBuffer = undefined; const elem_val = val.elemValueBuffer(0, &elem_value_buf); - return needsPointerRebase(elem_ty, elem_val); + return needsPointerRebase(elem_ty, elem_val, target); }, .Struct => { const fields = ty.structFields().values(); @@ -3898,7 +3898,7 @@ fn needsPointerRebase(ty: Type, val: Value) bool { if (val.castTag(.aggregate)) |payload| { const field_values = payload.data; for (field_values) |field_val, i| { - if (needsPointerRebase(fields[i].ty, field_val)) return true; + if (needsPointerRebase(fields[i].ty, field_val, target)) return true; } else return false; } else return false; }, @@ -3907,18 +3907,18 @@ fn needsPointerRebase(ty: Type, val: Value) bool { const sub_val = payload.data; var buffer: Type.Payload.ElemType = undefined; const sub_ty = ty.optionalChild(&buffer); - return needsPointerRebase(sub_ty, sub_val); + return needsPointerRebase(sub_ty, sub_val, target); } else return false; }, .Union => { const union_obj = val.cast(Value.Payload.Union).?.data; - const active_field_ty = ty.unionFieldType(union_obj.tag); - return needsPointerRebase(active_field_ty, union_obj.val); + const active_field_ty = ty.unionFieldType(union_obj.tag, target); + return needsPointerRebase(active_field_ty, union_obj.val, target); }, .ErrorUnion => { if (val.castTag(.eu_payload)) |payload| { const payload_ty = ty.errorUnionPayload(); - return needsPointerRebase(payload_ty, payload.data); + return needsPointerRebase(payload_ty, payload.data, target); } else return false; }, else => return false, @@ -3927,7 +3927,8 @@ fn needsPointerRebase(ty: Type, val: Value) bool { fn getMatchingSectionAtom(self: *MachO, atom: *Atom, name: []const u8, ty: Type, val: Value) !MatchingSection { const code = atom.code.items; - const alignment = ty.abiAlignment(self.base.options.target); + const target = self.base.options.target; + const alignment = ty.abiAlignment(target); const align_log_2 = math.log2(alignment); const zig_ty = ty.zigTypeTag(); const mode = self.base.options.optimize_mode; @@ -3954,7 +3955,7 @@ fn getMatchingSectionAtom(self: *MachO, atom: *Atom, name: []const u8, ty: Type, }; } - if (needsPointerRebase(ty, val)) { + if (needsPointerRebase(ty, val, target)) { break :blk (try self.getMatchingSection(.{ .segname = makeStaticString("__DATA_CONST"), .sectname = makeStaticString("__const"), diff --git a/src/print_air.zig b/src/print_air.zig index c6b27a6cd6..5e0179e3cc 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -299,12 +299,12 @@ const Writer = struct { fn writeTy(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { const ty = w.air.instructions.items(.data)[inst].ty; - try s.print("{}", .{ty}); + try s.print("{}", .{ty.fmtDebug()}); } fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { const ty_op = w.air.instructions.items(.data)[inst].ty_op; - try s.print("{}, ", .{w.air.getRefType(ty_op.ty)}); + try s.print("{}, ", .{w.air.getRefType(ty_op.ty).fmtDebug()}); try w.writeOperand(s, inst, 0, ty_op.operand); } @@ -313,7 +313,7 @@ const Writer = struct { const extra = w.air.extraData(Air.Block, ty_pl.payload); const body = w.air.extra[extra.end..][0..extra.data.body_len]; - try s.print("{}, {{\n", .{w.air.getRefType(ty_pl.ty)}); + try s.print("{}, {{\n", .{w.air.getRefType(ty_pl.ty).fmtDebug()}); const old_indent = w.indent; w.indent += 2; try w.writeBody(s, body); @@ -328,7 +328,7 @@ const Writer = struct { const len = @intCast(usize, vector_ty.arrayLen()); const elements = @bitCast([]const Air.Inst.Ref, w.air.extra[ty_pl.payload..][0..len]); - try s.print("{}, [", .{vector_ty}); + try s.print("{}, [", .{vector_ty.fmtDebug()}); for (elements) |elem, i| { if (i != 0) try s.writeAll(", "); try w.writeOperand(s, inst, i, elem); @@ -502,7 +502,7 @@ const Writer = struct { fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; const val = w.air.values[ty_pl.payload]; - try s.print("{}, {}", .{ w.air.getRefType(ty_pl.ty), val.fmtDebug() }); + try s.print("{}, {}", .{ w.air.getRefType(ty_pl.ty).fmtDebug(), val.fmtDebug() }); } fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { @@ -514,7 +514,7 @@ const Writer = struct { var op_index: usize = 0; const ret_ty = w.air.typeOfIndex(inst); - try s.print("{}", .{ret_ty}); + try s.print("{}", .{ret_ty.fmtDebug()}); if (is_volatile) { try s.writeAll(", volatile"); diff --git a/src/type.zig b/src/type.zig index 6d27150412..0b49eac0a8 100644 --- a/src/type.zig +++ b/src/type.zig @@ -6,6 +6,7 @@ const Target = std.Target; const Module = @import("Module.zig"); const log = std.log.scoped(.Type); const target_util = @import("target.zig"); +const TypedValue = @import("TypedValue.zig"); const file_struct = @This(); @@ -520,7 +521,7 @@ pub const Type = extern union { } } - pub fn eql(a: Type, b: Type) bool { + pub fn eql(a: Type, b: Type, target: Target) bool { // As a shortcut, if the small tags / addresses match, we're done. if (a.tag_if_small_enough == b.tag_if_small_enough) return true; @@ -636,7 +637,7 @@ pub const Type = extern union { const a_info = a.fnInfo(); const b_info = b.fnInfo(); - if (!eql(a_info.return_type, b_info.return_type)) + if (!eql(a_info.return_type, b_info.return_type, target)) return false; if (a_info.cc != b_info.cc) @@ -662,7 +663,7 @@ pub const Type = extern union { if (a_param_ty.tag() == .generic_poison) continue; if (b_param_ty.tag() == .generic_poison) continue; - if (!eql(a_param_ty, b_param_ty)) + if (!eql(a_param_ty, b_param_ty, target)) return false; } @@ -680,13 +681,13 @@ pub const Type = extern union { if (a.arrayLen() != b.arrayLen()) return false; const elem_ty = a.elemType(); - if (!elem_ty.eql(b.elemType())) + if (!elem_ty.eql(b.elemType(), target)) return false; const sentinel_a = a.sentinel(); const sentinel_b = b.sentinel(); if (sentinel_a) |sa| { if (sentinel_b) |sb| { - return sa.eql(sb, elem_ty); + return sa.eql(sb, elem_ty, target); } else { return false; } @@ -717,7 +718,7 @@ pub const Type = extern union { const info_a = a.ptrInfo().data; const info_b = b.ptrInfo().data; - if (!info_a.pointee_type.eql(info_b.pointee_type)) + if (!info_a.pointee_type.eql(info_b.pointee_type, target)) return false; if (info_a.@"align" != info_b.@"align") return false; @@ -740,7 +741,7 @@ pub const Type = extern union { const sentinel_b = info_b.sentinel; if (sentinel_a) |sa| { if (sentinel_b) |sb| { - if (!sa.eql(sb, info_a.pointee_type)) + if (!sa.eql(sb, info_a.pointee_type, target)) return false; } else { return false; @@ -761,7 +762,7 @@ pub const Type = extern union { var buf_a: Payload.ElemType = undefined; var buf_b: Payload.ElemType = undefined; - return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b)); + return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b), target); }, .anyerror_void_error_union, .error_union => { @@ -769,18 +770,18 @@ pub const Type = extern union { const a_set = a.errorUnionSet(); const b_set = b.errorUnionSet(); - if (!a_set.eql(b_set)) return false; + if (!a_set.eql(b_set, target)) return false; const a_payload = a.errorUnionPayload(); const b_payload = b.errorUnionPayload(); - if (!a_payload.eql(b_payload)) return false; + if (!a_payload.eql(b_payload, target)) return false; return true; }, .anyframe_T => { if (b.zigTypeTag() != .AnyFrame) return false; - return a.childType().eql(b.childType()); + return a.childType().eql(b.childType(), target); }, .empty_struct => { @@ -803,7 +804,7 @@ pub const Type = extern union { for (a_tuple.types) |a_ty, i| { const b_ty = b_tuple.types[i]; - if (!eql(a_ty, b_ty)) return false; + if (!eql(a_ty, b_ty, target)) return false; } for (a_tuple.values) |a_val, i| { @@ -819,7 +820,7 @@ pub const Type = extern union { if (b_val.tag() == .unreachable_value) { return false; } else { - if (!Value.eql(a_val, b_val, ty)) return false; + if (!Value.eql(a_val, b_val, ty, target)) return false; } } } @@ -839,7 +840,7 @@ pub const Type = extern union { for (a_struct_obj.types) |a_ty, i| { const b_ty = b_struct_obj.types[i]; - if (!eql(a_ty, b_ty)) return false; + if (!eql(a_ty, b_ty, target)) return false; } for (a_struct_obj.values) |a_val, i| { @@ -855,7 +856,7 @@ pub const Type = extern union { if (b_val.tag() == .unreachable_value) { return false; } else { - if (!Value.eql(a_val, b_val, ty)) return false; + if (!Value.eql(a_val, b_val, ty, target)) return false; } } } @@ -910,13 +911,13 @@ pub const Type = extern union { } } - pub fn hash(self: Type) u64 { + pub fn hash(self: Type, target: Target) u64 { var hasher = std.hash.Wyhash.init(0); - self.hashWithHasher(&hasher); + self.hashWithHasher(&hasher, target); return hasher.final(); } - pub fn hashWithHasher(ty: Type, hasher: *std.hash.Wyhash) void { + pub fn hashWithHasher(ty: Type, hasher: *std.hash.Wyhash, target: Target) void { switch (ty.tag()) { .generic_poison => unreachable, @@ -1035,7 +1036,7 @@ pub const Type = extern union { std.hash.autoHash(hasher, std.builtin.TypeId.Fn); const fn_info = ty.fnInfo(); - hashWithHasher(fn_info.return_type, hasher); + hashWithHasher(fn_info.return_type, hasher, target); std.hash.autoHash(hasher, fn_info.alignment); std.hash.autoHash(hasher, fn_info.cc); std.hash.autoHash(hasher, fn_info.is_var_args); @@ -1045,7 +1046,7 @@ pub const Type = extern union { for (fn_info.param_types) |param_ty, i| { std.hash.autoHash(hasher, fn_info.paramIsComptime(i)); if (param_ty.tag() == .generic_poison) continue; - hashWithHasher(param_ty, hasher); + hashWithHasher(param_ty, hasher, target); } }, @@ -1058,8 +1059,8 @@ pub const Type = extern union { const elem_ty = ty.elemType(); std.hash.autoHash(hasher, ty.arrayLen()); - hashWithHasher(elem_ty, hasher); - hashSentinel(ty.sentinel(), elem_ty, hasher); + hashWithHasher(elem_ty, hasher, target); + hashSentinel(ty.sentinel(), elem_ty, hasher, target); }, .vector => { @@ -1067,7 +1068,7 @@ pub const Type = extern union { const elem_ty = ty.elemType(); std.hash.autoHash(hasher, ty.vectorLen()); - hashWithHasher(elem_ty, hasher); + hashWithHasher(elem_ty, hasher, target); }, .single_const_pointer_to_comptime_int, @@ -1091,8 +1092,8 @@ pub const Type = extern union { std.hash.autoHash(hasher, std.builtin.TypeId.Pointer); const info = ty.ptrInfo().data; - hashWithHasher(info.pointee_type, hasher); - hashSentinel(info.sentinel, info.pointee_type, hasher); + hashWithHasher(info.pointee_type, hasher, target); + hashSentinel(info.sentinel, info.pointee_type, hasher, target); std.hash.autoHash(hasher, info.@"align"); std.hash.autoHash(hasher, info.@"addrspace"); std.hash.autoHash(hasher, info.bit_offset); @@ -1110,22 +1111,22 @@ pub const Type = extern union { std.hash.autoHash(hasher, std.builtin.TypeId.Optional); var buf: Payload.ElemType = undefined; - hashWithHasher(ty.optionalChild(&buf), hasher); + hashWithHasher(ty.optionalChild(&buf), hasher, target); }, .anyerror_void_error_union, .error_union => { std.hash.autoHash(hasher, std.builtin.TypeId.ErrorUnion); const set_ty = ty.errorUnionSet(); - hashWithHasher(set_ty, hasher); + hashWithHasher(set_ty, hasher, target); const payload_ty = ty.errorUnionPayload(); - hashWithHasher(payload_ty, hasher); + hashWithHasher(payload_ty, hasher, target); }, .anyframe_T => { std.hash.autoHash(hasher, std.builtin.TypeId.AnyFrame); - hashWithHasher(ty.childType(), hasher); + hashWithHasher(ty.childType(), hasher, target); }, .empty_struct => { @@ -1144,10 +1145,10 @@ pub const Type = extern union { std.hash.autoHash(hasher, tuple.types.len); for (tuple.types) |field_ty, i| { - hashWithHasher(field_ty, hasher); + hashWithHasher(field_ty, hasher, target); const field_val = tuple.values[i]; if (field_val.tag() == .unreachable_value) continue; - field_val.hash(field_ty, hasher); + field_val.hash(field_ty, hasher, target); } }, .anon_struct => { @@ -1159,9 +1160,9 @@ pub const Type = extern union { const field_name = struct_obj.names[i]; const field_val = struct_obj.values[i]; hasher.update(field_name); - hashWithHasher(field_ty, hasher); + hashWithHasher(field_ty, hasher, target); if (field_val.tag() == .unreachable_value) continue; - field_val.hash(field_ty, hasher); + field_val.hash(field_ty, hasher, target); } }, @@ -1209,35 +1210,35 @@ pub const Type = extern union { } } - fn hashSentinel(opt_val: ?Value, ty: Type, hasher: *std.hash.Wyhash) void { + fn hashSentinel(opt_val: ?Value, ty: Type, hasher: *std.hash.Wyhash, target: Target) void { if (opt_val) |s| { std.hash.autoHash(hasher, true); - s.hash(ty, hasher); + s.hash(ty, hasher, target); } else { std.hash.autoHash(hasher, false); } } pub const HashContext64 = struct { + target: Target, + pub fn hash(self: @This(), t: Type) u64 { - _ = self; - return t.hash(); + return t.hash(self.target); } pub fn eql(self: @This(), a: Type, b: Type) bool { - _ = self; - return a.eql(b); + return a.eql(b, self.target); } }; pub const HashContext32 = struct { + target: Target, + pub fn hash(self: @This(), t: Type) u32 { - _ = self; - return @truncate(u32, t.hash()); + return @truncate(u32, t.hash(self.target)); } pub fn eql(self: @This(), a: Type, b: Type, b_index: usize) bool { - _ = self; _ = b_index; - return a.eql(b); + return a.eql(b, self.target); } }; @@ -1404,8 +1405,8 @@ pub const Type = extern union { .function => { const payload = self.castTag(.function).?.data; const param_types = try allocator.alloc(Type, payload.param_types.len); - for (payload.param_types) |param_type, i| { - param_types[i] = try param_type.copy(allocator); + for (payload.param_types) |param_ty, i| { + param_types[i] = try param_ty.copy(allocator); } const other_comptime_params = payload.comptime_params[0..payload.param_types.len]; const comptime_params = try allocator.dupe(bool, other_comptime_params); @@ -1474,14 +1475,42 @@ pub const Type = extern union { return Type{ .ptr_otherwise = &new_payload.base }; } - pub fn format( + pub fn format(ty: Type, comptime unused_fmt_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { + _ = ty; + _ = unused_fmt_string; + _ = options; + _ = writer; + @compileError("do not format types directly; use either ty.fmtDebug() or ty.fmt()"); + } + + pub fn fmt(ty: Type, target: Target) std.fmt.Formatter(TypedValue.format) { + var ty_payload: Value.Payload.Ty = .{ + .base = .{ .tag = .ty }, + .data = ty, + }; + return .{ .data = .{ + .tv = .{ + .ty = Type.type, + .val = Value.initPayload(&ty_payload.base), + }, + .target = target, + } }; + } + + pub fn fmtDebug(ty: Type) std.fmt.Formatter(dump) { + return .{ .data = ty }; + } + + /// This is a debug function. In order to print types in a meaningful way + /// we also need access to the target. + pub fn dump( start_type: Type, - comptime fmt: []const u8, + comptime unused_format_string: []const u8, options: std.fmt.FormatOptions, writer: anytype, ) @TypeOf(writer).Error!void { _ = options; - comptime assert(fmt.len == 0); + comptime assert(unused_format_string.len == 0); var ty = start_type; while (true) { const t = ty.tag(); @@ -1584,7 +1613,7 @@ pub const Type = extern union { try writer.writeAll("fn("); for (payload.param_types) |param_type, i| { if (i != 0) try writer.writeAll(", "); - try param_type.format("", .{}, writer); + try param_type.dump("", .{}, writer); } if (payload.is_var_args) { if (payload.param_types.len != 0) { @@ -1622,7 +1651,7 @@ pub const Type = extern union { .vector => { const payload = ty.castTag(.vector).?.data; try writer.print("@Vector({d}, ", .{payload.len}); - try payload.elem_type.format("", .{}, writer); + try payload.elem_type.dump("", .{}, writer); return writer.writeAll(")"); }, .array => { @@ -1633,7 +1662,10 @@ pub const Type = extern union { }, .array_sentinel => { const payload = ty.castTag(.array_sentinel).?.data; - try writer.print("[{d}:{}]", .{ payload.len, payload.sentinel.fmtValue(payload.elem_type) }); + try writer.print("[{d}:{}]", .{ + payload.len, + payload.sentinel.fmtDebug(), + }); ty = payload.elem_type; continue; }, @@ -1646,9 +1678,9 @@ pub const Type = extern union { if (val.tag() != .unreachable_value) { try writer.writeAll("comptime "); } - try field_ty.format("", .{}, writer); + try field_ty.dump("", .{}, writer); if (val.tag() != .unreachable_value) { - try writer.print(" = {}", .{val.fmtValue(field_ty)}); + try writer.print(" = {}", .{val.fmtDebug()}); } } try writer.writeAll("}"); @@ -1665,9 +1697,9 @@ pub const Type = extern union { } try writer.writeAll(anon_struct.names[i]); try writer.writeAll(": "); - try field_ty.format("", .{}, writer); + try field_ty.dump("", .{}, writer); if (val.tag() != .unreachable_value) { - try writer.print(" = {}", .{val.fmtValue(field_ty)}); + try writer.print(" = {}", .{val.fmtDebug()}); } } try writer.writeAll("}"); @@ -1752,8 +1784,8 @@ pub const Type = extern union { const payload = ty.castTag(.pointer).?.data; if (payload.sentinel) |some| switch (payload.size) { .One, .C => unreachable, - .Many => try writer.print("[*:{}]", .{some.fmtValue(payload.pointee_type)}), - .Slice => try writer.print("[:{}]", .{some.fmtValue(payload.pointee_type)}), + .Many => try writer.print("[*:{}]", .{some.fmtDebug()}), + .Slice => try writer.print("[:{}]", .{some.fmtDebug()}), } else switch (payload.size) { .One => try writer.writeAll("*"), .Many => try writer.writeAll("[*]"), @@ -1780,7 +1812,7 @@ pub const Type = extern union { }, .error_union => { const payload = ty.castTag(.error_union).?.data; - try payload.error_set.format("", .{}, writer); + try payload.error_set.dump("", .{}, writer); try writer.writeAll("!"); ty = payload.payload; continue; @@ -1821,20 +1853,17 @@ pub const Type = extern union { } } - pub fn nameAllocArena(ty: Type, arena: Allocator) Allocator.Error![:0]const u8 { - return nameAllocAdvanced(ty, arena, true); + pub const nameAllocArena = nameAlloc; + + pub fn nameAlloc(ty: Type, ally: Allocator, target: Target) Allocator.Error![:0]const u8 { + var buffer = std.ArrayList(u8).init(ally); + defer buffer.deinit(); + try ty.print(buffer.writer(), target); + return buffer.toOwnedSliceSentinel(0); } - pub fn nameAlloc(ty: Type, gpa: Allocator) Allocator.Error![:0]const u8 { - return nameAllocAdvanced(ty, gpa, false); - } - - /// Returns a name suitable for `@typeName`. - pub fn nameAllocAdvanced( - ty: Type, - ally: Allocator, - is_arena: bool, - ) Allocator.Error![:0]const u8 { + /// Prints a name suitable for `@typeName`. + pub fn print(ty: Type, writer: anytype, target: Target) @TypeOf(writer).Error!void { const t = ty.tag(); switch (t) { .inferred_alloc_const => unreachable, @@ -1892,141 +1921,251 @@ pub const Type = extern union { .comptime_int, .comptime_float, .noreturn, - => return maybeDupe(@tagName(t), ally, is_arena), + => try writer.writeAll(@tagName(t)), - .enum_literal => return maybeDupe("@TypeOf(.enum_literal)", ally, is_arena), - .@"null" => return maybeDupe("@TypeOf(null)", ally, is_arena), - .@"undefined" => return maybeDupe("@TypeOf(undefined)", ally, is_arena), - .empty_struct_literal => return maybeDupe("@TypeOf(.{})", ally, is_arena), + .enum_literal => try writer.writeAll("@TypeOf(.enum_literal)"), + .@"null" => try writer.writeAll("@TypeOf(null)"), + .@"undefined" => try writer.writeAll("@TypeOf(undefined)"), + .empty_struct_literal => try writer.writeAll("@TypeOf(.{})"), .empty_struct => { const namespace = ty.castTag(.empty_struct).?.data; - var buffer = std.ArrayList(u8).init(ally); - defer buffer.deinit(); - try namespace.renderFullyQualifiedName("", buffer.writer()); - return buffer.toOwnedSliceSentinel(0); + try namespace.renderFullyQualifiedName("", writer); }, .@"struct" => { const struct_obj = ty.castTag(.@"struct").?.data; - return try struct_obj.owner_decl.getFullyQualifiedName(ally); + try struct_obj.owner_decl.renderFullyQualifiedName(writer); }, .@"union", .union_tagged => { const union_obj = ty.cast(Payload.Union).?.data; - return try union_obj.owner_decl.getFullyQualifiedName(ally); + try union_obj.owner_decl.renderFullyQualifiedName(writer); }, .enum_full, .enum_nonexhaustive => { const enum_full = ty.cast(Payload.EnumFull).?.data; - return try enum_full.owner_decl.getFullyQualifiedName(ally); + try enum_full.owner_decl.renderFullyQualifiedName(writer); }, .enum_simple => { const enum_simple = ty.castTag(.enum_simple).?.data; - return try enum_simple.owner_decl.getFullyQualifiedName(ally); + try enum_simple.owner_decl.renderFullyQualifiedName(writer); }, .enum_numbered => { const enum_numbered = ty.castTag(.enum_numbered).?.data; - return try enum_numbered.owner_decl.getFullyQualifiedName(ally); + try enum_numbered.owner_decl.renderFullyQualifiedName(writer); }, .@"opaque" => { const opaque_obj = ty.cast(Payload.Opaque).?.data; - return try opaque_obj.owner_decl.getFullyQualifiedName(ally); + try opaque_obj.owner_decl.renderFullyQualifiedName(writer); }, - .anyerror_void_error_union => return maybeDupe("anyerror!void", ally, is_arena), - .const_slice_u8 => return maybeDupe("[]const u8", ally, is_arena), - .const_slice_u8_sentinel_0 => return maybeDupe("[:0]const u8", ally, is_arena), - .fn_noreturn_no_args => return maybeDupe("fn() noreturn", ally, is_arena), - .fn_void_no_args => return maybeDupe("fn() void", ally, is_arena), - .fn_naked_noreturn_no_args => return maybeDupe("fn() callconv(.Naked) noreturn", ally, is_arena), - .fn_ccc_void_no_args => return maybeDupe("fn() callconv(.C) void", ally, is_arena), - .single_const_pointer_to_comptime_int => return maybeDupe("*const comptime_int", ally, is_arena), - .manyptr_u8 => return maybeDupe("[*]u8", ally, is_arena), - .manyptr_const_u8 => return maybeDupe("[*]const u8", ally, is_arena), - .manyptr_const_u8_sentinel_0 => return maybeDupe("[*:0]const u8", ally, is_arena), + .anyerror_void_error_union => try writer.writeAll("anyerror!void"), + .const_slice_u8 => try writer.writeAll("[]const u8"), + .const_slice_u8_sentinel_0 => try writer.writeAll("[:0]const u8"), + .fn_noreturn_no_args => try writer.writeAll("fn() noreturn"), + .fn_void_no_args => try writer.writeAll("fn() void"), + .fn_naked_noreturn_no_args => try writer.writeAll("fn() callconv(.Naked) noreturn"), + .fn_ccc_void_no_args => try writer.writeAll("fn() callconv(.C) void"), + .single_const_pointer_to_comptime_int => try writer.writeAll("*const comptime_int"), + .manyptr_u8 => try writer.writeAll("[*]u8"), + .manyptr_const_u8 => try writer.writeAll("[*]const u8"), + .manyptr_const_u8_sentinel_0 => try writer.writeAll("[*:0]const u8"), .error_set_inferred => { const func = ty.castTag(.error_set_inferred).?.data.func; - var buf = std.ArrayList(u8).init(ally); - defer buf.deinit(); - try buf.appendSlice("@typeInfo(@typeInfo(@TypeOf("); - try func.owner_decl.renderFullyQualifiedName(buf.writer()); - try buf.appendSlice(")).Fn.return_type.?).ErrorUnion.error_set"); - return try buf.toOwnedSliceSentinel(0); + try writer.writeAll("@typeInfo(@typeInfo(@TypeOf("); + try func.owner_decl.renderFullyQualifiedName(writer); + try writer.writeAll(")).Fn.return_type.?).ErrorUnion.error_set"); }, .function => { const fn_info = ty.fnInfo(); - var buf = std.ArrayList(u8).init(ally); - defer buf.deinit(); - try buf.appendSlice("fn("); - for (fn_info.param_types) |param_type, i| { - if (i != 0) try buf.appendSlice(", "); - const param_name = try param_type.nameAllocAdvanced(ally, is_arena); - defer if (!is_arena) ally.free(param_name); - try buf.appendSlice(param_name); + try writer.writeAll("fn("); + for (fn_info.param_types) |param_ty, i| { + if (i != 0) try writer.writeAll(", "); + try print(param_ty, writer, target); } if (fn_info.is_var_args) { if (fn_info.param_types.len != 0) { - try buf.appendSlice(", "); + try writer.writeAll(", "); } - try buf.appendSlice("..."); + try writer.writeAll("..."); } - try buf.appendSlice(") "); + try writer.writeAll(") "); if (fn_info.cc != .Unspecified) { - try buf.appendSlice("callconv(."); - try buf.appendSlice(@tagName(fn_info.cc)); - try buf.appendSlice(") "); + try writer.writeAll("callconv(."); + try writer.writeAll(@tagName(fn_info.cc)); + try writer.writeAll(") "); } if (fn_info.alignment != 0) { - try buf.writer().print("align({d}) ", .{fn_info.alignment}); + try writer.print("align({d}) ", .{fn_info.alignment}); } - { - const ret_ty_name = try fn_info.return_type.nameAllocAdvanced(ally, is_arena); - defer if (!is_arena) ally.free(ret_ty_name); - try buf.appendSlice(ret_ty_name); - } - return try buf.toOwnedSliceSentinel(0); + try print(fn_info.return_type, writer, target); }, .error_union => { const error_union = ty.castTag(.error_union).?.data; - - var buf = std.ArrayList(u8).init(ally); - defer buf.deinit(); - - { - const err_set_ty_name = try error_union.error_set.nameAllocAdvanced(ally, is_arena); - defer if (!is_arena) ally.free(err_set_ty_name); - try buf.appendSlice(err_set_ty_name); - } - - try buf.appendSlice("!"); - - { - const payload_ty_name = try error_union.payload.nameAllocAdvanced(ally, is_arena); - defer if (!is_arena) ally.free(payload_ty_name); - try buf.appendSlice(payload_ty_name); - } - - return try buf.toOwnedSliceSentinel(0); + try print(error_union.error_set, writer, target); + try writer.writeAll("!"); + try print(error_union.payload, writer, target); }, - else => { - // TODO this is wasteful and also an incorrect implementation of `@typeName` - var buf = std.ArrayList(u8).init(ally); - defer buf.deinit(); - try buf.writer().print("{}", .{ty}); - return try buf.toOwnedSliceSentinel(0); + .array_u8 => { + const len = ty.castTag(.array_u8).?.data; + try writer.print("[{d}]u8", .{len}); }, - } - } + .array_u8_sentinel_0 => { + const len = ty.castTag(.array_u8_sentinel_0).?.data; + try writer.print("[{d}:0]u8", .{len}); + }, + .vector => { + const payload = ty.castTag(.vector).?.data; + try writer.print("@Vector({d}, ", .{payload.len}); + try print(payload.elem_type, writer, target); + try writer.writeAll(")"); + }, + .array => { + const payload = ty.castTag(.array).?.data; + try writer.print("[{d}]", .{payload.len}); + try print(payload.elem_type, writer, target); + }, + .array_sentinel => { + const payload = ty.castTag(.array_sentinel).?.data; + try writer.print("[{d}:{}]", .{ + payload.len, + payload.sentinel.fmtValue(payload.elem_type, target), + }); + try print(payload.elem_type, writer, target); + }, + .tuple => { + const tuple = ty.castTag(.tuple).?.data; - fn maybeDupe(s: [:0]const u8, ally: Allocator, is_arena: bool) Allocator.Error![:0]const u8 { - if (is_arena) { - return s; - } else { - return try ally.dupeZ(u8, s); + try writer.writeAll("tuple{"); + for (tuple.types) |field_ty, i| { + if (i != 0) try writer.writeAll(", "); + const val = tuple.values[i]; + if (val.tag() != .unreachable_value) { + try writer.writeAll("comptime "); + } + try print(field_ty, writer, target); + if (val.tag() != .unreachable_value) { + try writer.print(" = {}", .{val.fmtValue(field_ty, target)}); + } + } + try writer.writeAll("}"); + }, + .anon_struct => { + const anon_struct = ty.castTag(.anon_struct).?.data; + + try writer.writeAll("struct{"); + for (anon_struct.types) |field_ty, i| { + if (i != 0) try writer.writeAll(", "); + const val = anon_struct.values[i]; + if (val.tag() != .unreachable_value) { + try writer.writeAll("comptime "); + } + try writer.writeAll(anon_struct.names[i]); + try writer.writeAll(": "); + + try print(field_ty, writer, target); + + if (val.tag() != .unreachable_value) { + try writer.print(" = {}", .{val.fmtValue(field_ty, target)}); + } + } + try writer.writeAll("}"); + }, + + .pointer, + .single_const_pointer, + .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + .const_slice, + .mut_slice, + => { + const info = ty.ptrInfo().data; + + if (info.sentinel) |s| switch (info.size) { + .One, .C => unreachable, + .Many => try writer.print("[*:{}]", .{s.fmtValue(info.pointee_type, target)}), + .Slice => try writer.print("[:{}]", .{s.fmtValue(info.pointee_type, target)}), + } else switch (info.size) { + .One => try writer.writeAll("*"), + .Many => try writer.writeAll("[*]"), + .C => try writer.writeAll("[*c]"), + .Slice => try writer.writeAll("[]"), + } + if (info.@"align" != 0 or info.host_size != 0) { + try writer.print("align({d}", .{info.@"align"}); + + if (info.bit_offset != 0) { + try writer.print(":{d}:{d}", .{ info.bit_offset, info.host_size }); + } + try writer.writeAll(") "); + } + if (info.@"addrspace" != .generic) { + try writer.print("addrspace(.{s}) ", .{@tagName(info.@"addrspace")}); + } + if (!info.mutable) try writer.writeAll("const "); + if (info.@"volatile") try writer.writeAll("volatile "); + if (info.@"allowzero" and info.size != .C) try writer.writeAll("allowzero "); + + try print(info.pointee_type, writer, target); + }, + + .int_signed => { + const bits = ty.castTag(.int_signed).?.data; + return writer.print("i{d}", .{bits}); + }, + .int_unsigned => { + const bits = ty.castTag(.int_unsigned).?.data; + return writer.print("u{d}", .{bits}); + }, + .optional => { + const child_type = ty.castTag(.optional).?.data; + try writer.writeByte('?'); + try print(child_type, writer, target); + }, + .optional_single_mut_pointer => { + const pointee_type = ty.castTag(.optional_single_mut_pointer).?.data; + try writer.writeAll("?*"); + try print(pointee_type, writer, target); + }, + .optional_single_const_pointer => { + const pointee_type = ty.castTag(.optional_single_const_pointer).?.data; + try writer.writeAll("?*const "); + try print(pointee_type, writer, target); + }, + .anyframe_T => { + const return_type = ty.castTag(.anyframe_T).?.data; + try writer.print("anyframe->", .{}); + try print(return_type, writer, target); + }, + .error_set => { + const names = ty.castTag(.error_set).?.data.names.keys(); + try writer.writeAll("error{"); + for (names) |name, i| { + if (i != 0) try writer.writeByte(','); + try writer.writeAll(name); + } + try writer.writeAll("}"); + }, + .error_set_single => { + const name = ty.castTag(.error_set_single).?.data; + return writer.print("error{{{s}}}", .{name}); + }, + .error_set_merged => { + const names = ty.castTag(.error_set_merged).?.data.keys(); + try writer.writeAll("error{"); + for (names) |name, i| { + if (i != 0) try writer.writeByte(','); + try writer.writeAll(name); + } + try writer.writeAll("}"); + }, } } @@ -2518,8 +2657,33 @@ pub const Type = extern union { } /// Returns 0 for 0-bit types. - pub fn abiAlignment(self: Type, target: Target) u32 { - return switch (self.tag()) { + pub fn abiAlignment(ty: Type, target: Target) u32 { + return ty.abiAlignmentAdvanced(target, .eager).scalar; + } + + /// May capture a reference to `ty`. + pub fn lazyAbiAlignment(ty: Type, target: Target, arena: Allocator) !Value { + switch (ty.abiAlignmentAdvanced(target, .{ .lazy = arena })) { + .val => |val| return try val, + .scalar => |x| return Value.Tag.int_u64.create(arena, x), + } + } + + /// If you pass `eager` you will get back `scalar` and assert the type is resolved. + /// If you pass `lazy` you may get back `scalar` or `val`. + /// If `val` is returned, a reference to `ty` has been captured. + fn abiAlignmentAdvanced( + ty: Type, + target: Target, + strat: union(enum) { + eager, + lazy: Allocator, + }, + ) union(enum) { + scalar: u32, + val: Allocator.Error!Value, + } { + return switch (ty.tag()) { .u1, .u8, .i8, @@ -2538,25 +2702,25 @@ pub const Type = extern union { .extern_options, .@"opaque", .anyopaque, - => return 1, + => return .{ .scalar = 1 }, .fn_noreturn_no_args, // represents machine code; not a pointer .fn_void_no_args, // represents machine code; not a pointer .fn_naked_noreturn_no_args, // represents machine code; not a pointer .fn_ccc_void_no_args, // represents machine code; not a pointer - => return target_util.defaultFunctionAlignment(target), + => return .{ .scalar = target_util.defaultFunctionAlignment(target) }, // represents machine code; not a pointer .function => { - const alignment = self.castTag(.function).?.data.alignment; - if (alignment != 0) return alignment; - return target_util.defaultFunctionAlignment(target); + const alignment = ty.castTag(.function).?.data.alignment; + if (alignment != 0) return .{ .scalar = alignment }; + return .{ .scalar = target_util.defaultFunctionAlignment(target) }; }, - .i16, .u16 => return 2, - .i32, .u32 => return 4, - .i64, .u64 => return 8, - .u128, .i128 => return 16, + .i16, .u16 => return .{ .scalar = 2 }, + .i32, .u32 => return .{ .scalar = 4 }, + .i64, .u64 => return .{ .scalar = 8 }, + .u128, .i128 => return .{ .scalar = 16 }, .isize, .usize, @@ -2579,40 +2743,40 @@ pub const Type = extern union { .manyptr_const_u8_sentinel_0, .@"anyframe", .anyframe_T, - => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + => return .{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) }, - .c_short => return @divExact(CType.short.sizeInBits(target), 8), - .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8), - .c_int => return @divExact(CType.int.sizeInBits(target), 8), - .c_uint => return @divExact(CType.uint.sizeInBits(target), 8), - .c_long => return @divExact(CType.long.sizeInBits(target), 8), - .c_ulong => return @divExact(CType.ulong.sizeInBits(target), 8), - .c_longlong => return @divExact(CType.longlong.sizeInBits(target), 8), - .c_ulonglong => return @divExact(CType.ulonglong.sizeInBits(target), 8), + .c_short => return .{ .scalar = @divExact(CType.short.sizeInBits(target), 8) }, + .c_ushort => return .{ .scalar = @divExact(CType.ushort.sizeInBits(target), 8) }, + .c_int => return .{ .scalar = @divExact(CType.int.sizeInBits(target), 8) }, + .c_uint => return .{ .scalar = @divExact(CType.uint.sizeInBits(target), 8) }, + .c_long => return .{ .scalar = @divExact(CType.long.sizeInBits(target), 8) }, + .c_ulong => return .{ .scalar = @divExact(CType.ulong.sizeInBits(target), 8) }, + .c_longlong => return .{ .scalar = @divExact(CType.longlong.sizeInBits(target), 8) }, + .c_ulonglong => return .{ .scalar = @divExact(CType.ulonglong.sizeInBits(target), 8) }, - .f16 => return 2, - .f32 => return 4, - .f64 => return 8, - .f128 => return 16, + .f16 => return .{ .scalar = 2 }, + .f32 => return .{ .scalar = 4 }, + .f64 => return .{ .scalar = 8 }, + .f128 => return .{ .scalar = 16 }, .f80 => switch (target.cpu.arch) { - .i386 => return 4, - .x86_64 => return 16, + .i386 => return .{ .scalar = 4 }, + .x86_64 => return .{ .scalar = 16 }, else => { var payload: Payload.Bits = .{ .base = .{ .tag = .int_unsigned }, .data = 80, }; const u80_ty = initPayload(&payload.base); - return abiAlignment(u80_ty, target); + return .{ .scalar = abiAlignment(u80_ty, target) }; }, }, .c_longdouble => switch (CType.longdouble.sizeInBits(target)) { - 16 => return abiAlignment(Type.f16, target), - 32 => return abiAlignment(Type.f32, target), - 64 => return abiAlignment(Type.f64, target), - 80 => return abiAlignment(Type.f80, target), - 128 => return abiAlignment(Type.f128, target), + 16 => return .{ .scalar = abiAlignment(Type.f16, target) }, + 32 => return .{ .scalar = abiAlignment(Type.f32, target) }, + 64 => return .{ .scalar = abiAlignment(Type.f64, target) }, + 80 => return .{ .scalar = abiAlignment(Type.f80, target) }, + 128 => return .{ .scalar = abiAlignment(Type.f128, target) }, else => unreachable, }, @@ -2622,60 +2786,93 @@ pub const Type = extern union { .anyerror, .error_set_inferred, .error_set_merged, - => return 2, // TODO revisit this when we have the concept of the error tag type + => return .{ .scalar = 2 }, // TODO revisit this when we have the concept of the error tag type - .array, .array_sentinel => return self.elemType().abiAlignment(target), + .array, .array_sentinel => return ty.elemType().abiAlignmentAdvanced(target, strat), // TODO audit this - is there any more complicated logic to determine // ABI alignment of vectors? - .vector => return 16, + .vector => return .{ .scalar = 16 }, .int_signed, .int_unsigned => { - const bits: u16 = self.cast(Payload.Bits).?.data; - if (bits == 0) return 0; - if (bits <= 8) return 1; - if (bits <= 16) return 2; - if (bits <= 32) return 4; - if (bits <= 64) return 8; - return 16; + const bits: u16 = ty.cast(Payload.Bits).?.data; + if (bits == 0) return .{ .scalar = 0 }; + if (bits <= 8) return .{ .scalar = 1 }; + if (bits <= 16) return .{ .scalar = 2 }; + if (bits <= 32) return .{ .scalar = 4 }; + if (bits <= 64) return .{ .scalar = 8 }; + return .{ .scalar = 16 }; }, .optional => { var buf: Payload.ElemType = undefined; - const child_type = self.optionalChild(&buf); - if (!child_type.hasRuntimeBits()) return 1; + const child_type = ty.optionalChild(&buf); - if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr()) - return @divExact(target.cpu.arch.ptrBitWidth(), 8); + if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr()) { + return .{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) }; + } - return child_type.abiAlignment(target); + switch (strat) { + .eager => { + if (!child_type.hasRuntimeBits()) return .{ .scalar = 1 }; + return .{ .scalar = child_type.abiAlignment(target) }; + }, + .lazy => |arena| switch (child_type.abiAlignmentAdvanced(target, strat)) { + .scalar => |x| return .{ .scalar = @maximum(x, 1) }, + .val => return .{ .val = Value.Tag.lazy_align.create(arena, ty) }, + }, + } }, .error_union => { - const data = self.castTag(.error_union).?.data; - if (!data.error_set.hasRuntimeBits()) { - return data.payload.abiAlignment(target); - } else if (!data.payload.hasRuntimeBits()) { - return data.error_set.abiAlignment(target); + const data = ty.castTag(.error_union).?.data; + switch (strat) { + .eager => { + if (!data.error_set.hasRuntimeBits()) { + return .{ .scalar = data.payload.abiAlignment(target) }; + } else if (!data.payload.hasRuntimeBits()) { + return .{ .scalar = data.error_set.abiAlignment(target) }; + } + return .{ .scalar = @maximum( + data.payload.abiAlignment(target), + data.error_set.abiAlignment(target), + ) }; + }, + .lazy => |arena| { + switch (data.payload.abiAlignmentAdvanced(target, strat)) { + .scalar => |payload_align| { + if (payload_align == 0) { + return data.error_set.abiAlignmentAdvanced(target, strat); + } + switch (data.error_set.abiAlignmentAdvanced(target, strat)) { + .scalar => |err_set_align| { + return .{ .scalar = @maximum(payload_align, err_set_align) }; + }, + .val => {}, + } + }, + .val => {}, + } + return .{ .val = Value.Tag.lazy_align.create(arena, ty) }; + }, } - return @maximum( - data.payload.abiAlignment(target), - data.error_set.abiAlignment(target), - ); }, .@"struct" => { - const fields = self.structFields(); - if (self.castTag(.@"struct")) |payload| { + if (ty.castTag(.@"struct")) |payload| { const struct_obj = payload.data; - assert(struct_obj.haveLayout()); + if (!struct_obj.haveLayout()) switch (strat) { + .eager => unreachable, // struct layout not resolved + .lazy => |arena| return .{ .val = Value.Tag.lazy_align.create(arena, ty) }, + }; if (struct_obj.layout == .Packed) { var buf: Type.Payload.Bits = undefined; const int_ty = struct_obj.packedIntegerType(target, &buf); - return int_ty.abiAlignment(target); + return .{ .scalar = int_ty.abiAlignment(target) }; } } + const fields = ty.structFields(); var big_align: u32 = 0; for (fields.values()) |field| { if (!field.ty.hasRuntimeBits()) continue; @@ -2683,31 +2880,45 @@ pub const Type = extern union { const field_align = field.normalAlignment(target); big_align = @maximum(big_align, field_align); } - return big_align; + return .{ .scalar = big_align }; }, .tuple, .anon_struct => { - const tuple = self.tupleFields(); + const tuple = ty.tupleFields(); var big_align: u32 = 0; for (tuple.types) |field_ty, i| { const val = tuple.values[i]; if (val.tag() != .unreachable_value) continue; // comptime field - if (!field_ty.hasRuntimeBits()) continue; - const field_align = field_ty.abiAlignment(target); - big_align = @maximum(big_align, field_align); + switch (field_ty.abiAlignmentAdvanced(target, strat)) { + .scalar => |field_align| big_align = @maximum(big_align, field_align), + .val => switch (strat) { + .eager => unreachable, // field type alignment not resolved + .lazy => |arena| return .{ .val = Value.Tag.lazy_align.create(arena, ty) }, + }, + } } - return big_align; + return .{ .scalar = big_align }; }, .enum_full, .enum_nonexhaustive, .enum_simple, .enum_numbered => { var buffer: Payload.Bits = undefined; - const int_tag_ty = self.intTagType(&buffer); - return int_tag_ty.abiAlignment(target); + const int_tag_ty = ty.intTagType(&buffer); + return .{ .scalar = int_tag_ty.abiAlignment(target) }; + }, + .@"union" => switch (strat) { + .eager => { + // TODO pass `true` for have_tag when unions have a safety tag + return .{ .scalar = ty.castTag(.@"union").?.data.abiAlignment(target, false) }; + }, + .lazy => |arena| return .{ .val = Value.Tag.lazy_align.create(arena, ty) }, + }, + .union_tagged => switch (strat) { + .eager => { + return .{ .scalar = ty.castTag(.union_tagged).?.data.abiAlignment(target, true) }; + }, + .lazy => |arena| return .{ .val = Value.Tag.lazy_align.create(arena, ty) }, }, - // TODO pass `true` for have_tag when unions have a safety tag - .@"union" => return self.castTag(.@"union").?.data.abiAlignment(target, false), - .union_tagged => return self.castTag(.union_tagged).?.data.abiAlignment(target, true), .empty_struct, .void, @@ -2719,7 +2930,7 @@ pub const Type = extern union { .@"undefined", .enum_literal, .type_info, - => return 0, + => return .{ .scalar = 0 }, .noreturn, .inferred_alloc_const, @@ -3392,10 +3603,7 @@ pub const Type = extern union { .optional => { const child_ty = self.castTag(.optional).?.data; - // optionals of zero sized types behave like bools, not pointers - if (!child_ty.hasRuntimeBits()) return false; if (child_ty.zigTypeTag() != .Pointer) return false; - const info = child_ty.ptrInfo().data; switch (info.size) { .Slice, .C => return false, @@ -3663,9 +3871,9 @@ pub const Type = extern union { return union_obj.fields; } - pub fn unionFieldType(ty: Type, enum_tag: Value) Type { + pub fn unionFieldType(ty: Type, enum_tag: Value, target: Target) Type { const union_obj = ty.cast(Payload.Union).?.data; - const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag).?; + const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag, target).?; assert(union_obj.haveFieldTypes()); return union_obj.fields.values()[index].ty; } @@ -4679,20 +4887,20 @@ pub const Type = extern union { /// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or /// an integer which represents the enum value. Returns the field index in /// declaration order, or `null` if `enum_tag` does not match any field. - pub fn enumTagFieldIndex(ty: Type, enum_tag: Value) ?usize { + pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, target: Target) ?usize { if (enum_tag.castTag(.enum_field_index)) |payload| { return @as(usize, payload.data); } const S = struct { - fn fieldWithRange(int_ty: Type, int_val: Value, end: usize) ?usize { + fn fieldWithRange(int_ty: Type, int_val: Value, end: usize, tg: Target) ?usize { if (int_val.compareWithZero(.lt)) return null; var end_payload: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = end, }; const end_val = Value.initPayload(&end_payload.base); - if (int_val.compare(.gte, end_val, int_ty)) return null; - return @intCast(usize, int_val.toUnsignedInt()); + if (int_val.compare(.gte, end_val, int_ty, tg)) return null; + return @intCast(usize, int_val.toUnsignedInt(tg)); } }; switch (ty.tag()) { @@ -4700,18 +4908,24 @@ pub const Type = extern union { const enum_full = ty.cast(Payload.EnumFull).?.data; const tag_ty = enum_full.tag_ty; if (enum_full.values.count() == 0) { - return S.fieldWithRange(tag_ty, enum_tag, enum_full.fields.count()); + return S.fieldWithRange(tag_ty, enum_tag, enum_full.fields.count(), target); } else { - return enum_full.values.getIndexContext(enum_tag, .{ .ty = tag_ty }); + return enum_full.values.getIndexContext(enum_tag, .{ + .ty = tag_ty, + .target = target, + }); } }, .enum_numbered => { const enum_obj = ty.castTag(.enum_numbered).?.data; const tag_ty = enum_obj.tag_ty; if (enum_obj.values.count() == 0) { - return S.fieldWithRange(tag_ty, enum_tag, enum_obj.fields.count()); + return S.fieldWithRange(tag_ty, enum_tag, enum_obj.fields.count(), target); } else { - return enum_obj.values.getIndexContext(enum_tag, .{ .ty = tag_ty }); + return enum_obj.values.getIndexContext(enum_tag, .{ + .ty = tag_ty, + .target = target, + }); } }, .enum_simple => { @@ -4723,7 +4937,7 @@ pub const Type = extern union { .data = bits, }; const tag_ty = Type.initPayload(&buffer.base); - return S.fieldWithRange(tag_ty, enum_tag, fields_len); + return S.fieldWithRange(tag_ty, enum_tag, fields_len, target); }, .atomic_order, .atomic_rmw_op, @@ -5018,14 +5232,14 @@ pub const Type = extern union { /// Asserts the type is an enum. pub fn enumHasInt(ty: Type, int: Value, target: Target) bool { const S = struct { - fn intInRange(tag_ty: Type, int_val: Value, end: usize) bool { + fn intInRange(tag_ty: Type, int_val: Value, end: usize, tg: Target) bool { if (int_val.compareWithZero(.lt)) return false; var end_payload: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = end, }; const end_val = Value.initPayload(&end_payload.base); - if (int_val.compare(.gte, end_val, tag_ty)) return false; + if (int_val.compare(.gte, end_val, tag_ty, tg)) return false; return true; } }; @@ -5035,18 +5249,24 @@ pub const Type = extern union { const enum_full = ty.castTag(.enum_full).?.data; const tag_ty = enum_full.tag_ty; if (enum_full.values.count() == 0) { - return S.intInRange(tag_ty, int, enum_full.fields.count()); + return S.intInRange(tag_ty, int, enum_full.fields.count(), target); } else { - return enum_full.values.containsContext(int, .{ .ty = tag_ty }); + return enum_full.values.containsContext(int, .{ + .ty = tag_ty, + .target = target, + }); } }, .enum_numbered => { const enum_obj = ty.castTag(.enum_numbered).?.data; const tag_ty = enum_obj.tag_ty; if (enum_obj.values.count() == 0) { - return S.intInRange(tag_ty, int, enum_obj.fields.count()); + return S.intInRange(tag_ty, int, enum_obj.fields.count(), target); } else { - return enum_obj.values.containsContext(int, .{ .ty = tag_ty }); + return enum_obj.values.containsContext(int, .{ + .ty = tag_ty, + .target = target, + }); } }, .enum_simple => { @@ -5058,7 +5278,7 @@ pub const Type = extern union { .data = bits, }; const tag_ty = Type.initPayload(&buffer.base); - return S.intInRange(tag_ty, int, fields_len); + return S.intInRange(tag_ty, int, fields_len, target); }, .atomic_order, .atomic_rmw_op, @@ -5070,7 +5290,7 @@ pub const Type = extern union { .prefetch_options, .export_options, .extern_options, - => @panic("TODO resolve std.builtin types"), + => unreachable, else => unreachable, } @@ -5620,7 +5840,7 @@ pub const Type = extern union { d.bit_offset == 0 and d.host_size == 0 and !d.@"allowzero" and !d.@"volatile") { if (d.sentinel) |sent| { - if (!d.mutable and d.pointee_type.eql(Type.u8)) { + if (!d.mutable and d.pointee_type.eql(Type.u8, target)) { switch (d.size) { .Slice => { if (sent.compareWithZero(.eq)) { @@ -5635,7 +5855,7 @@ pub const Type = extern union { else => {}, } } - } else if (!d.mutable and d.pointee_type.eql(Type.u8)) { + } else if (!d.mutable and d.pointee_type.eql(Type.u8, target)) { switch (d.size) { .Slice => return Type.initTag(.const_slice_u8), .Many => return Type.initTag(.manyptr_const_u8), @@ -5669,10 +5889,11 @@ pub const Type = extern union { len: u64, sent: ?Value, elem_type: Type, + target: Target, ) Allocator.Error!Type { - if (elem_type.eql(Type.u8)) { + if (elem_type.eql(Type.u8, target)) { if (sent) |some| { - if (some.eql(Value.zero, elem_type)) { + if (some.eql(Value.zero, elem_type, target)) { return Tag.array_u8_sentinel_0.create(arena, len); } } else { @@ -5715,6 +5936,25 @@ pub const Type = extern union { } } + pub fn errorUnion( + arena: Allocator, + error_set: Type, + payload: Type, + target: Target, + ) Allocator.Error!Type { + assert(error_set.zigTypeTag() == .ErrorSet); + if (error_set.eql(Type.@"anyerror", target) and + payload.eql(Type.void, target)) + { + return Type.initTag(.anyerror_void_error_union); + } + + return Type.Tag.error_union.create(arena, .{ + .error_set = error_set, + .payload = payload, + }); + } + pub fn smallestUnsignedBits(max: u64) u16 { if (max == 0) return 0; const base = std.math.log2(max); diff --git a/src/value.zig b/src/value.zig index 454b1d76a2..b54f296a24 100644 --- a/src/value.zig +++ b/src/value.zig @@ -8,6 +8,7 @@ const Target = std.Target; const Allocator = std.mem.Allocator; const Module = @import("Module.zig"); const Air = @import("Air.zig"); +const TypedValue = @import("TypedValue.zig"); /// This is the raw data, with no bookkeeping, no memory awareness, /// no de-duplication, and no type system awareness. @@ -175,6 +176,8 @@ pub const Value = extern union { /// and refers directly to the air. It will never be referenced by the air itself. /// TODO: This is probably a bad encoding, maybe put temp data in the sema instead. bound_fn, + /// The ABI alignment of the payload type. + lazy_align, pub const last_no_payload_tag = Tag.empty_array; pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; @@ -283,7 +286,10 @@ pub const Value = extern union { .enum_field_index => Payload.U32, - .ty => Payload.Ty, + .ty, + .lazy_align, + => Payload.Ty, + .int_type => Payload.IntType, .int_u64 => Payload.U64, .int_i64 => Payload.I64, @@ -453,7 +459,7 @@ pub const Value = extern union { .bound_fn, => unreachable, - .ty => { + .ty, .lazy_align => { const payload = self.castTag(.ty).?; const new_payload = try arena.create(Payload.Ty); new_payload.* = .{ @@ -608,7 +614,7 @@ pub const Value = extern union { @compileError("do not use format values directly; use either fmtDebug or fmtValue"); } - /// TODO this should become a debug dump() function. In order to print values in a meaningful way + /// This is a debug function. In order to print values in a meaningful way /// we also need access to the type. pub fn dump( start_val: Value, @@ -699,7 +705,12 @@ pub const Value = extern union { .the_only_possible_value => return out_stream.writeAll("(the only possible value)"), .bool_true => return out_stream.writeAll("true"), .bool_false => return out_stream.writeAll("false"), - .ty => return val.castTag(.ty).?.data.format("", options, out_stream), + .ty => return val.castTag(.ty).?.data.dump("", options, out_stream), + .lazy_align => { + try out_stream.writeAll("@alignOf("); + try val.castTag(.lazy_align).?.data.dump("", options, out_stream); + try out_stream.writeAll(")"); + }, .int_type => { const int_type = val.castTag(.int_type).?.data; return out_stream.print("{s}{d}", .{ @@ -778,15 +789,16 @@ pub const Value = extern union { return .{ .data = val }; } - const TypedValue = @import("TypedValue.zig"); - - pub fn fmtValue(val: Value, ty: Type) std.fmt.Formatter(TypedValue.format) { - return .{ .data = .{ .ty = ty, .val = val } }; + pub fn fmtValue(val: Value, ty: Type, target: Target) std.fmt.Formatter(TypedValue.format) { + return .{ .data = .{ + .tv = .{ .ty = ty, .val = val }, + .target = target, + } }; } /// Asserts that the value is representable as an array of bytes. /// Copies the value into a freshly allocated slice of memory, which is owned by the caller. - pub fn toAllocatedBytes(val: Value, ty: Type, allocator: Allocator) ![]u8 { + pub fn toAllocatedBytes(val: Value, ty: Type, allocator: Allocator, target: Target) ![]u8 { switch (val.tag()) { .bytes => { const bytes = val.castTag(.bytes).?.data; @@ -796,7 +808,7 @@ pub const Value = extern union { }, .enum_literal => return allocator.dupe(u8, val.castTag(.enum_literal).?.data), .repeated => { - const byte = @intCast(u8, val.castTag(.repeated).?.data.toUnsignedInt()); + const byte = @intCast(u8, val.castTag(.repeated).?.data.toUnsignedInt(target)); const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen())); std.mem.set(u8, result, byte); return result; @@ -804,23 +816,23 @@ pub const Value = extern union { .decl_ref => { const decl = val.castTag(.decl_ref).?.data; const decl_val = try decl.value(); - return decl_val.toAllocatedBytes(decl.ty, allocator); + return decl_val.toAllocatedBytes(decl.ty, allocator, target); }, .the_only_possible_value => return &[_]u8{}, .slice => { const slice = val.castTag(.slice).?.data; - return arrayToAllocatedBytes(slice.ptr, slice.len.toUnsignedInt(), allocator); + return arrayToAllocatedBytes(slice.ptr, slice.len.toUnsignedInt(target), allocator, target); }, - else => return arrayToAllocatedBytes(val, ty.arrayLen(), allocator), + else => return arrayToAllocatedBytes(val, ty.arrayLen(), allocator, target), } } - fn arrayToAllocatedBytes(val: Value, len: u64, allocator: Allocator) ![]u8 { + fn arrayToAllocatedBytes(val: Value, len: u64, allocator: Allocator, target: Target) ![]u8 { const result = try allocator.alloc(u8, @intCast(usize, len)); var elem_value_buf: ElemValueBuffer = undefined; for (result) |*elem, i| { const elem_val = val.elemValueBuffer(i, &elem_value_buf); - elem.* = @intCast(u8, elem_val.toUnsignedInt()); + elem.* = @intCast(u8, elem_val.toUnsignedInt(target)); } return result; } @@ -977,8 +989,8 @@ pub const Value = extern union { } /// Asserts the value is an integer. - pub fn toBigInt(self: Value, space: *BigIntSpace) BigIntConst { - switch (self.tag()) { + pub fn toBigInt(val: Value, space: *BigIntSpace, target: Target) BigIntConst { + switch (val.tag()) { .zero, .bool_false, .the_only_possible_value, // i0, u0 @@ -988,19 +1000,25 @@ pub const Value = extern union { .bool_true, => return BigIntMutable.init(&space.limbs, 1).toConst(), - .int_u64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_u64).?.data).toConst(), - .int_i64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_i64).?.data).toConst(), - .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt(), - .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt(), + .int_u64 => return BigIntMutable.init(&space.limbs, val.castTag(.int_u64).?.data).toConst(), + .int_i64 => return BigIntMutable.init(&space.limbs, val.castTag(.int_i64).?.data).toConst(), + .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt(), + .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt(), .undef => unreachable, + + .lazy_align => { + const x = val.castTag(.lazy_align).?.data.abiAlignment(target); + return BigIntMutable.init(&space.limbs, x).toConst(); + }, + else => unreachable, } } /// If the value fits in a u64, return it, otherwise null. /// Asserts not undefined. - pub fn getUnsignedInt(val: Value) ?u64 { + pub fn getUnsignedInt(val: Value, target: Target) ?u64 { switch (val.tag()) { .zero, .bool_false, @@ -1017,13 +1035,16 @@ pub const Value = extern union { .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(u64) catch null, .undef => unreachable, + + .lazy_align => return val.castTag(.lazy_align).?.data.abiAlignment(target), + else => return null, } } /// Asserts the value is an integer and it fits in a u64 - pub fn toUnsignedInt(val: Value) u64 { - return getUnsignedInt(val).?; + pub fn toUnsignedInt(val: Value, target: Target) u64 { + return getUnsignedInt(val, target).?; } /// Asserts the value is an integer and it fits in a i64 @@ -1066,7 +1087,7 @@ pub const Value = extern union { switch (ty.zigTypeTag()) { .Int => { var bigint_buffer: BigIntSpace = undefined; - const bigint = val.toBigInt(&bigint_buffer); + const bigint = val.toBigInt(&bigint_buffer, target); const bits = ty.intInfo(target).bits; const abi_size = @intCast(usize, ty.abiSize(target)); bigint.writeTwosComplement(buffer, bits, abi_size, target.cpu.arch.endian()); @@ -1075,7 +1096,7 @@ pub const Value = extern union { var enum_buffer: Payload.U64 = undefined; const int_val = val.enumToInt(ty, &enum_buffer); var bigint_buffer: BigIntSpace = undefined; - const bigint = int_val.toBigInt(&bigint_buffer); + const bigint = int_val.toBigInt(&bigint_buffer, target); const bits = ty.intInfo(target).bits; const abi_size = @intCast(usize, ty.abiSize(target)); bigint.writeTwosComplement(buffer, bits, abi_size, target.cpu.arch.endian()); @@ -1151,7 +1172,7 @@ pub const Value = extern union { 128 => bitcastFloatToBigInt(f128, val.toFloat(f128), &field_buf), else => unreachable, }, - .Int, .Bool => field_val.toBigInt(&field_space), + .Int, .Bool => field_val.toBigInt(&field_space, target), .Struct => packedStructToInt(field_val, field.ty, target, &field_buf), else => unreachable, }; @@ -1511,7 +1532,7 @@ pub const Value = extern union { const info = ty.intInfo(target); var buffer: Value.BigIntSpace = undefined; - const operand_bigint = val.toBigInt(&buffer); + const operand_bigint = val.toBigInt(&buffer, target); var limbs_buffer: [4]std.math.big.Limb = undefined; var result_bigint = BigIntMutable{ @@ -1532,7 +1553,7 @@ pub const Value = extern union { const info = ty.intInfo(target); var buffer: Value.BigIntSpace = undefined; - const operand_bigint = val.toBigInt(&buffer); + const operand_bigint = val.toBigInt(&buffer, target); const limbs = try arena.alloc( std.math.big.Limb, @@ -1553,7 +1574,7 @@ pub const Value = extern union { assert(info.bits % 8 == 0); var buffer: Value.BigIntSpace = undefined; - const operand_bigint = val.toBigInt(&buffer); + const operand_bigint = val.toBigInt(&buffer, target); const limbs = try arena.alloc( std.math.big.Limb, @@ -1597,7 +1618,7 @@ pub const Value = extern union { else => { var buffer: BigIntSpace = undefined; - return self.toBigInt(&buffer).bitCountTwosComp(); + return self.toBigInt(&buffer, target).bitCountTwosComp(); }, } } @@ -1624,6 +1645,17 @@ pub const Value = extern union { else => unreachable, }, + .lazy_align => { + const info = ty.intInfo(target); + const max_needed_bits = @as(u16, 16) + @boolToInt(info.signedness == .signed); + // If it is u16 or bigger we know the alignment fits without resolving it. + if (info.bits >= max_needed_bits) return true; + const x = self.castTag(.lazy_align).?.data.abiAlignment(target); + if (x == 0) return true; + const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); + return info.bits >= actual_needed_bits; + }, + .int_u64 => switch (ty.zigTypeTag()) { .Int => { const x = self.castTag(.int_u64).?.data; @@ -1643,7 +1675,7 @@ pub const Value = extern union { if (info.signedness == .unsigned and x < 0) return false; var buffer: BigIntSpace = undefined; - return self.toBigInt(&buffer).fitsInTwosComp(info.signedness, info.bits); + return self.toBigInt(&buffer, target).fitsInTwosComp(info.signedness, info.bits); }, .ComptimeInt => return true, else => unreachable, @@ -1765,6 +1797,15 @@ pub const Value = extern union { .int_big_positive => lhs.castTag(.int_big_positive).?.asBigInt().orderAgainstScalar(0), .int_big_negative => lhs.castTag(.int_big_negative).?.asBigInt().orderAgainstScalar(0), + .lazy_align => { + const ty = lhs.castTag(.lazy_align).?.data; + if (ty.hasRuntimeBitsIgnoreComptime()) { + return .gt; + } else { + return .eq; + } + }, + .float_16 => std.math.order(lhs.castTag(.float_16).?.data, 0), .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0), .float_64 => std.math.order(lhs.castTag(.float_64).?.data, 0), @@ -1776,7 +1817,7 @@ pub const Value = extern union { } /// Asserts the value is comparable. - pub fn order(lhs: Value, rhs: Value) std.math.Order { + pub fn order(lhs: Value, rhs: Value, target: Target) std.math.Order { const lhs_tag = lhs.tag(); const rhs_tag = rhs.tag(); const lhs_against_zero = lhs.orderAgainstZero(); @@ -1814,14 +1855,14 @@ pub const Value = extern union { var lhs_bigint_space: BigIntSpace = undefined; var rhs_bigint_space: BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_bigint_space); - const rhs_bigint = rhs.toBigInt(&rhs_bigint_space); + const lhs_bigint = lhs.toBigInt(&lhs_bigint_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_bigint_space, target); return lhs_bigint.order(rhs_bigint); } /// Asserts the value is comparable. Does not take a type parameter because it supports /// comparisons between heterogeneous types. - pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value) bool { + pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value, target: Target) bool { if (lhs.pointerDecl()) |lhs_decl| { if (rhs.pointerDecl()) |rhs_decl| { switch (op) { @@ -1843,39 +1884,39 @@ pub const Value = extern union { else => {}, } } - return order(lhs, rhs).compare(op); + return order(lhs, rhs, target).compare(op); } /// Asserts the values are comparable. Both operands have type `ty`. /// Vector results will be reduced with AND. - pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type) bool { + pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type, target: Target) bool { if (ty.zigTypeTag() == .Vector) { var i: usize = 0; while (i < ty.vectorLen()) : (i += 1) { - if (!compareScalar(lhs.indexVectorlike(i), op, rhs.indexVectorlike(i), ty.scalarType())) { + if (!compareScalar(lhs.indexVectorlike(i), op, rhs.indexVectorlike(i), ty.scalarType(), target)) { return false; } } return true; } - return compareScalar(lhs, op, rhs, ty); + return compareScalar(lhs, op, rhs, ty, target); } /// Asserts the values are comparable. Both operands have type `ty`. - pub fn compareScalar(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type) bool { + pub fn compareScalar(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type, target: Target) bool { return switch (op) { - .eq => lhs.eql(rhs, ty), - .neq => !lhs.eql(rhs, ty), - else => compareHetero(lhs, op, rhs), + .eq => lhs.eql(rhs, ty, target), + .neq => !lhs.eql(rhs, ty, target), + else => compareHetero(lhs, op, rhs, target), }; } /// Asserts the values are comparable vectors of type `ty`. - pub fn compareVector(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type, allocator: Allocator) !Value { + pub fn compareVector(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { assert(ty.zigTypeTag() == .Vector); const result_data = try allocator.alloc(Value, ty.vectorLen()); for (result_data) |*scalar, i| { - const res_bool = compareScalar(lhs.indexVectorlike(i), op, rhs.indexVectorlike(i), ty.scalarType()); + const res_bool = compareScalar(lhs.indexVectorlike(i), op, rhs.indexVectorlike(i), ty.scalarType(), target); scalar.* = if (res_bool) Value.@"true" else Value.@"false"; } return Value.Tag.aggregate.create(allocator, result_data); @@ -1899,12 +1940,12 @@ pub const Value = extern union { /// This function is used by hash maps and so treats floating-point NaNs as equal /// to each other, and not equal to other floating-point values. - pub fn eql(a: Value, b: Value, ty: Type) bool { + /// Similarly, it treats `undef` as a distinct value from all other values. + pub fn eql(a: Value, b: Value, ty: Type, target: Target) bool { const a_tag = a.tag(); const b_tag = b.tag(); - assert(a_tag != .undef); - assert(b_tag != .undef); if (a_tag == b_tag) switch (a_tag) { + .undef => return true, .void_value, .null_value, .the_only_possible_value, .empty_struct_value => return true, .enum_literal => { const a_name = a.castTag(.enum_literal).?.data; @@ -1920,31 +1961,31 @@ pub const Value = extern union { const a_payload = a.castTag(.opt_payload).?.data; const b_payload = b.castTag(.opt_payload).?.data; var buffer: Type.Payload.ElemType = undefined; - return eql(a_payload, b_payload, ty.optionalChild(&buffer)); + return eql(a_payload, b_payload, ty.optionalChild(&buffer), target); }, .slice => { const a_payload = a.castTag(.slice).?.data; const b_payload = b.castTag(.slice).?.data; - if (!eql(a_payload.len, b_payload.len, Type.usize)) return false; + if (!eql(a_payload.len, b_payload.len, Type.usize, target)) return false; var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; const ptr_ty = ty.slicePtrFieldType(&ptr_buf); - return eql(a_payload.ptr, b_payload.ptr, ptr_ty); + return eql(a_payload.ptr, b_payload.ptr, ptr_ty, target); }, .elem_ptr => { const a_payload = a.castTag(.elem_ptr).?.data; const b_payload = b.castTag(.elem_ptr).?.data; if (a_payload.index != b_payload.index) return false; - return eql(a_payload.array_ptr, b_payload.array_ptr, ty); + return eql(a_payload.array_ptr, b_payload.array_ptr, ty, target); }, .field_ptr => { const a_payload = a.castTag(.field_ptr).?.data; const b_payload = b.castTag(.field_ptr).?.data; if (a_payload.field_index != b_payload.field_index) return false; - return eql(a_payload.container_ptr, b_payload.container_ptr, ty); + return eql(a_payload.container_ptr, b_payload.container_ptr, ty, target); }, .@"error" => { const a_name = a.castTag(.@"error").?.data.name; @@ -1954,7 +1995,7 @@ pub const Value = extern union { .eu_payload => { const a_payload = a.castTag(.eu_payload).?.data; const b_payload = b.castTag(.eu_payload).?.data; - return eql(a_payload, b_payload, ty.errorUnionPayload()); + return eql(a_payload, b_payload, ty.errorUnionPayload(), target); }, .eu_payload_ptr => @panic("TODO: Implement more pointer eql cases"), .opt_payload_ptr => @panic("TODO: Implement more pointer eql cases"), @@ -1972,7 +2013,7 @@ pub const Value = extern union { const types = ty.tupleFields().types; assert(types.len == a_field_vals.len); for (types) |field_ty, i| { - if (!eql(a_field_vals[i], b_field_vals[i], field_ty)) return false; + if (!eql(a_field_vals[i], b_field_vals[i], field_ty, target)) return false; } return true; } @@ -1981,7 +2022,7 @@ pub const Value = extern union { const fields = ty.structFields().values(); assert(fields.len == a_field_vals.len); for (fields) |field, i| { - if (!eql(a_field_vals[i], b_field_vals[i], field.ty)) return false; + if (!eql(a_field_vals[i], b_field_vals[i], field.ty, target)) return false; } return true; } @@ -1990,7 +2031,7 @@ pub const Value = extern union { for (a_field_vals) |a_elem, i| { const b_elem = b_field_vals[i]; - if (!eql(a_elem, b_elem, elem_ty)) return false; + if (!eql(a_elem, b_elem, elem_ty, target)) return false; } return true; }, @@ -2005,17 +2046,19 @@ pub const Value = extern union { }, .Auto => { const tag_ty = ty.unionTagTypeHypothetical(); - if (!a_union.tag.eql(b_union.tag, tag_ty)) { + if (!a_union.tag.eql(b_union.tag, tag_ty, target)) { return false; } - const active_field_ty = ty.unionFieldType(a_union.tag); - return a_union.val.eql(b_union.val, active_field_ty); + const active_field_ty = ty.unionFieldType(a_union.tag, target); + return a_union.val.eql(b_union.val, active_field_ty, target); }, } }, else => {}, } else if (a_tag == .null_value or b_tag == .null_value) { return false; + } else if (a_tag == .undef or b_tag == .undef) { + return false; } if (a.pointerDecl()) |a_decl| { @@ -2034,7 +2077,7 @@ pub const Value = extern union { var buf_b: ToTypeBuffer = undefined; const a_type = a.toType(&buf_a); const b_type = b.toType(&buf_b); - return a_type.eql(b_type); + return a_type.eql(b_type, target); }, .Enum => { var buf_a: Payload.U64 = undefined; @@ -2043,7 +2086,7 @@ pub const Value = extern union { const b_val = b.enumToInt(ty, &buf_b); var buf_ty: Type.Payload.Bits = undefined; const int_ty = ty.intTagType(&buf_ty); - return eql(a_val, b_val, int_ty); + return eql(a_val, b_val, int_ty, target); }, .Array, .Vector => { const len = ty.arrayLen(); @@ -2054,7 +2097,7 @@ pub const Value = extern union { while (i < len) : (i += 1) { const a_elem = elemValueBuffer(a, i, &a_buf); const b_elem = elemValueBuffer(b, i, &b_buf); - if (!eql(a_elem, b_elem, elem_ty)) return false; + if (!eql(a_elem, b_elem, elem_ty, target)) return false; } return true; }, @@ -2070,15 +2113,15 @@ pub const Value = extern union { if (a_nan or b_nan) { return a_nan and b_nan; } - return order(a, b).compare(.eq); + return order(a, b, target).compare(.eq); }, - else => return order(a, b).compare(.eq), + else => return order(a, b, target).compare(.eq), } } /// This function is used by hash maps and so treats floating-point NaNs as equal /// to each other, and not equal to other floating-point values. - pub fn hash(val: Value, ty: Type, hasher: *std.hash.Wyhash) void { + pub fn hash(val: Value, ty: Type, hasher: *std.hash.Wyhash, target: Target) void { const zig_ty_tag = ty.zigTypeTag(); std.hash.autoHash(hasher, zig_ty_tag); if (val.isUndef()) return; @@ -2095,7 +2138,7 @@ pub const Value = extern union { .Type => { var buf: ToTypeBuffer = undefined; - return val.toType(&buf).hashWithHasher(hasher); + return val.toType(&buf).hashWithHasher(hasher, target); }, .Float, .ComptimeFloat => { // Normalize the float here because this hash must match eql semantics. @@ -2116,11 +2159,11 @@ pub const Value = extern union { const slice = val.castTag(.slice).?.data; var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; const ptr_ty = ty.slicePtrFieldType(&ptr_buf); - hash(slice.ptr, ptr_ty, hasher); - hash(slice.len, Type.usize, hasher); + hash(slice.ptr, ptr_ty, hasher, target); + hash(slice.len, Type.usize, hasher, target); }, - else => return hashPtr(val, hasher), + else => return hashPtr(val, hasher, target), }, .Array, .Vector => { const len = ty.arrayLen(); @@ -2129,14 +2172,14 @@ pub const Value = extern union { var elem_value_buf: ElemValueBuffer = undefined; while (index < len) : (index += 1) { const elem_val = val.elemValueBuffer(index, &elem_value_buf); - elem_val.hash(elem_ty, hasher); + elem_val.hash(elem_ty, hasher, target); } }, .Struct => { if (ty.isTupleOrAnonStruct()) { const fields = ty.tupleFields(); for (fields.values) |field_val, i| { - field_val.hash(fields.types[i], hasher); + field_val.hash(fields.types[i], hasher, target); } return; } @@ -2145,13 +2188,13 @@ pub const Value = extern union { switch (val.tag()) { .empty_struct_value => { for (fields) |field| { - field.default_val.hash(field.ty, hasher); + field.default_val.hash(field.ty, hasher, target); } }, .aggregate => { const field_values = val.castTag(.aggregate).?.data; for (field_values) |field_val, i| { - field_val.hash(fields[i].ty, hasher); + field_val.hash(fields[i].ty, hasher, target); } }, else => unreachable, @@ -2163,7 +2206,7 @@ pub const Value = extern union { const sub_val = payload.data; var buffer: Type.Payload.ElemType = undefined; const sub_ty = ty.optionalChild(&buffer); - sub_val.hash(sub_ty, hasher); + sub_val.hash(sub_ty, hasher, target); } else { std.hash.autoHash(hasher, false); // non-null } @@ -2172,14 +2215,14 @@ pub const Value = extern union { if (val.tag() == .@"error") { std.hash.autoHash(hasher, false); // error const sub_ty = ty.errorUnionSet(); - val.hash(sub_ty, hasher); + val.hash(sub_ty, hasher, target); return; } if (val.castTag(.eu_payload)) |payload| { std.hash.autoHash(hasher, true); // payload const sub_ty = ty.errorUnionPayload(); - payload.data.hash(sub_ty, hasher); + payload.data.hash(sub_ty, hasher, target); return; } else unreachable; }, @@ -2192,15 +2235,15 @@ pub const Value = extern union { .Enum => { var enum_space: Payload.U64 = undefined; const int_val = val.enumToInt(ty, &enum_space); - hashInt(int_val, hasher); + hashInt(int_val, hasher, target); }, .Union => { const union_obj = val.cast(Payload.Union).?.data; if (ty.unionTagType()) |tag_ty| { - union_obj.tag.hash(tag_ty, hasher); + union_obj.tag.hash(tag_ty, hasher, target); } - const active_field_ty = ty.unionFieldType(union_obj.tag); - union_obj.val.hash(active_field_ty, hasher); + const active_field_ty = ty.unionFieldType(union_obj.tag, target); + union_obj.val.hash(active_field_ty, hasher, target); }, .Fn => { const func: *Module.Fn = val.castTag(.function).?.data; @@ -2225,28 +2268,30 @@ pub const Value = extern union { pub const ArrayHashContext = struct { ty: Type, + target: Target, pub fn hash(self: @This(), val: Value) u32 { - const other_context: HashContext = .{ .ty = self.ty }; + const other_context: HashContext = .{ .ty = self.ty, .target = self.target }; return @truncate(u32, other_context.hash(val)); } pub fn eql(self: @This(), a: Value, b: Value, b_index: usize) bool { _ = b_index; - return a.eql(b, self.ty); + return a.eql(b, self.ty, self.target); } }; pub const HashContext = struct { ty: Type, + target: Target, pub fn hash(self: @This(), val: Value) u64 { var hasher = std.hash.Wyhash.init(0); - val.hash(self.ty, &hasher); + val.hash(self.ty, &hasher, self.target); return hasher.final(); } pub fn eql(self: @This(), a: Value, b: Value) bool { - return a.eql(b, self.ty); + return a.eql(b, self.ty, self.target); } }; @@ -2296,16 +2341,16 @@ pub const Value = extern union { }; } - fn hashInt(int_val: Value, hasher: *std.hash.Wyhash) void { + fn hashInt(int_val: Value, hasher: *std.hash.Wyhash, target: Target) void { var buffer: BigIntSpace = undefined; - const big = int_val.toBigInt(&buffer); + const big = int_val.toBigInt(&buffer, target); std.hash.autoHash(hasher, big.positive); for (big.limbs) |limb| { std.hash.autoHash(hasher, limb); } } - fn hashPtr(ptr_val: Value, hasher: *std.hash.Wyhash) void { + fn hashPtr(ptr_val: Value, hasher: *std.hash.Wyhash, target: Target) void { switch (ptr_val.tag()) { .decl_ref, .decl_ref_mut, @@ -2319,25 +2364,25 @@ pub const Value = extern union { .elem_ptr => { const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; - hashPtr(elem_ptr.array_ptr, hasher); + hashPtr(elem_ptr.array_ptr, hasher, target); std.hash.autoHash(hasher, Value.Tag.elem_ptr); std.hash.autoHash(hasher, elem_ptr.index); }, .field_ptr => { const field_ptr = ptr_val.castTag(.field_ptr).?.data; std.hash.autoHash(hasher, Value.Tag.field_ptr); - hashPtr(field_ptr.container_ptr, hasher); + hashPtr(field_ptr.container_ptr, hasher, target); std.hash.autoHash(hasher, field_ptr.field_index); }, .eu_payload_ptr => { const err_union_ptr = ptr_val.castTag(.eu_payload_ptr).?.data; std.hash.autoHash(hasher, Value.Tag.eu_payload_ptr); - hashPtr(err_union_ptr.container_ptr, hasher); + hashPtr(err_union_ptr.container_ptr, hasher, target); }, .opt_payload_ptr => { const opt_ptr = ptr_val.castTag(.opt_payload_ptr).?.data; std.hash.autoHash(hasher, Value.Tag.opt_payload_ptr); - hashPtr(opt_ptr.container_ptr, hasher); + hashPtr(opt_ptr.container_ptr, hasher, target); }, .zero, @@ -2349,7 +2394,7 @@ pub const Value = extern union { .bool_false, .bool_true, .the_only_possible_value, - => return hashInt(ptr_val, hasher), + => return hashInt(ptr_val, hasher, target), else => unreachable, } @@ -2411,9 +2456,9 @@ pub const Value = extern union { }; } - pub fn sliceLen(val: Value) u64 { + pub fn sliceLen(val: Value, target: Target) u64 { return switch (val.tag()) { - .slice => val.castTag(.slice).?.data.len.toUnsignedInt(), + .slice => val.castTag(.slice).?.data.len.toUnsignedInt(target), .decl_ref => { const decl = val.castTag(.decl_ref).?.data; if (decl.ty.zigTypeTag() == .Array) { @@ -2561,7 +2606,7 @@ pub const Value = extern union { } /// Returns a pointer to the element value at the index. - pub fn elemPtr(val: Value, ty: Type, arena: Allocator, index: usize) Allocator.Error!Value { + pub fn elemPtr(val: Value, ty: Type, arena: Allocator, index: usize, target: Target) Allocator.Error!Value { const elem_ty = ty.elemType2(); const ptr_val = switch (val.tag()) { .slice => val.castTag(.slice).?.data.ptr, @@ -2570,7 +2615,7 @@ pub const Value = extern union { if (ptr_val.tag() == .elem_ptr) { const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; - if (elem_ptr.elem_ty.eql(elem_ty)) { + if (elem_ptr.elem_ty.eql(elem_ty, target)) { return Tag.elem_ptr.create(arena, .{ .array_ptr = elem_ptr.array_ptr, .elem_ty = elem_ptr.elem_ty, @@ -2821,8 +2866,8 @@ pub const Value = extern union { var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const rhs_bigint = rhs.toBigInt(&rhs_space); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_space, target); const limbs = try arena.alloc( std.math.big.Limb, std.math.big.int.calcTwosCompLimbCount(info.bits), @@ -2865,7 +2910,7 @@ pub const Value = extern union { if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); if (ty.zigTypeTag() == .ComptimeInt) { - return intAdd(lhs, rhs, ty, arena); + return intAdd(lhs, rhs, ty, arena, target); } if (ty.isAnyFloat()) { @@ -2925,8 +2970,8 @@ pub const Value = extern union { var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const rhs_bigint = rhs.toBigInt(&rhs_space); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_space, target); const limbs = try arena.alloc( std.math.big.Limb, std.math.big.int.calcTwosCompLimbCount(info.bits), @@ -2947,8 +2992,8 @@ pub const Value = extern union { var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const rhs_bigint = rhs.toBigInt(&rhs_space); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_space, target); const limbs = try arena.alloc( std.math.big.Limb, std.math.big.int.calcTwosCompLimbCount(info.bits), @@ -2991,7 +3036,7 @@ pub const Value = extern union { if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); if (ty.zigTypeTag() == .ComptimeInt) { - return intSub(lhs, rhs, ty, arena); + return intSub(lhs, rhs, ty, arena, target); } if (ty.isAnyFloat()) { @@ -3035,8 +3080,8 @@ pub const Value = extern union { var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const rhs_bigint = rhs.toBigInt(&rhs_space); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_space, target); const limbs = try arena.alloc( std.math.big.Limb, std.math.big.int.calcTwosCompLimbCount(info.bits), @@ -3057,8 +3102,8 @@ pub const Value = extern union { var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const rhs_bigint = rhs.toBigInt(&rhs_space); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_space, target); const limbs = try arena.alloc( std.math.big.Limb, lhs_bigint.limbs.len + rhs_bigint.limbs.len, @@ -3110,7 +3155,7 @@ pub const Value = extern union { if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); if (ty.zigTypeTag() == .ComptimeInt) { - return intMul(lhs, rhs, ty, arena); + return intMul(lhs, rhs, ty, arena, target); } if (ty.isAnyFloat()) { @@ -3154,8 +3199,8 @@ pub const Value = extern union { var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const rhs_bigint = rhs.toBigInt(&rhs_space); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_space, target); const limbs = try arena.alloc( std.math.big.Limb, std.math.max( @@ -3175,24 +3220,24 @@ pub const Value = extern union { } /// Supports both floats and ints; handles undefined. - pub fn numberMax(lhs: Value, rhs: Value) Value { + pub fn numberMax(lhs: Value, rhs: Value, target: Target) Value { if (lhs.isUndef() or rhs.isUndef()) return undef; if (lhs.isNan()) return rhs; if (rhs.isNan()) return lhs; - return switch (order(lhs, rhs)) { + return switch (order(lhs, rhs, target)) { .lt => rhs, .gt, .eq => lhs, }; } /// Supports both floats and ints; handles undefined. - pub fn numberMin(lhs: Value, rhs: Value) Value { + pub fn numberMin(lhs: Value, rhs: Value, target: Target) Value { if (lhs.isUndef() or rhs.isUndef()) return undef; if (lhs.isNan()) return rhs; if (rhs.isNan()) return lhs; - return switch (order(lhs, rhs)) { + return switch (order(lhs, rhs, target)) { .lt => lhs, .gt, .eq => rhs, }; @@ -3224,7 +3269,7 @@ pub const Value = extern union { // TODO is this a performance issue? maybe we should try the operation without // resorting to BigInt first. var val_space: Value.BigIntSpace = undefined; - const val_bigint = val.toBigInt(&val_space); + const val_bigint = val.toBigInt(&val_space, target); const limbs = try arena.alloc( std.math.big.Limb, std.math.big.int.calcTwosCompLimbCount(info.bits), @@ -3236,27 +3281,27 @@ pub const Value = extern union { } /// operands must be (vectors of) integers; handles undefined scalars. - pub fn bitwiseAnd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value { + pub fn bitwiseAnd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try allocator.alloc(Value, ty.vectorLen()); for (result_data) |*scalar, i| { - scalar.* = try bitwiseAndScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator); + scalar.* = try bitwiseAndScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target); } return Value.Tag.aggregate.create(allocator, result_data); } - return bitwiseAndScalar(lhs, rhs, allocator); + return bitwiseAndScalar(lhs, rhs, allocator, target); } /// operands must be integers; handles undefined. - pub fn bitwiseAndScalar(lhs: Value, rhs: Value, arena: Allocator) !Value { + pub fn bitwiseAndScalar(lhs: Value, rhs: Value, arena: Allocator, target: Target) !Value { if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); // TODO is this a performance issue? maybe we should try the operation without // resorting to BigInt first. var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const rhs_bigint = rhs.toBigInt(&rhs_space); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_space, target); const limbs = try arena.alloc( std.math.big.Limb, // + 1 for negatives @@ -3283,38 +3328,38 @@ pub const Value = extern union { pub fn bitwiseNandScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, target: Target) !Value { if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); - const anded = try bitwiseAnd(lhs, rhs, ty, arena); + const anded = try bitwiseAnd(lhs, rhs, ty, arena, target); const all_ones = if (ty.isSignedInt()) try Value.Tag.int_i64.create(arena, -1) else try ty.maxInt(arena, target); - return bitwiseXor(anded, all_ones, ty, arena); + return bitwiseXor(anded, all_ones, ty, arena, target); } /// operands must be (vectors of) integers; handles undefined scalars. - pub fn bitwiseOr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value { + pub fn bitwiseOr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try allocator.alloc(Value, ty.vectorLen()); for (result_data) |*scalar, i| { - scalar.* = try bitwiseOrScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator); + scalar.* = try bitwiseOrScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target); } return Value.Tag.aggregate.create(allocator, result_data); } - return bitwiseOrScalar(lhs, rhs, allocator); + return bitwiseOrScalar(lhs, rhs, allocator, target); } /// operands must be integers; handles undefined. - pub fn bitwiseOrScalar(lhs: Value, rhs: Value, arena: Allocator) !Value { + pub fn bitwiseOrScalar(lhs: Value, rhs: Value, arena: Allocator, target: Target) !Value { if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); // TODO is this a performance issue? maybe we should try the operation without // resorting to BigInt first. var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const rhs_bigint = rhs.toBigInt(&rhs_space); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_space, target); const limbs = try arena.alloc( std.math.big.Limb, std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len), @@ -3325,27 +3370,27 @@ pub const Value = extern union { } /// operands must be (vectors of) integers; handles undefined scalars. - pub fn bitwiseXor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value { + pub fn bitwiseXor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try allocator.alloc(Value, ty.vectorLen()); for (result_data) |*scalar, i| { - scalar.* = try bitwiseXorScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator); + scalar.* = try bitwiseXorScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target); } return Value.Tag.aggregate.create(allocator, result_data); } - return bitwiseXorScalar(lhs, rhs, allocator); + return bitwiseXorScalar(lhs, rhs, allocator, target); } /// operands must be integers; handles undefined. - pub fn bitwiseXorScalar(lhs: Value, rhs: Value, arena: Allocator) !Value { + pub fn bitwiseXorScalar(lhs: Value, rhs: Value, arena: Allocator, target: Target) !Value { if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); // TODO is this a performance issue? maybe we should try the operation without // resorting to BigInt first. var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const rhs_bigint = rhs.toBigInt(&rhs_space); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_space, target); const limbs = try arena.alloc( std.math.big.Limb, // + 1 for negatives @@ -3356,24 +3401,24 @@ pub const Value = extern union { return fromBigInt(arena, result_bigint.toConst()); } - pub fn intAdd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value { + pub fn intAdd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try allocator.alloc(Value, ty.vectorLen()); for (result_data) |*scalar, i| { - scalar.* = try intAddScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator); + scalar.* = try intAddScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target); } return Value.Tag.aggregate.create(allocator, result_data); } - return intAddScalar(lhs, rhs, allocator); + return intAddScalar(lhs, rhs, allocator, target); } - pub fn intAddScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value { + pub fn intAddScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { // TODO is this a performance issue? maybe we should try the operation without // resorting to BigInt first. var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const rhs_bigint = rhs.toBigInt(&rhs_space); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_space, target); const limbs = try allocator.alloc( std.math.big.Limb, std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, @@ -3383,24 +3428,24 @@ pub const Value = extern union { return fromBigInt(allocator, result_bigint.toConst()); } - pub fn intSub(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value { + pub fn intSub(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try allocator.alloc(Value, ty.vectorLen()); for (result_data) |*scalar, i| { - scalar.* = try intSubScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator); + scalar.* = try intSubScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target); } return Value.Tag.aggregate.create(allocator, result_data); } - return intSubScalar(lhs, rhs, allocator); + return intSubScalar(lhs, rhs, allocator, target); } - pub fn intSubScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value { + pub fn intSubScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { // TODO is this a performance issue? maybe we should try the operation without // resorting to BigInt first. var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const rhs_bigint = rhs.toBigInt(&rhs_space); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_space, target); const limbs = try allocator.alloc( std.math.big.Limb, std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, @@ -3410,24 +3455,24 @@ pub const Value = extern union { return fromBigInt(allocator, result_bigint.toConst()); } - pub fn intDiv(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value { + pub fn intDiv(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try allocator.alloc(Value, ty.vectorLen()); for (result_data) |*scalar, i| { - scalar.* = try intDivScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator); + scalar.* = try intDivScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target); } return Value.Tag.aggregate.create(allocator, result_data); } - return intDivScalar(lhs, rhs, allocator); + return intDivScalar(lhs, rhs, allocator, target); } - pub fn intDivScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value { + pub fn intDivScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { // TODO is this a performance issue? maybe we should try the operation without // resorting to BigInt first. var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const rhs_bigint = rhs.toBigInt(&rhs_space); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_space, target); const limbs_q = try allocator.alloc( std.math.big.Limb, lhs_bigint.limbs.len, @@ -3446,24 +3491,24 @@ pub const Value = extern union { return fromBigInt(allocator, result_q.toConst()); } - pub fn intDivFloor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value { + pub fn intDivFloor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try allocator.alloc(Value, ty.vectorLen()); for (result_data) |*scalar, i| { - scalar.* = try intDivFloorScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator); + scalar.* = try intDivFloorScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target); } return Value.Tag.aggregate.create(allocator, result_data); } - return intDivFloorScalar(lhs, rhs, allocator); + return intDivFloorScalar(lhs, rhs, allocator, target); } - pub fn intDivFloorScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value { + pub fn intDivFloorScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { // TODO is this a performance issue? maybe we should try the operation without // resorting to BigInt first. var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const rhs_bigint = rhs.toBigInt(&rhs_space); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_space, target); const limbs_q = try allocator.alloc( std.math.big.Limb, lhs_bigint.limbs.len, @@ -3482,24 +3527,24 @@ pub const Value = extern union { return fromBigInt(allocator, result_q.toConst()); } - pub fn intRem(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value { + pub fn intRem(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try allocator.alloc(Value, ty.vectorLen()); for (result_data) |*scalar, i| { - scalar.* = try intRemScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator); + scalar.* = try intRemScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target); } return Value.Tag.aggregate.create(allocator, result_data); } - return intRemScalar(lhs, rhs, allocator); + return intRemScalar(lhs, rhs, allocator, target); } - pub fn intRemScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value { + pub fn intRemScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { // TODO is this a performance issue? maybe we should try the operation without // resorting to BigInt first. var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const rhs_bigint = rhs.toBigInt(&rhs_space); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_space, target); const limbs_q = try allocator.alloc( std.math.big.Limb, lhs_bigint.limbs.len, @@ -3520,24 +3565,24 @@ pub const Value = extern union { return fromBigInt(allocator, result_r.toConst()); } - pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value { + pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try allocator.alloc(Value, ty.vectorLen()); for (result_data) |*scalar, i| { - scalar.* = try intModScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator); + scalar.* = try intModScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target); } return Value.Tag.aggregate.create(allocator, result_data); } - return intModScalar(lhs, rhs, allocator); + return intModScalar(lhs, rhs, allocator, target); } - pub fn intModScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value { + pub fn intModScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { // TODO is this a performance issue? maybe we should try the operation without // resorting to BigInt first. var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const rhs_bigint = rhs.toBigInt(&rhs_space); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_space, target); const limbs_q = try allocator.alloc( std.math.big.Limb, lhs_bigint.limbs.len, @@ -3658,24 +3703,24 @@ pub const Value = extern union { } } - pub fn intMul(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value { + pub fn intMul(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try allocator.alloc(Value, ty.vectorLen()); for (result_data) |*scalar, i| { - scalar.* = try intMulScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator); + scalar.* = try intMulScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target); } return Value.Tag.aggregate.create(allocator, result_data); } - return intMulScalar(lhs, rhs, allocator); + return intMulScalar(lhs, rhs, allocator, target); } - pub fn intMulScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value { + pub fn intMulScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { // TODO is this a performance issue? maybe we should try the operation without // resorting to BigInt first. var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const rhs_bigint = rhs.toBigInt(&rhs_space); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const rhs_bigint = rhs.toBigInt(&rhs_space, target); const limbs = try allocator.alloc( std.math.big.Limb, lhs_bigint.limbs.len + rhs_bigint.limbs.len, @@ -3690,34 +3735,41 @@ pub const Value = extern union { return fromBigInt(allocator, result_bigint.toConst()); } - pub fn intTrunc(val: Value, ty: Type, allocator: Allocator, signedness: std.builtin.Signedness, bits: u16) !Value { + pub fn intTrunc(val: Value, ty: Type, allocator: Allocator, signedness: std.builtin.Signedness, bits: u16, target: Target) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try allocator.alloc(Value, ty.vectorLen()); for (result_data) |*scalar, i| { - scalar.* = try intTruncScalar(val.indexVectorlike(i), allocator, signedness, bits); + scalar.* = try intTruncScalar(val.indexVectorlike(i), allocator, signedness, bits, target); } return Value.Tag.aggregate.create(allocator, result_data); } - return intTruncScalar(val, allocator, signedness, bits); + return intTruncScalar(val, allocator, signedness, bits, target); } /// This variant may vectorize on `bits`. Asserts that `bits` is a (vector of) `u16`. - pub fn intTruncBitsAsValue(val: Value, ty: Type, allocator: Allocator, signedness: std.builtin.Signedness, bits: Value) !Value { + pub fn intTruncBitsAsValue( + val: Value, + ty: Type, + allocator: Allocator, + signedness: std.builtin.Signedness, + bits: Value, + target: Target, + ) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try allocator.alloc(Value, ty.vectorLen()); for (result_data) |*scalar, i| { - scalar.* = try intTruncScalar(val.indexVectorlike(i), allocator, signedness, @intCast(u16, bits.indexVectorlike(i).toUnsignedInt())); + scalar.* = try intTruncScalar(val.indexVectorlike(i), allocator, signedness, @intCast(u16, bits.indexVectorlike(i).toUnsignedInt(target)), target); } return Value.Tag.aggregate.create(allocator, result_data); } - return intTruncScalar(val, allocator, signedness, @intCast(u16, bits.toUnsignedInt())); + return intTruncScalar(val, allocator, signedness, @intCast(u16, bits.toUnsignedInt(target)), target); } - pub fn intTruncScalar(val: Value, allocator: Allocator, signedness: std.builtin.Signedness, bits: u16) !Value { + pub fn intTruncScalar(val: Value, allocator: Allocator, signedness: std.builtin.Signedness, bits: u16, target: Target) !Value { if (bits == 0) return Value.zero; var val_space: Value.BigIntSpace = undefined; - const val_bigint = val.toBigInt(&val_space); + const val_bigint = val.toBigInt(&val_space, target); const limbs = try allocator.alloc( std.math.big.Limb, @@ -3729,23 +3781,23 @@ pub const Value = extern union { return fromBigInt(allocator, result_bigint.toConst()); } - pub fn shl(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value { + pub fn shl(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try allocator.alloc(Value, ty.vectorLen()); for (result_data) |*scalar, i| { - scalar.* = try shlScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator); + scalar.* = try shlScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target); } return Value.Tag.aggregate.create(allocator, result_data); } - return shlScalar(lhs, rhs, allocator); + return shlScalar(lhs, rhs, allocator, target); } - pub fn shlScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value { + pub fn shlScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { // TODO is this a performance issue? maybe we should try the operation without // resorting to BigInt first. var lhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const shift = @intCast(usize, rhs.toUnsignedInt()); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const shift = @intCast(usize, rhs.toUnsignedInt(target)); const limbs = try allocator.alloc( std.math.big.Limb, lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1, @@ -3768,8 +3820,8 @@ pub const Value = extern union { ) !OverflowArithmeticResult { const info = ty.intInfo(target); var lhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const shift = @intCast(usize, rhs.toUnsignedInt()); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const shift = @intCast(usize, rhs.toUnsignedInt(target)); const limbs = try allocator.alloc( std.math.big.Limb, lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1, @@ -3819,8 +3871,8 @@ pub const Value = extern union { const info = ty.intInfo(target); var lhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const shift = @intCast(usize, rhs.toUnsignedInt()); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const shift = @intCast(usize, rhs.toUnsignedInt(target)); const limbs = try arena.alloc( std.math.big.Limb, std.math.big.int.calcTwosCompLimbCount(info.bits), @@ -3858,29 +3910,29 @@ pub const Value = extern union { arena: Allocator, target: Target, ) !Value { - const shifted = try lhs.shl(rhs, ty, arena); + const shifted = try lhs.shl(rhs, ty, arena, target); const int_info = ty.intInfo(target); - const truncated = try shifted.intTrunc(ty, arena, int_info.signedness, int_info.bits); + const truncated = try shifted.intTrunc(ty, arena, int_info.signedness, int_info.bits, target); return truncated; } - pub fn shr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value { + pub fn shr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try allocator.alloc(Value, ty.vectorLen()); for (result_data) |*scalar, i| { - scalar.* = try shrScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator); + scalar.* = try shrScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target); } return Value.Tag.aggregate.create(allocator, result_data); } - return shrScalar(lhs, rhs, allocator); + return shrScalar(lhs, rhs, allocator, target); } - pub fn shrScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value { + pub fn shrScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { // TODO is this a performance issue? maybe we should try the operation without // resorting to BigInt first. var lhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space); - const shift = @intCast(usize, rhs.toUnsignedInt()); + const lhs_bigint = lhs.toBigInt(&lhs_space, target); + const shift = @intCast(usize, rhs.toUnsignedInt(target)); const result_limbs = lhs_bigint.limbs.len -| (shift / (@sizeOf(std.math.big.Limb) * 8)); if (result_limbs == 0) { diff --git a/test/behavior.zig b/test/behavior.zig index d413529a50..29eadbf14f 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -125,6 +125,7 @@ test { _ = @import("behavior/src.zig"); _ = @import("behavior/struct.zig"); _ = @import("behavior/struct_contains_null_ptr_itself.zig"); + _ = @import("behavior/struct_contains_slice_of_itself.zig"); _ = @import("behavior/switch.zig"); _ = @import("behavior/switch_prong_err_enum.zig"); _ = @import("behavior/switch_prong_implicit_cast.zig"); @@ -179,6 +180,5 @@ test { _ = @import("behavior/bugs/6781.zig"); _ = @import("behavior/bugs/7027.zig"); _ = @import("behavior/select.zig"); - _ = @import("behavior/struct_contains_slice_of_itself.zig"); } } From 60d8c4739de14823c407245f01c9b7483f3b6e7f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 22 Mar 2022 15:42:09 -0700 Subject: [PATCH 2/3] Sema: introduce a mechanism in Value to resolve types This commit adds a new optional argument to several Value methods which provides the ability to resolve types if it comes to it. This prevents having duplicated logic inside both Sema and Value. With this commit, the "struct contains slice of itself" test is passing by exploiting the new lazy_align Value Tag. --- src/Module.zig | 6 ++ src/Sema.zig | 48 ++++++---- src/type.zig | 95 +++++++++++++------ src/value.zig | 63 ++++++++++-- .../struct_contains_slice_of_itself.zig | 9 ++ 5 files changed, 167 insertions(+), 54 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 4164c2659c..7b27546f52 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -177,6 +177,12 @@ const MonomorphedFuncsContext = struct { } }; +pub const WipAnalysis = struct { + sema: *Sema, + block: *Sema.Block, + src: Module.LazySrcLoc, +}; + pub const MemoizedCallSet = std.HashMapUnmanaged( MemoizedCall.Key, MemoizedCall.Result, diff --git a/src/Sema.zig b/src/Sema.zig index 5e344bb7d0..2428db5b0f 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1591,7 +1591,7 @@ fn resolveInt( const coerced = try sema.coerce(block, dest_ty, air_inst, src); const val = try sema.resolveConstValue(block, src, coerced); const target = sema.mod.getTarget(); - return val.toUnsignedInt(target); + return (try val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?; } // Returns a compile error if the value has tag `variable`. See `resolveInstValue` for @@ -9926,7 +9926,7 @@ fn analyzePtrArithmetic( const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(target)); // TODO I tried to put this check earlier but it the LLVM backend generate invalid instructinons if (offset_int == 0) return ptr; - if (ptr_val.getUnsignedInt(target)) |addr| { + if (try ptr_val.getUnsignedIntAdvanced(target, sema.kit(block, ptr_src))) |addr| { const ptr_child_ty = ptr_ty.childType(); const elem_ty = if (ptr_ty.isSinglePointer() and ptr_child_ty.zigTypeTag() == .Array) ptr_child_ty.childType() @@ -11863,6 +11863,8 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const elem_ty_src: LazySrcLoc = .unneeded; const inst_data = sema.code.instructions.items(.data)[inst].ptr_type; const extra = sema.code.extraData(Zir.Inst.PtrType, inst_data.payload_index); + const unresolved_elem_ty = try sema.resolveType(block, elem_ty_src, extra.data.elem_type); + const target = sema.mod.getTarget(); var extra_i = extra.end; @@ -11872,10 +11874,19 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air break :blk (try sema.resolveInstConst(block, .unneeded, ref)).val; } else null; - const abi_align = if (inst_data.flags.has_align) blk: { + const abi_align: u32 = if (inst_data.flags.has_align) blk: { const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); extra_i += 1; - const abi_align = try sema.resolveInt(block, .unneeded, ref, Type.u32); + const coerced = try sema.coerce(block, Type.u32, sema.resolveInst(ref), src); + const val = try sema.resolveConstValue(block, src, coerced); + // Check if this happens to be the lazy alignment of our element type, in + // which case we can make this 0 without resolving it. + if (val.castTag(.lazy_align)) |payload| { + if (payload.data.eql(unresolved_elem_ty, target)) { + break :blk 0; + } + } + const abi_align = (try val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?; break :blk @intCast(u32, abi_align); } else 0; @@ -11903,7 +11914,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air return sema.fail(block, src, "bit offset starts after end of host integer", .{}); } - const unresolved_elem_ty = try sema.resolveType(block, elem_ty_src, extra.data.elem_type); const elem_ty = if (abi_align == 0) unresolved_elem_ty else t: { @@ -11911,7 +11921,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air try sema.resolveTypeLayout(block, elem_ty_src, elem_ty); break :t elem_ty; }; - const target = sema.mod.getTarget(); const ty = try Type.ptr(sema.arena, target, .{ .pointee_type = elem_ty, .sentinel = sentinel, @@ -18390,15 +18399,15 @@ fn storePtrVal( operand_val: Value, operand_ty: Type, ) !void { - var kit = try beginComptimePtrMutation(sema, block, src, ptr_val); - try sema.checkComptimeVarStore(block, src, kit.decl_ref_mut); + var mut_kit = try beginComptimePtrMutation(sema, block, src, ptr_val); + try sema.checkComptimeVarStore(block, src, mut_kit.decl_ref_mut); - const bitcasted_val = try sema.bitCastVal(block, src, operand_val, operand_ty, kit.ty, 0); + const bitcasted_val = try sema.bitCastVal(block, src, operand_val, operand_ty, mut_kit.ty, 0); - const arena = kit.beginArena(sema.gpa); - defer kit.finishArena(); + const arena = mut_kit.beginArena(sema.gpa); + defer mut_kit.finishArena(); - kit.val.* = try bitcasted_val.copy(arena); + mut_kit.val.* = try bitcasted_val.copy(arena); } const ComptimePtrMutationKit = struct { @@ -19891,7 +19900,7 @@ fn cmpNumeric( return Air.Inst.Ref.bool_false; } } - if (Value.compareHetero(lhs_val, op, rhs_val, target)) { + if (try Value.compareHeteroAdvanced(lhs_val, op, rhs_val, target, sema.kit(block, src))) { return Air.Inst.Ref.bool_true; } else { return Air.Inst.Ref.bool_false; @@ -20758,7 +20767,7 @@ pub fn resolveFnTypes( } } -fn resolveTypeLayout( +pub fn resolveTypeLayout( sema: *Sema, block: *Block, src: LazySrcLoc, @@ -20929,7 +20938,7 @@ fn resolveUnionFully( union_obj.status = .fully_resolved; } -fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type { +pub fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type { switch (ty.tag()) { .@"struct" => { const struct_obj = ty.castTag(.@"struct").?.data; @@ -22209,7 +22218,9 @@ fn typePtrOrOptionalPtrTy( /// This function returns false negatives when structs and unions are having their /// field types resolved. /// TODO assert the return value matches `ty.comptimeOnly` -fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool { +/// TODO merge these implementations together with the "advanced"/sema_kit pattern seen +/// elsewhere in value.zig +pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool { return switch (ty.tag()) { .u1, .u8, @@ -22415,6 +22426,7 @@ fn typeAbiSize(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u64 { return ty.abiSize(target); } +/// TODO merge with Type.abiAlignmentAdvanced fn typeAbiAlignment(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u32 { try sema.resolveTypeLayout(block, src, ty); const target = sema.mod.getTarget(); @@ -22498,3 +22510,7 @@ fn anonStructFieldIndex( struct_ty.fmt(target), field_name, }); } + +fn kit(sema: *Sema, block: *Block, src: LazySrcLoc) Module.WipAnalysis { + return .{ .sema = sema, .block = block, .src = src }; +} diff --git a/src/type.zig b/src/type.zig index 0b49eac0a8..8668b36dca 100644 --- a/src/type.zig +++ b/src/type.zig @@ -1483,20 +1483,29 @@ pub const Type = extern union { @compileError("do not format types directly; use either ty.fmtDebug() or ty.fmt()"); } - pub fn fmt(ty: Type, target: Target) std.fmt.Formatter(TypedValue.format) { - var ty_payload: Value.Payload.Ty = .{ - .base = .{ .tag = .ty }, - .data = ty, - }; + pub fn fmt(ty: Type, target: Target) std.fmt.Formatter(format2) { return .{ .data = .{ - .tv = .{ - .ty = Type.type, - .val = Value.initPayload(&ty_payload.base), - }, + .ty = ty, .target = target, } }; } + const FormatContext = struct { + ty: Type, + target: Target, + }; + + fn format2( + ctx: FormatContext, + comptime unused_format_string: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + comptime assert(unused_format_string.len == 0); + _ = options; + return print(ctx.ty, writer, ctx.target); + } + pub fn fmtDebug(ty: Type) std.fmt.Formatter(dump) { return .{ .data = ty }; } @@ -2241,8 +2250,12 @@ pub const Type = extern union { /// * the type has only one possible value, making its ABI size 0. /// When `ignore_comptime_only` is true, then types that are comptime only /// may return false positives. - pub fn hasRuntimeBitsAdvanced(ty: Type, ignore_comptime_only: bool) bool { - return switch (ty.tag()) { + pub fn hasRuntimeBitsAdvanced( + ty: Type, + ignore_comptime_only: bool, + sema_kit: ?Module.WipAnalysis, + ) Module.CompileError!bool { + switch (ty.tag()) { .u1, .u8, .i8, @@ -2296,7 +2309,7 @@ pub const Type = extern union { .@"anyframe", .anyopaque, .@"opaque", - => true, + => return true, // These are false because they are comptime-only types. .single_const_pointer_to_comptime_int, @@ -2320,7 +2333,7 @@ pub const Type = extern union { .fn_void_no_args, .fn_naked_noreturn_no_args, .fn_ccc_void_no_args, - => false, + => return false, // These types have more than one possible value, so the result is the same as // asking whether they are comptime-only types. @@ -2337,20 +2350,34 @@ pub const Type = extern union { .const_slice, .mut_slice, .pointer, - => if (ignore_comptime_only) true else !comptimeOnly(ty), + => { + if (ignore_comptime_only) { + return true; + } else if (sema_kit) |sk| { + return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty)); + } else { + return !comptimeOnly(ty); + } + }, .@"struct" => { const struct_obj = ty.castTag(.@"struct").?.data; + if (sema_kit) |sk| { + _ = try sk.sema.typeRequiresComptime(sk.block, sk.src, ty); + } switch (struct_obj.requires_comptime) { .wip => unreachable, .yes => return false, .no => if (struct_obj.known_non_opv) return true, .unknown => {}, } + if (sema_kit) |sk| { + _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); + } assert(struct_obj.haveFieldTypes()); for (struct_obj.fields.values()) |value| { if (value.is_comptime) continue; - if (value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only)) + if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) return true; } else { return false; @@ -2368,14 +2395,17 @@ pub const Type = extern union { .enum_numbered, .enum_nonexhaustive => { var buffer: Payload.Bits = undefined; const int_tag_ty = ty.intTagType(&buffer); - return int_tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only); + return int_tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit); }, .@"union" => { const union_obj = ty.castTag(.@"union").?.data; + if (sema_kit) |sk| { + _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); + } assert(union_obj.haveFieldTypes()); for (union_obj.fields.values()) |value| { - if (value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only)) + if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) return true; } else { return false; @@ -2383,29 +2413,32 @@ pub const Type = extern union { }, .union_tagged => { const union_obj = ty.castTag(.union_tagged).?.data; - if (union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only)) { + if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) { return true; } + if (sema_kit) |sk| { + _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); + } assert(union_obj.haveFieldTypes()); for (union_obj.fields.values()) |value| { - if (value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only)) + if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) return true; } else { return false; } }, - .array, .vector => ty.arrayLen() != 0 and - ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only), - .array_u8 => ty.arrayLen() != 0, - .array_sentinel => ty.childType().hasRuntimeBitsAdvanced(ignore_comptime_only), + .array, .vector => return ty.arrayLen() != 0 and + try ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit), + .array_u8 => return ty.arrayLen() != 0, + .array_sentinel => return ty.childType().hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit), - .int_signed, .int_unsigned => ty.cast(Payload.Bits).?.data != 0, + .int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data != 0, .error_union => { const payload = ty.castTag(.error_union).?.data; - return payload.error_set.hasRuntimeBitsAdvanced(ignore_comptime_only) or - payload.payload.hasRuntimeBitsAdvanced(ignore_comptime_only); + return (try payload.error_set.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) or + (try payload.payload.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)); }, .tuple, .anon_struct => { @@ -2413,7 +2446,7 @@ pub const Type = extern union { for (tuple.types) |field_ty, i| { const val = tuple.values[i]; if (val.tag() != .unreachable_value) continue; // comptime field - if (field_ty.hasRuntimeBitsAdvanced(ignore_comptime_only)) return true; + if (try field_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) return true; } return false; }, @@ -2422,7 +2455,7 @@ pub const Type = extern union { .inferred_alloc_mut => unreachable, .var_args_param => unreachable, .generic_poison => unreachable, - }; + } } /// true if and only if the type has a well-defined memory layout @@ -2548,11 +2581,11 @@ pub const Type = extern union { } pub fn hasRuntimeBits(ty: Type) bool { - return hasRuntimeBitsAdvanced(ty, false); + return hasRuntimeBitsAdvanced(ty, false, null) catch unreachable; } pub fn hasRuntimeBitsIgnoreComptime(ty: Type) bool { - return hasRuntimeBitsAdvanced(ty, true); + return hasRuntimeBitsAdvanced(ty, true, null) catch unreachable; } pub fn isFnOrHasRuntimeBits(ty: Type) bool { @@ -4538,6 +4571,8 @@ pub const Type = extern union { /// During semantic analysis, instead call `Sema.typeRequiresComptime` which /// resolves field types rather than asserting they are already resolved. + /// TODO merge these implementations together with the "advanced" pattern seen + /// elsewhere in this file. pub fn comptimeOnly(ty: Type) bool { return switch (ty.tag()) { .u1, diff --git a/src/value.zig b/src/value.zig index b54f296a24..fb9a2f826a 100644 --- a/src/value.zig +++ b/src/value.zig @@ -9,6 +9,7 @@ const Allocator = std.mem.Allocator; const Module = @import("Module.zig"); const Air = @import("Air.zig"); const TypedValue = @import("TypedValue.zig"); +const Sema = @import("Sema.zig"); /// This is the raw data, with no bookkeeping, no memory awareness, /// no de-duplication, and no type system awareness. @@ -990,6 +991,16 @@ pub const Value = extern union { /// Asserts the value is an integer. pub fn toBigInt(val: Value, space: *BigIntSpace, target: Target) BigIntConst { + return val.toBigIntAdvanced(space, target, null) catch unreachable; + } + + /// Asserts the value is an integer. + pub fn toBigIntAdvanced( + val: Value, + space: *BigIntSpace, + target: Target, + sema_kit: ?Module.WipAnalysis, + ) !BigIntConst { switch (val.tag()) { .zero, .bool_false, @@ -1008,7 +1019,11 @@ pub const Value = extern union { .undef => unreachable, .lazy_align => { - const x = val.castTag(.lazy_align).?.data.abiAlignment(target); + const ty = val.castTag(.lazy_align).?.data; + if (sema_kit) |sk| { + try sk.sema.resolveTypeLayout(sk.block, sk.src, ty); + } + const x = ty.abiAlignment(target); return BigIntMutable.init(&space.limbs, x).toConst(); }, @@ -1019,6 +1034,12 @@ pub const Value = extern union { /// If the value fits in a u64, return it, otherwise null. /// Asserts not undefined. pub fn getUnsignedInt(val: Value, target: Target) ?u64 { + return getUnsignedIntAdvanced(val, target, null) catch unreachable; + } + + /// If the value fits in a u64, return it, otherwise null. + /// Asserts not undefined. + pub fn getUnsignedIntAdvanced(val: Value, target: Target, sema_kit: ?Module.WipAnalysis) !?u64 { switch (val.tag()) { .zero, .bool_false, @@ -1036,7 +1057,13 @@ pub const Value = extern union { .undef => unreachable, - .lazy_align => return val.castTag(.lazy_align).?.data.abiAlignment(target), + .lazy_align => { + const ty = val.castTag(.lazy_align).?.data; + if (sema_kit) |sk| { + try sk.sema.resolveTypeLayout(sk.block, sk.src, ty); + } + return ty.abiAlignment(target); + }, else => return null, } @@ -1777,6 +1804,10 @@ pub const Value = extern union { } pub fn orderAgainstZero(lhs: Value) std.math.Order { + return orderAgainstZeroAdvanced(lhs, null) catch unreachable; + } + + pub fn orderAgainstZeroAdvanced(lhs: Value, sema_kit: ?Module.WipAnalysis) !std.math.Order { return switch (lhs.tag()) { .zero, .bool_false, @@ -1799,7 +1830,7 @@ pub const Value = extern union { .lazy_align => { const ty = lhs.castTag(.lazy_align).?.data; - if (ty.hasRuntimeBitsIgnoreComptime()) { + if (try ty.hasRuntimeBitsAdvanced(false, sema_kit)) { return .gt; } else { return .eq; @@ -1818,10 +1849,16 @@ pub const Value = extern union { /// Asserts the value is comparable. pub fn order(lhs: Value, rhs: Value, target: Target) std.math.Order { + return orderAdvanced(lhs, rhs, target, null) catch unreachable; + } + + /// Asserts the value is comparable. + /// If sema_kit is null then this function asserts things are resolved and cannot fail. + pub fn orderAdvanced(lhs: Value, rhs: Value, target: Target, sema_kit: ?Module.WipAnalysis) !std.math.Order { const lhs_tag = lhs.tag(); const rhs_tag = rhs.tag(); - const lhs_against_zero = lhs.orderAgainstZero(); - const rhs_against_zero = rhs.orderAgainstZero(); + const lhs_against_zero = try lhs.orderAgainstZeroAdvanced(sema_kit); + const rhs_against_zero = try rhs.orderAgainstZeroAdvanced(sema_kit); switch (lhs_against_zero) { .lt => if (rhs_against_zero != .lt) return .lt, .eq => return rhs_against_zero.invert(), @@ -1855,14 +1892,24 @@ pub const Value = extern union { var lhs_bigint_space: BigIntSpace = undefined; var rhs_bigint_space: BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_bigint_space, target); - const rhs_bigint = rhs.toBigInt(&rhs_bigint_space, target); + const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_bigint_space, target, sema_kit); + const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_bigint_space, target, sema_kit); return lhs_bigint.order(rhs_bigint); } /// Asserts the value is comparable. Does not take a type parameter because it supports /// comparisons between heterogeneous types. pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value, target: Target) bool { + return compareHeteroAdvanced(lhs, op, rhs, target, null) catch unreachable; + } + + pub fn compareHeteroAdvanced( + lhs: Value, + op: std.math.CompareOperator, + rhs: Value, + target: Target, + sema_kit: ?Module.WipAnalysis, + ) !bool { if (lhs.pointerDecl()) |lhs_decl| { if (rhs.pointerDecl()) |rhs_decl| { switch (op) { @@ -1884,7 +1931,7 @@ pub const Value = extern union { else => {}, } } - return order(lhs, rhs, target).compare(op); + return (try orderAdvanced(lhs, rhs, target, sema_kit)).compare(op); } /// Asserts the values are comparable. Both operands have type `ty`. diff --git a/test/behavior/struct_contains_slice_of_itself.zig b/test/behavior/struct_contains_slice_of_itself.zig index 11b838a758..cbff2514ea 100644 --- a/test/behavior/struct_contains_slice_of_itself.zig +++ b/test/behavior/struct_contains_slice_of_itself.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const expect = @import("std").testing.expect; const Node = struct { @@ -11,6 +12,10 @@ const NodeAligned = struct { }; test "struct contains slice of itself" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + var other_nodes = [_]Node{ Node{ .payload = 31, @@ -48,6 +53,10 @@ test "struct contains slice of itself" { } test "struct contains aligned slice of itself" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + var other_nodes = [_]NodeAligned{ NodeAligned{ .payload = 31, From 44f9061b718e9bdcd43d258291f89930b74aa56a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 22 Mar 2022 15:58:19 -0700 Subject: [PATCH 3/3] fix merge conflicts and test cases --- src/Sema.zig | 17 +++++++++++++---- test/stage2/x86_64.zig | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 2428db5b0f..e6447ea2ef 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -19732,7 +19732,10 @@ fn analyzeSlice( block, end_src, "end index {} out of bounds for array of length {}", - .{ end_val.fmtValue(Type.usize), len_val.fmtValue(Type.usize) }, + .{ + end_val.fmtValue(Type.usize, target), + len_val.fmtValue(Type.usize, target), + }, ); } if (end_val.eql(len_val, Type.usize, target)) { @@ -19758,7 +19761,10 @@ fn analyzeSlice( block, end_src, "end index {} out of bounds for slice of length {}", - .{ end_val.fmtValue(Type.usize), slice_len_val.fmtValue(Type.usize) }, + .{ + end_val.fmtValue(Type.usize, target), + slice_len_val.fmtValue(Type.usize, target), + }, ); } if (end_val.eql(slice_len_val, Type.usize, target)) { @@ -19794,12 +19800,15 @@ fn analyzeSlice( // requirement: start <= end if (try sema.resolveDefinedValue(block, src, end)) |end_val| { if (try sema.resolveDefinedValue(block, src, start)) |start_val| { - if (start_val.compare(.gt, end_val, Type.usize)) { + if (start_val.compare(.gt, end_val, Type.usize, target)) { return sema.fail( block, start_src, "start index {} is larger than end index {}", - .{ start_val.fmtValue(Type.usize), end_val.fmtValue(Type.usize) }, + .{ + start_val.fmtValue(Type.usize, target), + end_val.fmtValue(Type.usize, target), + }, ); } } diff --git a/test/stage2/x86_64.zig b/test/stage2/x86_64.zig index 38dafd8fc0..a7ebce36d3 100644 --- a/test/stage2/x86_64.zig +++ b/test/stage2/x86_64.zig @@ -1166,7 +1166,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ _ = x; \\} , &[_][]const u8{ - ":2:9: error: variable of type '@Type(.Null)' must be const or comptime", + ":2:9: error: variable of type '@TypeOf(null)' must be const or comptime", }); }