authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-29 17:48:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-29 17:49:02-07:00
logd6067db06267e37dec65202667741bc1b63fe980
treea693698a60b30a7d0ca2764056858c8b74066cd7
parent5ff01bd820ea08005a422f046ad5bbad663b0dab

stage2: implement `@popCount` for non-vectors


14 files changed, 209 insertions(+), 176 deletions(-)

lib/std/math/big/int.zig+30
......@@ -733,6 +733,27 @@ pub const Mutable = struct {
733733 rma.truncate(rma.toConst(), signedness, bit_count);
734734 }
735735
736 /// r = @popCount(a) with 2s-complement semantics.
737 /// r and a may be aliases.
738 ///
739 /// Assets the result fits in `r`. Upper bound on the number of limbs needed by
740 /// r is `calcTwosCompLimbCount(bit_count)`.
741 pub fn popCount(r: *Mutable, a: Const, bit_count: usize) void {
742 r.copy(a);
743
744 if (!a.positive) {
745 r.positive = true; // Negate.
746 r.bitNotWrap(r.toConst(), .unsigned, bit_count); // Bitwise NOT.
747 r.addScalar(r.toConst(), 1); // Add one.
748 }
749
750 var sum: Limb = 0;
751 for (r.limbs[0..r.len]) |limb| {
752 sum += @popCount(Limb, limb);
753 }
754 r.set(sum);
755 }
756
736757 /// rma = a * a
737758 ///
738759 /// `rma` may not alias with `a`.
......@@ -2735,6 +2756,15 @@ pub const Managed = struct {
27352756 m.saturate(a, signedness, bit_count);
27362757 r.setMetadata(m.positive, m.len);
27372758 }
2759
2760 /// r = @popCount(a) with 2s-complement semantics.
2761 /// r and a may be aliases.
2762 pub fn popCount(r: *Managed, a: Const, bit_count: usize) !void {
2763 try r.ensureCapacity(calcTwosCompLimbCount(bit_count));
2764 var m = r.toMutable();
2765 m.popCount(a, bit_count);
2766 r.setMetadata(m.positive, m.len);
2767 }
27382768};
27392769
27402770/// Different operators which can be used in accumulation style functions
lib/std/math/big/int_test.zig+11
......@@ -2434,3 +2434,14 @@ test "big.int regression test for realloc with alias" {
24342434
24352435 try testing.expect(a.toConst().orderAgainstScalar(14691098406862188148944207245954912110548093601382197697835) == .eq);
24362436}
2437
2438test "big int popcount" {
2439 var a = try Managed.initSet(testing.allocator, -1);
2440 defer a.deinit();
2441 var b = try Managed.initSet(testing.allocator, -1);
2442 defer b.deinit();
2443
2444 try a.popCount(b.toConst(), 16);
2445
2446 try testing.expect(a.toConst().orderAgainstScalar(16) == .eq);
2447}
src/Air.zig+5
......@@ -202,6 +202,10 @@ pub const Inst = struct {
202202 /// Result type will always be an unsigned integer big enough to fit the answer.
203203 /// Uses the `ty_op` field.
204204 ctz,
205 /// Count number of 1 bits in an integer according to its representation in twos complement.
206 /// Result type will always be an unsigned integer big enough to fit the answer.
207 /// Uses the `ty_op` field.
208 popcount,
205209
206210 /// `<`. Result type is always bool.
207211 /// Uses the `bin_op` field.
......@@ -744,6 +748,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
744748 .get_union_tag,
745749 .clz,
746750 .ctz,
751 .popcount,
747752 => return air.getRefType(datas[inst].ty_op.ty),
748753
749754 .loop,
src/Liveness.zig+1
......@@ -313,6 +313,7 @@ fn analyzeInst(
313313 .get_union_tag,
314314 .clz,
315315 .ctz,
316 .popcount,
316317 => {
317318 const o = inst_datas[inst].ty_op;
318319 return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none });
src/Sema.zig+24-2
......@@ -9904,8 +9904,30 @@ fn zirCtz(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
99049904
99059905fn zirPopCount(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
99069906 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
9907 const src = inst_data.src();
9908 return sema.fail(block, src, "TODO: Sema.zirPopCount", .{});
9907 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
9908 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
9909 const operand = sema.resolveInst(inst_data.operand);
9910 const operand_ty = sema.typeOf(operand);
9911 // TODO implement support for vectors
9912 if (operand_ty.zigTypeTag() != .Int) {
9913 return sema.fail(block, ty_src, "expected integer type, found '{}'", .{
9914 operand_ty,
9915 });
9916 }
9917 const target = sema.mod.getTarget();
9918 const bits = operand_ty.intInfo(target).bits;
9919 if (bits == 0) return Air.Inst.Ref.zero;
9920
9921 const result_ty = try Type.smallestUnsignedInt(sema.arena, bits);
9922
9923 const runtime_src = if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
9924 if (val.isUndef()) return sema.addConstUndef(result_ty);
9925 const result_val = try val.popCount(operand_ty, target, sema.arena);
9926 return sema.addConstant(result_ty, result_val);
9927 } else operand_src;
9928
9929 try sema.requireRuntimeBlock(block, runtime_src);
9930 return block.addTyOp(.popcount, result_ty, operand);
99099931}
99109932
99119933fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
src/arch/aarch64/CodeGen.zig+7
......@@ -481,6 +481,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
481481 .get_union_tag => try self.airGetUnionTag(inst),
482482 .clz => try self.airClz(inst),
483483 .ctz => try self.airCtz(inst),
484 .popcount => try self.airPopcount(inst),
484485
485486 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
486487 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
......@@ -1138,6 +1139,12 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
11381139 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
11391140}
11401141
1142fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
1143 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1144 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airPopcount for {}", .{self.target.cpu.arch});
1145 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1146}
1147
11411148fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool {
11421149 if (!self.liveness.operandDies(inst, op_index))
11431150 return false;
src/codegen.zig+9
......@@ -836,6 +836,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
836836 .get_union_tag => try self.airGetUnionTag(inst),
837837 .clz => try self.airClz(inst),
838838 .ctz => try self.airCtz(inst),
839 .popcount => try self.airPopcount(inst),
839840
840841 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
841842 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
......@@ -1610,6 +1611,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
16101611 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
16111612 }
16121613
1614 fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
1615 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1616 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1617 else => return self.fail("TODO implement airPopcount for {}", .{self.target.cpu.arch}),
1618 };
1619 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1620 }
1621
16131622 fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool {
16141623 if (!self.liveness.operandDies(inst, op_index))
16151624 return false;
src/codegen/c.zig+1
......@@ -1107,6 +1107,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
11071107 .get_union_tag => try airGetUnionTag(f, inst),
11081108 .clz => try airBuiltinCall(f, inst, "clz"),
11091109 .ctz => try airBuiltinCall(f, inst, "ctz"),
1110 .popcount => try airBuiltinCall(f, inst, "popcount"),
11101111
11111112 .int_to_float,
11121113 .float_to_int,
src/codegen/llvm.zig+35
......@@ -1777,6 +1777,7 @@ pub const FuncGen = struct {
17771777 .get_union_tag => try self.airGetUnionTag(inst),
17781778 .clz => try self.airClzCtz(inst, "ctlz"),
17791779 .ctz => try self.airClzCtz(inst, "cttz"),
1780 .popcount => try self.airPopCount(inst, "ctpop"),
17801781
17811782 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
17821783 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
......@@ -3679,6 +3680,40 @@ pub const FuncGen = struct {
36793680 }
36803681 }
36813682
3683 fn airPopCount(self: *FuncGen, inst: Air.Inst.Index, prefix: [*:0]const u8) !?*const llvm.Value {
3684 if (self.liveness.isUnused(inst)) return null;
3685
3686 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3687 const operand_ty = self.air.typeOf(ty_op.operand);
3688 const operand = try self.resolveInst(ty_op.operand);
3689 const target = self.dg.module.getTarget();
3690 const bits = operand_ty.intInfo(target).bits;
3691
3692 var fn_name_buf: [100]u8 = undefined;
3693 const llvm_fn_name = std.fmt.bufPrintZ(&fn_name_buf, "llvm.{s}.i{d}", .{
3694 prefix, bits,
3695 }) catch unreachable;
3696 const fn_val = self.dg.object.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
3697 const operand_llvm_ty = try self.dg.llvmType(operand_ty);
3698 const param_types = [_]*const llvm.Type{operand_llvm_ty};
3699 const fn_type = llvm.functionType(operand_llvm_ty, &param_types, param_types.len, .False);
3700 break :blk self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);
3701 };
3702
3703 const params = [_]*const llvm.Value{operand};
3704 const wrong_size_result = self.builder.buildCall(fn_val, &params, params.len, .C, .Auto, "");
3705 const result_ty = self.air.typeOfIndex(inst);
3706 const result_llvm_ty = try self.dg.llvmType(result_ty);
3707 const result_bits = result_ty.intInfo(target).bits;
3708 if (bits > result_bits) {
3709 return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");
3710 } else if (bits < result_bits) {
3711 return self.builder.buildZExt(wrong_size_result, result_llvm_ty, "");
3712 } else {
3713 return wrong_size_result;
3714 }
3715 }
3716
36823717 fn callFloor(self: *FuncGen, arg: *const llvm.Value, ty: Type) !*const llvm.Value {
36833718 return self.callFloatUnary(arg, ty, "floor");
36843719 }
src/print_air.zig+1
......@@ -196,6 +196,7 @@ const Writer = struct {
196196 .get_union_tag,
197197 .clz,
198198 .ctz,
199 .popcount,
199200 => try w.writeTyOp(s, inst),
200201
201202 .block,
src/value.zig+59-157
......@@ -1062,14 +1062,7 @@ pub const Value = extern union {
10621062 const limbs_buffer = try arena.alloc(std.math.big.Limb, 2);
10631063 var bigint = BigIntMutable.init(limbs_buffer, 0);
10641064 bigint.readTwosComplement(buffer, int_info.bits, endian, int_info.signedness);
1065 // TODO if it fits in 64 bits then use one of those tags
1066
1067 const result_limbs = bigint.limbs[0..bigint.len];
1068 if (bigint.positive) {
1069 return Value.Tag.int_big_positive.create(arena, result_limbs);
1070 } else {
1071 return Value.Tag.int_big_negative.create(arena, result_limbs);
1072 }
1065 return fromBigInt(arena, bigint.toConst());
10731066 },
10741067 .Float => switch (ty.floatBits(target)) {
10751068 16 => return Value.Tag.float_16.create(arena, floatReadFromMemory(f16, target, buffer)),
......@@ -1200,16 +1193,34 @@ pub const Value = extern union {
12001193 if (x == 0) return 0;
12011194 return @intCast(usize, std.math.log2(x) + 1);
12021195 },
1203 .int_i64 => {
1204 @panic("TODO implement i64 intBitCountTwosComp");
1205 },
12061196 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
12071197 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),
12081198
1209 else => unreachable,
1199 else => {
1200 var buffer: BigIntSpace = undefined;
1201 return self.toBigInt(&buffer).bitCountTwosComp();
1202 },
12101203 }
12111204 }
12121205
1206 pub fn popCount(val: Value, ty: Type, target: Target, arena: *Allocator) !Value {
1207 assert(!val.isUndef());
1208
1209 const info = ty.intInfo(target);
1210
1211 var buffer: Value.BigIntSpace = undefined;
1212 const operand_bigint = val.toBigInt(&buffer);
1213
1214 const limbs = try arena.alloc(
1215 std.math.big.Limb,
1216 std.math.big.int.calcTwosCompLimbCount(info.bits),
1217 );
1218 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
1219 result_bigint.popCount(operand_bigint, info.bits);
1220
1221 return fromBigInt(arena, result_bigint.toConst());
1222 }
1223
12131224 /// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
12141225 pub fn intFitsInType(self: Value, ty: Type, target: Target) bool {
12151226 switch (self.tag()) {
......@@ -1246,7 +1257,8 @@ pub const Value = extern union {
12461257 const info = ty.intInfo(target);
12471258 if (info.signedness == .unsigned and x < 0)
12481259 return false;
1249 @panic("TODO implement i64 intFitsInType");
1260 var buffer: BigIntSpace = undefined;
1261 return self.toBigInt(&buffer).fitsInTwosComp(info.signedness, info.bits);
12501262 },
12511263 .ComptimeInt => return true,
12521264 else => unreachable,
......@@ -1943,12 +1955,22 @@ pub const Value = extern union {
19431955 );
19441956 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
19451957 result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
1946 const result_limbs = result_bigint.limbs[0..result_bigint.len];
1958 return fromBigInt(arena, result_bigint.toConst());
1959 }
19471960
1948 if (result_bigint.positive) {
1949 return Value.Tag.int_big_positive.create(arena, result_limbs);
1961 fn fromBigInt(arena: *Allocator, big_int: BigIntConst) !Value {
1962 if (big_int.positive) {
1963 if (big_int.to(u64)) |x| {
1964 return Value.Tag.int_u64.create(arena, x);
1965 } else |_| {
1966 return Value.Tag.int_big_positive.create(arena, big_int.limbs);
1967 }
19501968 } else {
1951 return Value.Tag.int_big_negative.create(arena, result_limbs);
1969 if (big_int.to(i64)) |x| {
1970 return Value.Tag.int_i64.create(arena, x);
1971 } else |_| {
1972 return Value.Tag.int_big_negative.create(arena, big_int.limbs);
1973 }
19521974 }
19531975 }
19541976
......@@ -1975,13 +1997,7 @@ pub const Value = extern union {
19751997 );
19761998 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
19771999 result_bigint.addSat(lhs_bigint, rhs_bigint, info.signedness, info.bits);
1978 const result_limbs = result_bigint.limbs[0..result_bigint.len];
1979
1980 if (result_bigint.positive) {
1981 return Value.Tag.int_big_positive.create(arena, result_limbs);
1982 } else {
1983 return Value.Tag.int_big_negative.create(arena, result_limbs);
1984 }
2000 return fromBigInt(arena, result_bigint.toConst());
19852001 }
19862002
19872003 /// Supports both floats and ints; handles undefined.
......@@ -2010,13 +2026,7 @@ pub const Value = extern union {
20102026 );
20112027 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
20122028 result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
2013 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2014
2015 if (result_bigint.positive) {
2016 return Value.Tag.int_big_positive.create(arena, result_limbs);
2017 } else {
2018 return Value.Tag.int_big_negative.create(arena, result_limbs);
2019 }
2029 return fromBigInt(arena, result_bigint.toConst());
20202030 }
20212031
20222032 /// Supports integers only; asserts neither operand is undefined.
......@@ -2042,13 +2052,7 @@ pub const Value = extern union {
20422052 );
20432053 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
20442054 result_bigint.subSat(lhs_bigint, rhs_bigint, info.signedness, info.bits);
2045 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2046
2047 if (result_bigint.positive) {
2048 return Value.Tag.int_big_positive.create(arena, result_limbs);
2049 } else {
2050 return Value.Tag.int_big_negative.create(arena, result_limbs);
2051 }
2055 return fromBigInt(arena, result_bigint.toConst());
20522056 }
20532057
20542058 /// Supports both floats and ints; handles undefined.
......@@ -2082,13 +2086,7 @@ pub const Value = extern union {
20822086 );
20832087 defer arena.free(limbs_buffer);
20842088 result_bigint.mulWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits, limbs_buffer, arena);
2085 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2086
2087 if (result_bigint.positive) {
2088 return Value.Tag.int_big_positive.create(arena, result_limbs);
2089 } else {
2090 return Value.Tag.int_big_negative.create(arena, result_limbs);
2091 }
2089 return fromBigInt(arena, result_bigint.toConst());
20922090 }
20932091
20942092 /// Supports integers only; asserts neither operand is undefined.
......@@ -2124,13 +2122,7 @@ pub const Value = extern union {
21242122 defer arena.free(limbs_buffer);
21252123 result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, arena);
21262124 result_bigint.saturate(result_bigint.toConst(), info.signedness, info.bits);
2127 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2128
2129 if (result_bigint.positive) {
2130 return Value.Tag.int_big_positive.create(arena, result_limbs);
2131 } else {
2132 return Value.Tag.int_big_negative.create(arena, result_limbs);
2133 }
2125 return fromBigInt(arena, result_bigint.toConst());
21342126 }
21352127
21362128 /// Supports both floats and ints; handles undefined.
......@@ -2174,13 +2166,7 @@ pub const Value = extern union {
21742166
21752167 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
21762168 result_bigint.bitNotWrap(val_bigint, info.signedness, info.bits);
2177 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2178
2179 if (result_bigint.positive) {
2180 return Value.Tag.int_big_positive.create(arena, result_limbs);
2181 } else {
2182 return Value.Tag.int_big_negative.create(arena, result_limbs);
2183 }
2169 return fromBigInt(arena, result_bigint.toConst());
21842170 }
21852171
21862172 /// operands must be integers; handles undefined.
......@@ -2200,13 +2186,7 @@ pub const Value = extern union {
22002186 );
22012187 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
22022188 result_bigint.bitAnd(lhs_bigint, rhs_bigint);
2203 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2204
2205 if (result_bigint.positive) {
2206 return Value.Tag.int_big_positive.create(arena, result_limbs);
2207 } else {
2208 return Value.Tag.int_big_negative.create(arena, result_limbs);
2209 }
2189 return fromBigInt(arena, result_bigint.toConst());
22102190 }
22112191
22122192 /// operands must be integers; handles undefined.
......@@ -2239,13 +2219,7 @@ pub const Value = extern union {
22392219 );
22402220 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
22412221 result_bigint.bitOr(lhs_bigint, rhs_bigint);
2242 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2243
2244 if (result_bigint.positive) {
2245 return Value.Tag.int_big_positive.create(arena, result_limbs);
2246 } else {
2247 return Value.Tag.int_big_negative.create(arena, result_limbs);
2248 }
2222 return fromBigInt(arena, result_bigint.toConst());
22492223 }
22502224
22512225 /// operands must be integers; handles undefined.
......@@ -2265,13 +2239,7 @@ pub const Value = extern union {
22652239 );
22662240 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
22672241 result_bigint.bitXor(lhs_bigint, rhs_bigint);
2268 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2269
2270 if (result_bigint.positive) {
2271 return Value.Tag.int_big_positive.create(arena, result_limbs);
2272 } else {
2273 return Value.Tag.int_big_negative.create(arena, result_limbs);
2274 }
2242 return fromBigInt(arena, result_bigint.toConst());
22752243 }
22762244
22772245 pub fn intAdd(lhs: Value, rhs: Value, allocator: *Allocator) !Value {
......@@ -2287,13 +2255,7 @@ pub const Value = extern union {
22872255 );
22882256 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
22892257 result_bigint.add(lhs_bigint, rhs_bigint);
2290 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2291
2292 if (result_bigint.positive) {
2293 return Value.Tag.int_big_positive.create(allocator, result_limbs);
2294 } else {
2295 return Value.Tag.int_big_negative.create(allocator, result_limbs);
2296 }
2258 return fromBigInt(allocator, result_bigint.toConst());
22972259 }
22982260
22992261 pub fn intSub(lhs: Value, rhs: Value, allocator: *Allocator) !Value {
......@@ -2309,13 +2271,7 @@ pub const Value = extern union {
23092271 );
23102272 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
23112273 result_bigint.sub(lhs_bigint, rhs_bigint);
2312 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2313
2314 if (result_bigint.positive) {
2315 return Value.Tag.int_big_positive.create(allocator, result_limbs);
2316 } else {
2317 return Value.Tag.int_big_negative.create(allocator, result_limbs);
2318 }
2274 return fromBigInt(allocator, result_bigint.toConst());
23192275 }
23202276
23212277 pub fn intDiv(lhs: Value, rhs: Value, allocator: *Allocator) !Value {
......@@ -2340,13 +2296,7 @@ pub const Value = extern union {
23402296 var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined };
23412297 var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined };
23422298 result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer);
2343 const result_limbs = result_q.limbs[0..result_q.len];
2344
2345 if (result_q.positive) {
2346 return Value.Tag.int_big_positive.create(allocator, result_limbs);
2347 } else {
2348 return Value.Tag.int_big_negative.create(allocator, result_limbs);
2349 }
2299 return fromBigInt(allocator, result_q.toConst());
23502300 }
23512301
23522302 pub fn intDivFloor(lhs: Value, rhs: Value, allocator: *Allocator) !Value {
......@@ -2371,13 +2321,7 @@ pub const Value = extern union {
23712321 var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined };
23722322 var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined };
23732323 result_q.divFloor(&result_r, lhs_bigint, rhs_bigint, limbs_buffer);
2374 const result_limbs = result_q.limbs[0..result_q.len];
2375
2376 if (result_q.positive) {
2377 return Value.Tag.int_big_positive.create(allocator, result_limbs);
2378 } else {
2379 return Value.Tag.int_big_negative.create(allocator, result_limbs);
2380 }
2324 return fromBigInt(allocator, result_q.toConst());
23812325 }
23822326
23832327 pub fn intRem(lhs: Value, rhs: Value, allocator: *Allocator) !Value {
......@@ -2404,13 +2348,7 @@ pub const Value = extern union {
24042348 var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined };
24052349 var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined };
24062350 result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer);
2407 const result_limbs = result_r.limbs[0..result_r.len];
2408
2409 if (result_r.positive) {
2410 return Value.Tag.int_big_positive.create(allocator, result_limbs);
2411 } else {
2412 return Value.Tag.int_big_negative.create(allocator, result_limbs);
2413 }
2351 return fromBigInt(allocator, result_r.toConst());
24142352 }
24152353
24162354 pub fn intMod(lhs: Value, rhs: Value, allocator: *Allocator) !Value {
......@@ -2435,13 +2373,7 @@ pub const Value = extern union {
24352373 var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined };
24362374 var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined };
24372375 result_q.divFloor(&result_r, lhs_bigint, rhs_bigint, limbs_buffer);
2438 const result_limbs = result_r.limbs[0..result_r.len];
2439
2440 if (result_r.positive) {
2441 return Value.Tag.int_big_positive.create(allocator, result_limbs);
2442 } else {
2443 return Value.Tag.int_big_negative.create(allocator, result_limbs);
2444 }
2376 return fromBigInt(allocator, result_r.toConst());
24452377 }
24462378
24472379 /// Returns true if the value is a floating point type and is NaN. Returns false otherwise.
......@@ -2487,13 +2419,7 @@ pub const Value = extern union {
24872419 );
24882420 defer allocator.free(limbs_buffer);
24892421 result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, allocator);
2490 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2491
2492 if (result_bigint.positive) {
2493 return Value.Tag.int_big_positive.create(allocator, result_limbs);
2494 } else {
2495 return Value.Tag.int_big_negative.create(allocator, result_limbs);
2496 }
2422 return fromBigInt(allocator, result_bigint.toConst());
24972423 }
24982424
24992425 pub fn intTrunc(val: Value, allocator: *Allocator, signedness: std.builtin.Signedness, bits: u16) !Value {
......@@ -2507,13 +2433,7 @@ pub const Value = extern union {
25072433 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
25082434
25092435 result_bigint.truncate(val_bigint, signedness, bits);
2510 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2511
2512 if (result_bigint.positive) {
2513 return Value.Tag.int_big_positive.create(allocator, result_limbs);
2514 } else {
2515 return Value.Tag.int_big_negative.create(allocator, result_limbs);
2516 }
2436 return fromBigInt(allocator, result_bigint.toConst());
25172437 }
25182438
25192439 pub fn shl(lhs: Value, rhs: Value, allocator: *Allocator) !Value {
......@@ -2532,13 +2452,7 @@ pub const Value = extern union {
25322452 .len = undefined,
25332453 };
25342454 result_bigint.shiftLeft(lhs_bigint, shift);
2535 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2536
2537 if (result_bigint.positive) {
2538 return Value.Tag.int_big_positive.create(allocator, result_limbs);
2539 } else {
2540 return Value.Tag.int_big_negative.create(allocator, result_limbs);
2541 }
2455 return fromBigInt(allocator, result_bigint.toConst());
25422456 }
25432457
25442458 pub fn shlSat(
......@@ -2565,13 +2479,7 @@ pub const Value = extern union {
25652479 .len = undefined,
25662480 };
25672481 result_bigint.shiftLeftSat(lhs_bigint, shift, info.signedness, info.bits);
2568 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2569
2570 if (result_bigint.positive) {
2571 return Value.Tag.int_big_positive.create(arena, result_limbs);
2572 } else {
2573 return Value.Tag.int_big_negative.create(arena, result_limbs);
2574 }
2482 return fromBigInt(arena, result_bigint.toConst());
25752483 }
25762484
25772485 pub fn shr(lhs: Value, rhs: Value, allocator: *Allocator) !Value {
......@@ -2590,13 +2498,7 @@ pub const Value = extern union {
25902498 .len = undefined,
25912499 };
25922500 result_bigint.shiftRight(lhs_bigint, shift);
2593 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2594
2595 if (result_bigint.positive) {
2596 return Value.Tag.int_big_positive.create(allocator, result_limbs);
2597 } else {
2598 return Value.Tag.int_big_negative.create(allocator, result_limbs);
2599 }
2501 return fromBigInt(allocator, result_bigint.toConst());
26002502 }
26012503
26022504 pub fn floatAdd(
test/behavior.zig+2-1
......@@ -50,6 +50,7 @@ test {
5050 _ = @import("behavior/null.zig");
5151 _ = @import("behavior/optional.zig");
5252 _ = @import("behavior/pointers.zig");
53 _ = @import("behavior/popcount.zig");
5354 _ = @import("behavior/ptrcast.zig");
5455 _ = @import("behavior/pub_enum.zig");
5556 _ = @import("behavior/saturating_arithmetic.zig");
......@@ -153,7 +154,7 @@ test {
153154 _ = @import("behavior/null_stage1.zig");
154155 _ = @import("behavior/optional_stage1.zig");
155156 _ = @import("behavior/pointers_stage1.zig");
156 _ = @import("behavior/popcount.zig");
157 _ = @import("behavior/popcount_stage1.zig");
157158 _ = @import("behavior/ptrcast_stage1.zig");
158159 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
159160 _ = @import("behavior/reflection.zig");
test/behavior/popcount.zig-16
......@@ -44,19 +44,3 @@ fn testPopCountIntegers() !void {
4444 try expect(@popCount(i128, 0b11111111000110001100010000100001000011000011100101010001) == 24);
4545 }
4646}
47
48test "@popCount vectors" {
49 comptime try testPopCountVectors();
50 try testPopCountVectors();
51}
52
53fn testPopCountVectors() !void {
54 {
55 var x: Vector(8, u32) = [1]u32{0xffffffff} ** 8;
56 try expectEqual([1]u6{32} ** 8, @as([8]u6, @popCount(u32, x)));
57 }
58 {
59 var x: Vector(8, i16) = [1]i16{-1} ** 8;
60 try expectEqual([1]u5{16} ** 8, @as([8]u5, @popCount(i16, x)));
61 }
62}
test/behavior/popcount_stage1.zig created+24
......@@ -0,0 +1,24 @@
1const std = @import("std");
2const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;
4const Vector = std.meta.Vector;
5
6test "@popCount vectors" {
7 comptime try testPopCountVectors();
8 try testPopCountVectors();
9}
10
11fn testPopCountVectors() !void {
12 {
13 var x: Vector(8, u32) = [1]u32{0xffffffff} ** 8;
14 const expected = [1]u6{32} ** 8;
15 const result: [8]u6 = @popCount(u32, x);
16 try expect(std.mem.eql(u6, &expected, &result));
17 }
18 {
19 var x: Vector(8, i16) = [1]i16{-1} ** 8;
20 const expected = [1]u5{16} ** 8;
21 const result: [8]u5 = @popCount(i16, x);
22 try expect(std.mem.eql(u5, &expected, &result));
23 }
24}