Commit f466667888

Andrew Kelley <andrew@ziglang.org>
2022-11-29 21:40:57
stage2: fix crash on comptime lazy `@ctz` and `@clz`
1 parent ceb0a63
Changed files (3)
lib
std
math
src
lib/std/math/big/int.zig
@@ -2376,6 +2376,34 @@ pub const Const = struct {
     pub fn eq(a: Const, b: Const) bool {
         return order(a, b) == .eq;
     }
+
+    pub fn clz(a: Const, bits: Limb) Limb {
+        // Limbs are stored in little-endian order but we need
+        // to iterate big-endian.
+        var total_limb_lz: Limb = 0;
+        var i: usize = a.limbs.len;
+        const bits_per_limb = @sizeOf(Limb) * 8;
+        while (i != 0) {
+            i -= 1;
+            const limb = a.limbs[i];
+            const this_limb_lz = @clz(limb);
+            total_limb_lz += this_limb_lz;
+            if (this_limb_lz != bits_per_limb) break;
+        }
+        const total_limb_bits = a.limbs.len * bits_per_limb;
+        return total_limb_lz + bits - total_limb_bits;
+    }
+
+    pub fn ctz(a: Const) Limb {
+        // Limbs are stored in little-endian order.
+        var result: Limb = 0;
+        for (a.limbs) |limb| {
+            const limb_tz = @ctz(limb);
+            result += limb_tz;
+            if (limb_tz != @sizeOf(Limb) * 8) break;
+        }
+        return result;
+    }
 };
 
 /// An arbitrary-precision big integer along with an allocator which manages the memory.
src/Sema.zig
@@ -19299,6 +19299,7 @@ fn zirBitCount(
         .Int => {
             if (try sema.resolveMaybeUndefVal(operand)) |val| {
                 if (val.isUndef()) return sema.addConstUndef(result_scalar_ty);
+                try sema.resolveLazyValue(val);
                 return sema.addIntUnsigned(result_scalar_ty, comptimeOp(val, operand_ty, target));
             } else {
                 try sema.requireRuntimeBlock(block, src, operand_src);
src/value.zig
@@ -1677,22 +1677,8 @@ pub const Value = extern union {
                 @panic("TODO implement i64 Value clz");
             },
             .int_big_positive => {
-                // TODO: move this code into std lib big ints
                 const bigint = val.castTag(.int_big_positive).?.asBigInt();
-                // Limbs are stored in little-endian order but we need
-                // to iterate big-endian.
-                var total_limb_lz: u64 = 0;
-                var i: usize = bigint.limbs.len;
-                const bits_per_limb = @sizeOf(std.math.big.Limb) * 8;
-                while (i != 0) {
-                    i -= 1;
-                    const limb = bigint.limbs[i];
-                    const this_limb_lz = @clz(limb);
-                    total_limb_lz += this_limb_lz;
-                    if (this_limb_lz != bits_per_limb) break;
-                }
-                const total_limb_bits = bigint.limbs.len * bits_per_limb;
-                return total_limb_lz + ty_bits - total_limb_bits;
+                return bigint.clz(ty_bits);
             },
             .int_big_negative => {
                 @panic("TODO implement int_big_negative Value clz");
@@ -1703,6 +1689,12 @@ pub const Value = extern union {
                 return ty_bits;
             },
 
+            .lazy_align, .lazy_size => {
+                var bigint_buf: BigIntSpace = undefined;
+                const bigint = val.toBigIntAdvanced(&bigint_buf, target, null) catch unreachable;
+                return bigint.clz(ty_bits);
+            },
+
             else => unreachable,
         }
     }
@@ -1721,16 +1713,8 @@ pub const Value = extern union {
                 @panic("TODO implement i64 Value ctz");
             },
             .int_big_positive => {
-                // TODO: move this code into std lib big ints
                 const bigint = val.castTag(.int_big_positive).?.asBigInt();
-                // Limbs are stored in little-endian order.
-                var result: u64 = 0;
-                for (bigint.limbs) |limb| {
-                    const limb_tz = @ctz(limb);
-                    result += limb_tz;
-                    if (limb_tz != @sizeOf(std.math.big.Limb) * 8) break;
-                }
-                return result;
+                return bigint.ctz();
             },
             .int_big_negative => {
                 @panic("TODO implement int_big_negative Value ctz");
@@ -1741,6 +1725,12 @@ pub const Value = extern union {
                 return ty_bits;
             },
 
+            .lazy_align, .lazy_size => {
+                var bigint_buf: BigIntSpace = undefined;
+                const bigint = val.toBigIntAdvanced(&bigint_buf, target, null) catch unreachable;
+                return bigint.ctz();
+            },
+
             else => unreachable,
         }
     }