From 4c3c605e5f53c91430efac821ce1b863cbb5bf06 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 7 May 2023 12:53:14 -0700 Subject: [PATCH] InternPool: add getCoercedInt to avoid copy in Sema --- src/InternPool.zig | 20 ++++++++++++++++++++ src/Sema.zig | 15 +-------------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/InternPool.zig b/src/InternPool.zig index 3f6e4793b8..f6d594cbbb 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -1535,6 +1535,26 @@ pub fn slicePtrType(ip: InternPool, i: Index) Index { } } +/// Given an existing integer value, returns the same numerical value but with +/// the supplied type. +pub fn getCoercedInt(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index { + const key = ip.indexToKey(val); + // The key cannot be passed directly to `get`, otherwise in the case of + // big_int storage, the limbs would be invalidated before they are read. + // Here we pre-reserve the limbs to ensure that the logic in `addInt` will + // not use an invalidated limbs pointer. + switch (key.int.storage) { + .u64, .i64 => {}, + .big_int => |big_int| { + try reserveLimbs(ip, gpa, @typeInfo(Int).Struct.fields.len + big_int.limbs.len); + }, + } + return ip.get(gpa, .{ .int = .{ + .ty = new_ty, + .storage = key.int.storage, + } }); +} + pub fn dump(ip: InternPool) void { dumpFallible(ip, std.heap.page_allocator) catch return; } diff --git a/src/Sema.zig b/src/Sema.zig index e92c626691..dc5bb1cdea 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -25957,20 +25957,7 @@ fn coerceExtra( if (!opts.report_err) return error.NotCoercible; return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) }); } - const key = mod.intern_pool.indexToKey(val.ip_index); - // If the int is represented as a bigint, copy it so we can safely pass it to `mod.intern` - const int_storage: InternPool.Key.Int.Storage = switch (key.int.storage) { - .u64 => |x| .{ .u64 = x }, - .i64 => |x| .{ .i64 = x }, - .big_int => |big_int| .{ .big_int = .{ - .limbs = try sema.arena.dupe(std.math.big.Limb, big_int.limbs), - .positive = big_int.positive, - } }, - }; - const new_val = try mod.intern(.{ .int = .{ - .ty = dest_ty.ip_index, - .storage = int_storage, - } }); + const new_val = try mod.intern_pool.getCoercedInt(sema.gpa, val.ip_index, dest_ty.ip_index); return try sema.addConstant(dest_ty, new_val.toValue()); } if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {