Skip to content

Commit

Permalink
Merge pull request #22717 from jacobly0/x86_64-rewrite
Browse files Browse the repository at this point in the history
x86_64: rewrite `@truncate`
  • Loading branch information
andrewrk authored Feb 7, 2025
2 parents 42e48b8 + 6afc577 commit 2d4954a
Show file tree
Hide file tree
Showing 13 changed files with 32,602 additions and 10,176 deletions.
2 changes: 1 addition & 1 deletion build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ pub fn build(b: *std.Build) !void {
.skip_non_native = skip_non_native,
.skip_libc = skip_libc,
.use_llvm = use_llvm,
.max_rss = 1.25 * 1024 * 1024 * 1024,
.max_rss = 2 * 1024 * 1024 * 1024,
}));

test_modules_step.dependOn(tests.addModuleTests(b, .{
Expand Down
27 changes: 10 additions & 17 deletions lib/std/math/big/int.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1793,9 +1793,13 @@ pub const Mutable = struct {
/// The upper bound is `calcTwosCompLimbCount(a.len)`.
pub fn truncate(r: *Mutable, a: Const, signedness: Signedness, bit_count: usize) void {
const req_limbs = calcTwosCompLimbCount(bit_count);
const abs_trunc_a: Const = .{
.positive = true,
.limbs = a.limbs[0..@min(a.limbs.len, req_limbs)],
};

// Handle 0-bit integers.
if (req_limbs == 0 or a.eqlZero()) {
if (req_limbs == 0 or abs_trunc_a.eqlZero()) {
r.set(0);
return;
}
Expand All @@ -1810,15 +1814,10 @@ pub const Mutable = struct {
// Note, we simply take req_limbs * @bitSizeOf(Limb) as the
// target bit count.

r.addScalar(a.abs(), -1);
r.addScalar(abs_trunc_a, -1);

// Zero-extend the result
if (req_limbs > r.len) {
@memset(r.limbs[r.len..req_limbs], 0);
}

// Truncate to required number of limbs.
assert(r.limbs.len >= req_limbs);
@memset(r.limbs[r.len..req_limbs], 0);
r.len = req_limbs;

// Without truncating, we can already peek at the sign bit of the result here.
Expand Down Expand Up @@ -1846,16 +1845,10 @@ pub const Mutable = struct {
r.normalize(r.len);
}
} else {
if (a.limbs.len < req_limbs) {
// Integer fits within target bits, no wrapping required.
r.copy(a);
return;
}
r.copy(abs_trunc_a);
// If the integer fits within target bits, no wrapping is required.
if (r.len < req_limbs) return;

r.copy(.{
.positive = a.positive,
.limbs = a.limbs[0..req_limbs],
});
r.limbs[r.len - 1] &= mask;
r.normalize(r.len);

Expand Down
25 changes: 25 additions & 0 deletions lib/std/math/big/int_test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1934,6 +1934,31 @@ test "truncate multi unsigned many" {
try testing.expect((try b.toInt(i1)) == 0);
}

test "truncate to mutable with fewer limbs" {
var res_limbs: [1]Limb = undefined;
var res: Mutable = .{
.limbs = &res_limbs,
.len = undefined,
.positive = undefined,
};
res.truncate(.{ .positive = true, .limbs = &.{ 0, 1 } }, .unsigned, @bitSizeOf(Limb));
try testing.expect(res.eqlZero());
res.truncate(.{ .positive = true, .limbs = &.{ 0, 1 } }, .signed, @bitSizeOf(Limb));
try testing.expect(res.eqlZero());
res.truncate(.{ .positive = false, .limbs = &.{ 0, 1 } }, .unsigned, @bitSizeOf(Limb));
try testing.expect(res.eqlZero());
res.truncate(.{ .positive = false, .limbs = &.{ 0, 1 } }, .signed, @bitSizeOf(Limb));
try testing.expect(res.eqlZero());
res.truncate(.{ .positive = true, .limbs = &.{ std.math.maxInt(Limb), 1 } }, .unsigned, @bitSizeOf(Limb));
try testing.expect(res.toConst().orderAgainstScalar(std.math.maxInt(Limb)).compare(.eq));
res.truncate(.{ .positive = true, .limbs = &.{ std.math.maxInt(Limb), 1 } }, .signed, @bitSizeOf(Limb));
try testing.expect(res.toConst().orderAgainstScalar(-1).compare(.eq));
res.truncate(.{ .positive = false, .limbs = &.{ std.math.maxInt(Limb), 1 } }, .unsigned, @bitSizeOf(Limb));
try testing.expect(res.toConst().orderAgainstScalar(1).compare(.eq));
res.truncate(.{ .positive = false, .limbs = &.{ std.math.maxInt(Limb), 1 } }, .signed, @bitSizeOf(Limb));
try testing.expect(res.toConst().orderAgainstScalar(1).compare(.eq));
}

test "saturate single signed positive" {
var a = try Managed.initSet(testing.allocator, 0xBBBB_BBBB);
defer a.deinit();
Expand Down
2 changes: 1 addition & 1 deletion src/Air.zig
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ pub const Inst = struct {
/// and the operand is not a valid value of this type; i.e. equivalent to
/// a safety check based on `.is_named_enum_value`
intcast_safe,
/// Truncate higher bits from an integer, resulting in an integer with the same
/// Truncate higher bits from an integer, resulting in an integer type with the same
/// sign but an equal or smaller number of bits.
/// Uses the `ty_op` field.
trunc,
Expand Down
38 changes: 21 additions & 17 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -23842,23 +23842,27 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
@tagName(dest_info.signedness), operand_ty.fmt(pt),
});
}
if (operand_info.bits < dest_info.bits) {
const msg = msg: {
const msg = try sema.errMsg(
src,
"destination type '{}' has more bits than source type '{}'",
.{ dest_ty.fmt(pt), operand_ty.fmt(pt) },
);
errdefer msg.destroy(sema.gpa);
try sema.errNote(src, msg, "destination type has {d} bits", .{
dest_info.bits,
});
try sema.errNote(operand_src, msg, "operand type has {d} bits", .{
operand_info.bits,
});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(block, msg);
switch (std.math.order(dest_info.bits, operand_info.bits)) {
.gt => {
const msg = msg: {
const msg = try sema.errMsg(
src,
"destination type '{}' has more bits than source type '{}'",
.{ dest_ty.fmt(pt), operand_ty.fmt(pt) },
);
errdefer msg.destroy(sema.gpa);
try sema.errNote(src, msg, "destination type has {d} bits", .{
dest_info.bits,
});
try sema.errNote(operand_src, msg, "operand type has {d} bits", .{
operand_info.bits,
});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(block, msg);
},
.eq => return operand,
.lt => {},
}
}

Expand Down
Loading

0 comments on commit 2d4954a

Please sign in to comment.