mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
Merge pull request #23209 from jacobly0/x86_64-rewrite
x86_64: rewrite wrapping multiplication
This commit is contained in:
commit
98640cbeb8
@ -1096,7 +1096,7 @@ pub const Mutable = struct {
|
||||
/// Asserts there is enough memory to fit the result. The upper bound Limb count is
|
||||
/// `a.limbs.len + (shift / (@sizeOf(Limb) * 8))`.
|
||||
pub fn shiftLeft(r: *Mutable, a: Const, shift: usize) void {
|
||||
llshl(r.limbs[0..], a.limbs[0..a.limbs.len], shift);
|
||||
llshl(r.limbs, a.limbs, shift);
|
||||
r.normalize(a.limbs.len + (shift / limb_bits) + 1);
|
||||
r.positive = a.positive;
|
||||
}
|
||||
@ -1165,7 +1165,7 @@ pub const Mutable = struct {
|
||||
|
||||
// This shift should not be able to overflow, so invoke llshl and normalize manually
|
||||
// to avoid the extra required limb.
|
||||
llshl(r.limbs[0..], a.limbs[0..a.limbs.len], shift);
|
||||
llshl(r.limbs, a.limbs, shift);
|
||||
r.normalize(a.limbs.len + (shift / limb_bits));
|
||||
r.positive = a.positive;
|
||||
}
|
||||
@ -1202,17 +1202,11 @@ pub const Mutable = struct {
|
||||
break :nonzero a.limbs[full_limbs_shifted_out] << not_covered != 0;
|
||||
};
|
||||
|
||||
llshr(r.limbs[0..], a.limbs[0..a.limbs.len], shift);
|
||||
llshr(r.limbs, a.limbs, shift);
|
||||
|
||||
r.len = a.limbs.len - full_limbs_shifted_out;
|
||||
r.positive = a.positive;
|
||||
if (nonzero_negative_shiftout) {
|
||||
if (full_limbs_shifted_out > 0) {
|
||||
r.limbs[a.limbs.len - full_limbs_shifted_out] = 0;
|
||||
r.len += 1;
|
||||
}
|
||||
r.addScalar(r.toConst(), -1);
|
||||
}
|
||||
if (nonzero_negative_shiftout) r.addScalar(r.toConst(), -1);
|
||||
r.normalize(r.len);
|
||||
}
|
||||
|
||||
@ -1755,119 +1749,60 @@ pub const Mutable = struct {
|
||||
y.shiftRight(y.toConst(), norm_shift);
|
||||
}
|
||||
|
||||
/// If a is positive, this passes through to truncate.
|
||||
/// If a is negative, then r is set to positive with the bit pattern ~(a - 1).
|
||||
/// r may alias a.
|
||||
///
|
||||
/// Asserts `r` has enough storage to store the result.
|
||||
/// The upper bound is `calcTwosCompLimbCount(a.len)`.
|
||||
pub fn convertToTwosComplement(r: *Mutable, a: Const, signedness: Signedness, bit_count: usize) void {
|
||||
if (a.positive) {
|
||||
r.truncate(a, signedness, bit_count);
|
||||
return;
|
||||
}
|
||||
|
||||
const req_limbs = calcTwosCompLimbCount(bit_count);
|
||||
if (req_limbs == 0 or a.eqlZero()) {
|
||||
r.set(0);
|
||||
return;
|
||||
}
|
||||
|
||||
const bit = @as(Log2Limb, @truncate(bit_count - 1));
|
||||
const signmask = @as(Limb, 1) << bit;
|
||||
const mask = (signmask << 1) -% 1;
|
||||
|
||||
r.addScalar(a.abs(), -1);
|
||||
if (req_limbs > r.len) {
|
||||
@memset(r.limbs[r.len..req_limbs], 0);
|
||||
}
|
||||
|
||||
assert(r.limbs.len >= req_limbs);
|
||||
r.len = req_limbs;
|
||||
|
||||
llnot(r.limbs[0..r.len]);
|
||||
r.limbs[r.len - 1] &= mask;
|
||||
r.normalize(r.len);
|
||||
}
|
||||
|
||||
/// Truncate an integer to a number of bits, following 2s-complement semantics.
|
||||
/// r may alias a.
|
||||
/// `r` may alias `a`.
|
||||
///
|
||||
/// Asserts `r` has enough storage to store the result.
|
||||
/// Asserts `r` has enough storage to compute the result.
|
||||
/// 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 abs_trunc_a.eqlZero()) {
|
||||
if (bit_count == 0) {
|
||||
@branchHint(.unlikely);
|
||||
r.set(0);
|
||||
return;
|
||||
}
|
||||
|
||||
const bit = @as(Log2Limb, @truncate(bit_count - 1));
|
||||
const signmask = @as(Limb, 1) << bit; // 0b0..010...0 where 1 is the sign bit.
|
||||
const mask = (signmask << 1) -% 1; // 0b0..01..1 where the leftmost 1 is the sign bit.
|
||||
const max_limbs = calcTwosCompLimbCount(bit_count);
|
||||
const sign_bit = @as(Limb, 1) << @truncate(bit_count - 1);
|
||||
const mask = @as(Limb, maxInt(Limb)) >> @truncate(-%bit_count);
|
||||
|
||||
if (!a.positive) {
|
||||
// Convert the integer from sign-magnitude into twos-complement.
|
||||
// -x = ~(x - 1)
|
||||
// Note, we simply take req_limbs * @bitSizeOf(Limb) as the
|
||||
// target bit count.
|
||||
// Guess whether the result will have the same sign as `a`.
|
||||
// * If the result will be signed zero, the guess is `true`.
|
||||
// * If the result will be the minimum signed integer, the guess is `false`.
|
||||
// * If the result will be unsigned zero, the guess is `a.positive`.
|
||||
// * Otherwise the guess is correct.
|
||||
const same_sign_guess = switch (signedness) {
|
||||
.signed => max_limbs > a.limbs.len or a.limbs[max_limbs - 1] & sign_bit == 0,
|
||||
.unsigned => a.positive,
|
||||
};
|
||||
|
||||
r.addScalar(abs_trunc_a, -1);
|
||||
|
||||
// Zero-extend the result
|
||||
@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.
|
||||
// Note that it will be 0 if the result is negative, as we did not apply the flip here.
|
||||
// If the result is negative, we have
|
||||
// -(-x & mask)
|
||||
// = ~(~(x - 1) & mask) + 1
|
||||
// = ~(~((x - 1) | ~mask)) + 1
|
||||
// = ((x - 1) | ~mask)) + 1
|
||||
// Note, this is only valid for the target bits and not the upper bits
|
||||
// of the most significant limb. Those still need to be cleared.
|
||||
// Also note that `mask` is zero for all other bits, reducing to the identity.
|
||||
// This means that we still need to use & mask to clear off the upper bits.
|
||||
|
||||
if (signedness == .signed and r.limbs[r.len - 1] & signmask == 0) {
|
||||
// Re-add the one and negate to get the result.
|
||||
r.limbs[r.len - 1] &= mask;
|
||||
// Note, addition cannot require extra limbs here as we did a subtraction before.
|
||||
r.addScalar(r.toConst(), 1);
|
||||
r.normalize(r.len);
|
||||
r.positive = false;
|
||||
} else {
|
||||
llnot(r.limbs[0..r.len]);
|
||||
r.limbs[r.len - 1] &= mask;
|
||||
r.normalize(r.len);
|
||||
}
|
||||
} else {
|
||||
const abs_trunc_a: Const = .{
|
||||
.positive = true,
|
||||
.limbs = a.limbs[0..llnormalize(a.limbs[0..@min(a.limbs.len, max_limbs)])],
|
||||
};
|
||||
if (same_sign_guess or abs_trunc_a.eqlZero()) {
|
||||
// One of the following is true:
|
||||
// * The result is zero.
|
||||
// * The result is non-zero and has the same sign as `a`.
|
||||
r.copy(abs_trunc_a);
|
||||
// If the integer fits within target bits, no wrapping is required.
|
||||
if (r.len < req_limbs) return;
|
||||
|
||||
r.limbs[r.len - 1] &= mask;
|
||||
if (max_limbs <= r.len) r.limbs[max_limbs - 1] &= mask;
|
||||
r.normalize(r.len);
|
||||
|
||||
if (signedness == .signed and r.limbs[r.len - 1] & signmask != 0) {
|
||||
// Convert 2s-complement back to sign-magnitude.
|
||||
// Sign-extend the upper bits so that they are inverted correctly.
|
||||
r.limbs[r.len - 1] |= ~mask;
|
||||
llnot(r.limbs[0..r.len]);
|
||||
|
||||
// Note, can only overflow if r holds 0xFFF...F which can only happen if
|
||||
// a holds 0.
|
||||
r.addScalar(r.toConst(), 1);
|
||||
|
||||
r.positive = false;
|
||||
}
|
||||
r.positive = a.positive or r.eqlZero();
|
||||
} else {
|
||||
// One of the following is true:
|
||||
// * The result is the minimum signed integer.
|
||||
// * The result is unsigned zero.
|
||||
// * The result is non-zero and has the opposite sign as `a`.
|
||||
r.addScalar(abs_trunc_a, -1);
|
||||
llnot(r.limbs[0..r.len]);
|
||||
@memset(r.limbs[r.len..max_limbs], maxInt(Limb));
|
||||
r.limbs[max_limbs - 1] &= mask;
|
||||
r.normalize(max_limbs);
|
||||
r.positive = switch (signedness) {
|
||||
// The only value with the sign bit still set is the minimum signed integer.
|
||||
.signed => !a.positive and r.limbs[max_limbs - 1] & sign_bit == 0,
|
||||
.unsigned => !a.positive or r.eqlZero(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1020,7 +1020,7 @@ test "mul large" {
|
||||
// Generate a number that's large enough to cross the thresholds for the use
|
||||
// of subquadratic algorithms
|
||||
for (a.limbs) |*p| {
|
||||
p.* = std.math.maxInt(Limb);
|
||||
p.* = maxInt(Limb);
|
||||
}
|
||||
a.setMetadata(true, 50);
|
||||
|
||||
@ -1104,7 +1104,7 @@ test "mulWrap large" {
|
||||
// Generate a number that's large enough to cross the thresholds for the use
|
||||
// of subquadratic algorithms
|
||||
for (a.limbs) |*p| {
|
||||
p.* = std.math.maxInt(Limb);
|
||||
p.* = maxInt(Limb);
|
||||
}
|
||||
a.setMetadata(true, 50);
|
||||
|
||||
@ -1961,23 +1961,78 @@ test "truncate to mutable with fewer limbs" {
|
||||
.positive = undefined,
|
||||
};
|
||||
res.truncate(.{ .positive = true, .limbs = &.{ 0, 1 } }, .unsigned, @bitSizeOf(Limb));
|
||||
try testing.expect(res.eqlZero());
|
||||
try testing.expect(res.positive and res.len == 1 and res.limbs[0] == 0);
|
||||
res.truncate(.{ .positive = true, .limbs = &.{ 0, 1 } }, .signed, @bitSizeOf(Limb));
|
||||
try testing.expect(res.eqlZero());
|
||||
try testing.expect(res.positive and res.len == 1 and res.limbs[0] == 0);
|
||||
res.truncate(.{ .positive = false, .limbs = &.{ 0, 1 } }, .unsigned, @bitSizeOf(Limb));
|
||||
try testing.expect(res.eqlZero());
|
||||
try testing.expect(res.positive and res.len == 1 and res.limbs[0] == 0);
|
||||
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.positive and res.len == 1 and res.limbs[0] == 0);
|
||||
res.truncate(.{ .positive = true, .limbs = &.{ maxInt(Limb), 1 } }, .unsigned, @bitSizeOf(Limb));
|
||||
try testing.expect(res.toConst().orderAgainstScalar(maxInt(Limb)).compare(.eq));
|
||||
res.truncate(.{ .positive = true, .limbs = &.{ 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));
|
||||
res.truncate(.{ .positive = false, .limbs = &.{ 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));
|
||||
res.truncate(.{ .positive = false, .limbs = &.{ maxInt(Limb), 1 } }, .signed, @bitSizeOf(Limb));
|
||||
try testing.expect(res.toConst().orderAgainstScalar(1).compare(.eq));
|
||||
}
|
||||
|
||||
test "truncate value that normalizes after being masked" {
|
||||
var res_limbs: [2]Limb = undefined;
|
||||
var res: Mutable = .{
|
||||
.limbs = &res_limbs,
|
||||
.len = undefined,
|
||||
.positive = undefined,
|
||||
};
|
||||
res.truncate(.{ .positive = true, .limbs = &.{ 0, 2 } }, .signed, 1 + @bitSizeOf(Limb));
|
||||
try testing.expect(res.positive and res.len == 1 and res.limbs[0] == 0);
|
||||
res.truncate(.{ .positive = true, .limbs = &.{ 1, 2 } }, .signed, 1 + @bitSizeOf(Limb));
|
||||
try testing.expect(res.toConst().orderAgainstScalar(1).compare(.eq));
|
||||
}
|
||||
|
||||
test "truncate to zero" {
|
||||
var res_limbs: [1]Limb = undefined;
|
||||
var res: Mutable = .{
|
||||
.limbs = &res_limbs,
|
||||
.len = undefined,
|
||||
.positive = undefined,
|
||||
};
|
||||
res.truncate(.{ .positive = true, .limbs = &.{0} }, .signed, @bitSizeOf(Limb));
|
||||
try testing.expect(res.positive and res.len == 1 and res.limbs[0] == 0);
|
||||
res.truncate(.{ .positive = false, .limbs = &.{0} }, .signed, @bitSizeOf(Limb));
|
||||
try testing.expect(res.positive and res.len == 1 and res.limbs[0] == 0);
|
||||
res.truncate(.{ .positive = true, .limbs = &.{0} }, .unsigned, @bitSizeOf(Limb));
|
||||
try testing.expect(res.positive and res.len == 1 and res.limbs[0] == 0);
|
||||
res.truncate(.{ .positive = false, .limbs = &.{0} }, .unsigned, @bitSizeOf(Limb));
|
||||
try testing.expect(res.positive and res.len == 1 and res.limbs[0] == 0);
|
||||
res.truncate(.{ .positive = true, .limbs = &.{ 0, 1 } }, .signed, @bitSizeOf(Limb));
|
||||
try testing.expect(res.positive and res.len == 1 and res.limbs[0] == 0);
|
||||
res.truncate(.{ .positive = false, .limbs = &.{ 0, 1 } }, .signed, @bitSizeOf(Limb));
|
||||
try testing.expect(res.positive and res.len == 1 and res.limbs[0] == 0);
|
||||
res.truncate(.{ .positive = true, .limbs = &.{ 0, 1 } }, .unsigned, @bitSizeOf(Limb));
|
||||
try testing.expect(res.positive and res.len == 1 and res.limbs[0] == 0);
|
||||
res.truncate(.{ .positive = false, .limbs = &.{ 0, 1 } }, .unsigned, @bitSizeOf(Limb));
|
||||
try testing.expect(res.positive and res.len == 1 and res.limbs[0] == 0);
|
||||
}
|
||||
|
||||
test "truncate to minimum signed integer" {
|
||||
var res_limbs: [1]Limb = undefined;
|
||||
var res: Mutable = .{
|
||||
.limbs = &res_limbs,
|
||||
.len = undefined,
|
||||
.positive = undefined,
|
||||
};
|
||||
res.truncate(.{ .positive = true, .limbs = &.{1 << @bitSizeOf(Limb) - 1} }, .signed, @bitSizeOf(Limb));
|
||||
try testing.expect(res.toConst().orderAgainstScalar(-1 << @bitSizeOf(Limb) - 1).compare(.eq));
|
||||
res.truncate(.{ .positive = false, .limbs = &.{1 << @bitSizeOf(Limb) - 1} }, .signed, @bitSizeOf(Limb));
|
||||
try testing.expect(res.toConst().orderAgainstScalar(-1 << @bitSizeOf(Limb) - 1).compare(.eq));
|
||||
res.truncate(.{ .positive = true, .limbs = &.{1 << @bitSizeOf(Limb) - 1} }, .unsigned, @bitSizeOf(Limb));
|
||||
try testing.expect(res.toConst().orderAgainstScalar(1 << @bitSizeOf(Limb) - 1).compare(.eq));
|
||||
res.truncate(.{ .positive = false, .limbs = &.{1 << @bitSizeOf(Limb) - 1} }, .unsigned, @bitSizeOf(Limb));
|
||||
try testing.expect(res.toConst().orderAgainstScalar(1 << @bitSizeOf(Limb) - 1).compare(.eq));
|
||||
}
|
||||
|
||||
test "saturate single signed positive" {
|
||||
var a = try Managed.initSet(testing.allocator, 0xBBBB_BBBB);
|
||||
defer a.deinit();
|
||||
@ -2136,6 +2191,15 @@ test "shift-right negative" {
|
||||
a.setSign(true);
|
||||
try a.shiftRight(&arg7, 4);
|
||||
try testing.expect(try a.toInt(i16) == -2048);
|
||||
|
||||
var arg8_limbs: [1]Limb = undefined;
|
||||
var arg8: Mutable = .{
|
||||
.limbs = &arg8_limbs,
|
||||
.len = undefined,
|
||||
.positive = undefined,
|
||||
};
|
||||
arg8.shiftRight(.{ .limbs = &.{ 1, 1 }, .positive = false }, @bitSizeOf(Limb));
|
||||
try testing.expect(arg8.toConst().orderAgainstScalar(-2).compare(.eq));
|
||||
}
|
||||
|
||||
test "sat shift-left simple unsigned" {
|
||||
|
||||
@ -2136,7 +2136,7 @@ pub const Inst = struct {
|
||||
ref_start_index = static_len,
|
||||
_,
|
||||
|
||||
pub const static_len = 93;
|
||||
pub const static_len = 97;
|
||||
|
||||
pub fn toRef(i: Index) Inst.Ref {
|
||||
return @enumFromInt(@intFromEnum(Index.ref_start_index) + @intFromEnum(i));
|
||||
@ -2221,6 +2221,10 @@ pub const Inst = struct {
|
||||
slice_const_u8_sentinel_0_type,
|
||||
vector_16_i8_type,
|
||||
vector_32_i8_type,
|
||||
vector_1_u8_type,
|
||||
vector_2_u8_type,
|
||||
vector_4_u8_type,
|
||||
vector_8_u8_type,
|
||||
vector_16_u8_type,
|
||||
vector_32_u8_type,
|
||||
vector_8_i16_type,
|
||||
|
||||
@ -985,6 +985,10 @@ pub const Inst = struct {
|
||||
slice_const_u8_sentinel_0_type = @intFromEnum(InternPool.Index.slice_const_u8_sentinel_0_type),
|
||||
vector_16_i8_type = @intFromEnum(InternPool.Index.vector_16_i8_type),
|
||||
vector_32_i8_type = @intFromEnum(InternPool.Index.vector_32_i8_type),
|
||||
vector_1_u8_type = @intFromEnum(InternPool.Index.vector_1_u8_type),
|
||||
vector_2_u8_type = @intFromEnum(InternPool.Index.vector_2_u8_type),
|
||||
vector_4_u8_type = @intFromEnum(InternPool.Index.vector_4_u8_type),
|
||||
vector_8_u8_type = @intFromEnum(InternPool.Index.vector_8_u8_type),
|
||||
vector_16_u8_type = @intFromEnum(InternPool.Index.vector_16_u8_type),
|
||||
vector_32_u8_type = @intFromEnum(InternPool.Index.vector_32_u8_type),
|
||||
vector_8_i16_type = @intFromEnum(InternPool.Index.vector_8_i16_type),
|
||||
|
||||
@ -4573,6 +4573,10 @@ pub const Index = enum(u32) {
|
||||
|
||||
vector_16_i8_type,
|
||||
vector_32_i8_type,
|
||||
vector_1_u8_type,
|
||||
vector_2_u8_type,
|
||||
vector_4_u8_type,
|
||||
vector_8_u8_type,
|
||||
vector_16_u8_type,
|
||||
vector_32_u8_type,
|
||||
vector_8_i16_type,
|
||||
@ -5089,6 +5093,14 @@ pub const static_keys = [_]Key{
|
||||
.{ .vector_type = .{ .len = 16, .child = .i8_type } },
|
||||
// @Vector(32, i8)
|
||||
.{ .vector_type = .{ .len = 32, .child = .i8_type } },
|
||||
// @Vector(1, u8)
|
||||
.{ .vector_type = .{ .len = 1, .child = .u8_type } },
|
||||
// @Vector(2, u8)
|
||||
.{ .vector_type = .{ .len = 2, .child = .u8_type } },
|
||||
// @Vector(4, u8)
|
||||
.{ .vector_type = .{ .len = 4, .child = .u8_type } },
|
||||
// @Vector(8, u8)
|
||||
.{ .vector_type = .{ .len = 8, .child = .u8_type } },
|
||||
// @Vector(16, u8)
|
||||
.{ .vector_type = .{ .len = 16, .child = .u8_type } },
|
||||
// @Vector(32, u8)
|
||||
@ -11766,6 +11778,10 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
|
||||
.slice_const_u8_sentinel_0_type,
|
||||
.vector_16_i8_type,
|
||||
.vector_32_i8_type,
|
||||
.vector_1_u8_type,
|
||||
.vector_2_u8_type,
|
||||
.vector_4_u8_type,
|
||||
.vector_8_u8_type,
|
||||
.vector_16_u8_type,
|
||||
.vector_32_u8_type,
|
||||
.vector_8_i16_type,
|
||||
@ -12106,6 +12122,10 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
|
||||
|
||||
.vector_16_i8_type,
|
||||
.vector_32_i8_type,
|
||||
.vector_1_u8_type,
|
||||
.vector_2_u8_type,
|
||||
.vector_4_u8_type,
|
||||
.vector_8_u8_type,
|
||||
.vector_16_u8_type,
|
||||
.vector_32_u8_type,
|
||||
.vector_8_i16_type,
|
||||
|
||||
@ -36377,6 +36377,10 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
|
||||
.slice_const_u8_sentinel_0_type,
|
||||
.vector_16_i8_type,
|
||||
.vector_32_i8_type,
|
||||
.vector_1_u8_type,
|
||||
.vector_2_u8_type,
|
||||
.vector_4_u8_type,
|
||||
.vector_8_u8_type,
|
||||
.vector_16_u8_type,
|
||||
.vector_32_u8_type,
|
||||
.vector_8_i16_type,
|
||||
|
||||
@ -4201,6 +4201,10 @@ pub const slice_const_u8_sentinel_0: Type = .{ .ip_index = .slice_const_u8_senti
|
||||
|
||||
pub const vector_16_i8: Type = .{ .ip_index = .vector_16_i8_type };
|
||||
pub const vector_32_i8: Type = .{ .ip_index = .vector_32_i8_type };
|
||||
pub const vector_1_u8: Type = .{ .ip_index = .vector_1_u8_type };
|
||||
pub const vector_2_u8: Type = .{ .ip_index = .vector_2_u8_type };
|
||||
pub const vector_4_u8: Type = .{ .ip_index = .vector_4_u8_type };
|
||||
pub const vector_8_u8: Type = .{ .ip_index = .vector_8_u8_type };
|
||||
pub const vector_16_u8: Type = .{ .ip_index = .vector_16_u8_type };
|
||||
pub const vector_32_u8: Type = .{ .ip_index = .vector_32_u8_type };
|
||||
pub const vector_8_i16: Type = .{ .ip_index = .vector_8_i16_type };
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -592,6 +592,7 @@ pub const Op = enum {
|
||||
else => unreachable,
|
||||
},
|
||||
},
|
||||
.gphi => .r8,
|
||||
.segment => .sreg,
|
||||
.x87 => switch (reg) {
|
||||
.st0 => .st0,
|
||||
|
||||
@ -579,7 +579,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
|
||||
.rrri => inst.data.rrri.fixes,
|
||||
.rri_s, .rri_u => inst.data.rri.fixes,
|
||||
.ri_s, .ri_u, .ri_64, .ir => inst.data.ri.fixes,
|
||||
.rm, .rmi_s, .mr => inst.data.rx.fixes,
|
||||
.rm, .rmi_s, .rmi_u, .mr => inst.data.rx.fixes,
|
||||
.mrr, .rrm, .rmr => inst.data.rrx.fixes,
|
||||
.rmi, .mri => inst.data.rix.fixes,
|
||||
.rrmr => inst.data.rrrx.fixes,
|
||||
|
||||
@ -384,6 +384,7 @@ pub const Register = enum(u8) {
|
||||
|
||||
pub const Class = enum {
|
||||
general_purpose,
|
||||
gphi,
|
||||
segment,
|
||||
x87,
|
||||
mmx,
|
||||
@ -400,7 +401,7 @@ pub const Register = enum(u8) {
|
||||
@intFromEnum(Register.eax) ... @intFromEnum(Register.r15d) => .general_purpose,
|
||||
@intFromEnum(Register.ax) ... @intFromEnum(Register.r15w) => .general_purpose,
|
||||
@intFromEnum(Register.al) ... @intFromEnum(Register.r15b) => .general_purpose,
|
||||
@intFromEnum(Register.ah) ... @intFromEnum(Register.bh) => .general_purpose,
|
||||
@intFromEnum(Register.ah) ... @intFromEnum(Register.bh) => .gphi,
|
||||
|
||||
@intFromEnum(Register.ymm0) ... @intFromEnum(Register.ymm15) => .sse,
|
||||
@intFromEnum(Register.xmm0) ... @intFromEnum(Register.xmm15) => .sse,
|
||||
@ -525,7 +526,6 @@ pub const Register = enum(u8) {
|
||||
}
|
||||
|
||||
fn gpBase(reg: Register) u7 {
|
||||
assert(reg.class() == .general_purpose);
|
||||
return switch (@intFromEnum(reg)) {
|
||||
// zig fmt: off
|
||||
@intFromEnum(Register.rax) ... @intFromEnum(Register.r15) => @intFromEnum(Register.rax),
|
||||
@ -577,7 +577,7 @@ pub const Register = enum(u8) {
|
||||
/// DWARF register encoding
|
||||
pub fn dwarfNum(reg: Register) u6 {
|
||||
return switch (reg.class()) {
|
||||
.general_purpose => if (reg.isExtended())
|
||||
.general_purpose, .gphi => if (reg.isExtended())
|
||||
reg.enc()
|
||||
else
|
||||
@as(u3, @truncate(@as(u24, 0o54673120) >> @as(u5, reg.enc()) * 3)),
|
||||
|
||||
@ -8175,7 +8175,7 @@ fn formatIntLiteral(
|
||||
try writer.writeAll(string);
|
||||
} else {
|
||||
try data.ctype.renderLiteralPrefix(writer, data.kind, ctype_pool);
|
||||
wrap.convertToTwosComplement(int, data.int_info.signedness, c_bits);
|
||||
wrap.truncate(int, .unsigned, c_bits);
|
||||
@memset(wrap.limbs[wrap.len..], 0);
|
||||
wrap.len = wrap.limbs.len;
|
||||
const limbs_per_c_limb = @divExact(wrap.len, c_limb_info.count);
|
||||
@ -8207,7 +8207,6 @@ fn formatIntLiteral(
|
||||
c_limb_int_info.signedness = .signed;
|
||||
c_limb_ctype = c_limb_info.ctype.toSigned();
|
||||
|
||||
c_limb_mut.positive = wrap.positive;
|
||||
c_limb_mut.truncate(
|
||||
c_limb_mut.toConst(),
|
||||
.signed,
|
||||
|
||||
@ -1474,6 +1474,66 @@ pub const Pool = struct {
|
||||
};
|
||||
return pool.fromFields(allocator, .@"struct", &fields, kind);
|
||||
},
|
||||
.vector_1_u8_type => {
|
||||
const vector_ctype = try pool.getVector(allocator, .{
|
||||
.elem_ctype = .u8,
|
||||
.len = 1,
|
||||
});
|
||||
if (!kind.isParameter()) return vector_ctype;
|
||||
var fields = [_]Info.Field{
|
||||
.{
|
||||
.name = .{ .index = .array },
|
||||
.ctype = vector_ctype,
|
||||
.alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
|
||||
},
|
||||
};
|
||||
return pool.fromFields(allocator, .@"struct", &fields, kind);
|
||||
},
|
||||
.vector_2_u8_type => {
|
||||
const vector_ctype = try pool.getVector(allocator, .{
|
||||
.elem_ctype = .u8,
|
||||
.len = 2,
|
||||
});
|
||||
if (!kind.isParameter()) return vector_ctype;
|
||||
var fields = [_]Info.Field{
|
||||
.{
|
||||
.name = .{ .index = .array },
|
||||
.ctype = vector_ctype,
|
||||
.alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
|
||||
},
|
||||
};
|
||||
return pool.fromFields(allocator, .@"struct", &fields, kind);
|
||||
},
|
||||
.vector_4_u8_type => {
|
||||
const vector_ctype = try pool.getVector(allocator, .{
|
||||
.elem_ctype = .u8,
|
||||
.len = 4,
|
||||
});
|
||||
if (!kind.isParameter()) return vector_ctype;
|
||||
var fields = [_]Info.Field{
|
||||
.{
|
||||
.name = .{ .index = .array },
|
||||
.ctype = vector_ctype,
|
||||
.alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
|
||||
},
|
||||
};
|
||||
return pool.fromFields(allocator, .@"struct", &fields, kind);
|
||||
},
|
||||
.vector_8_u8_type => {
|
||||
const vector_ctype = try pool.getVector(allocator, .{
|
||||
.elem_ctype = .u8,
|
||||
.len = 8,
|
||||
});
|
||||
if (!kind.isParameter()) return vector_ctype;
|
||||
var fields = [_]Info.Field{
|
||||
.{
|
||||
.name = .{ .index = .array },
|
||||
.ctype = vector_ctype,
|
||||
.alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
|
||||
},
|
||||
};
|
||||
return pool.fromFields(allocator, .@"struct", &fields, kind);
|
||||
},
|
||||
.vector_16_u8_type => {
|
||||
const vector_ctype = try pool.getVector(allocator, .{
|
||||
.elem_ctype = .u8,
|
||||
|
||||
5759
test/behavior/x86_64/binary.zig
Normal file
5759
test/behavior/x86_64/binary.zig
Normal file
File diff suppressed because it is too large
Load Diff
@ -116,8 +116,10 @@ pub fn build(b: *std.Build) void {
|
||||
const target = b.resolveTargetQuery(query);
|
||||
const cpu = query.serializeCpuAlloc(b.allocator) catch @panic("OOM");
|
||||
for ([_][]const u8{
|
||||
"math.zig",
|
||||
"binary.zig",
|
||||
"cast.zig",
|
||||
"mem.zig",
|
||||
"unary.zig",
|
||||
}) |path| {
|
||||
const test_mod = b.createModule(.{
|
||||
.root_source_file = b.path(path),
|
||||
|
||||
14565
test/behavior/x86_64/cast.zig
Normal file
14565
test/behavior/x86_64/cast.zig
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1820
test/behavior/x86_64/unary.zig
Normal file
1820
test/behavior/x86_64/unary.zig
Normal file
File diff suppressed because it is too large
Load Diff
@ -117,9 +117,9 @@ export fn testMutablePointer() void {
|
||||
// tmp.zig:37:38: note: imported here
|
||||
// neg_inf.zon:1:1: error: expected type '?u8'
|
||||
// tmp.zig:57:28: note: imported here
|
||||
// neg_inf.zon:1:1: error: expected type 'tmp.testNonExhaustiveEnum__enum_487'
|
||||
// neg_inf.zon:1:1: error: expected type 'tmp.testNonExhaustiveEnum__enum_491'
|
||||
// tmp.zig:62:39: note: imported here
|
||||
// neg_inf.zon:1:1: error: expected type 'tmp.testUntaggedUnion__union_489'
|
||||
// neg_inf.zon:1:1: error: expected type 'tmp.testUntaggedUnion__union_493'
|
||||
// tmp.zig:67:44: note: imported here
|
||||
// neg_inf.zon:1:1: error: expected type 'tmp.testTaggedUnionVoid__union_492'
|
||||
// neg_inf.zon:1:1: error: expected type 'tmp.testTaggedUnionVoid__union_496'
|
||||
// tmp.zig:72:50: note: imported here
|
||||
|
||||
@ -15,6 +15,6 @@ pub export fn entry() void {
|
||||
// error
|
||||
//
|
||||
// :7:25: error: unable to resolve comptime value
|
||||
// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_461.C' must be comptime-known
|
||||
// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_465.C' must be comptime-known
|
||||
// :4:16: note: struct requires comptime because of this field
|
||||
// :4:16: note: types are not available at runtime
|
||||
|
||||
@ -16,5 +16,5 @@ pub export fn entry2() void {
|
||||
//
|
||||
// :3:6: error: no field or member function named 'copy' in '[]const u8'
|
||||
// :9:8: error: no field or member function named 'bar' in '@TypeOf(.{})'
|
||||
// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_465'
|
||||
// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_469'
|
||||
// :12:6: note: struct declared here
|
||||
|
||||
@ -6,6 +6,6 @@ export fn foo() void {
|
||||
|
||||
// error
|
||||
//
|
||||
// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_454'
|
||||
// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_458'
|
||||
// :3:16: note: struct declared here
|
||||
// :1:11: note: struct declared here
|
||||
|
||||
@ -44,9 +44,9 @@ comptime {
|
||||
//
|
||||
// :5:23: error: expected error union type, found 'comptime_int'
|
||||
// :10:23: error: expected error union type, found '@TypeOf(.{})'
|
||||
// :15:23: error: expected error union type, found 'tmp.test2__struct_491'
|
||||
// :15:23: error: expected error union type, found 'tmp.test2__struct_495'
|
||||
// :15:23: note: struct declared here
|
||||
// :20:27: error: expected error union type, found 'tmp.test3__struct_493'
|
||||
// :20:27: error: expected error union type, found 'tmp.test3__struct_497'
|
||||
// :20:27: note: struct declared here
|
||||
// :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }'
|
||||
// :31:13: error: expected error union type, found 'u32'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user