Merge pull request #23209 from jacobly0/x86_64-rewrite

x86_64: rewrite wrapping multiplication
This commit is contained in:
Jacob Young 2025-03-23 21:56:58 -04:00 committed by GitHub
commit 98640cbeb8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 26211 additions and 22326 deletions

View File

@ -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(),
};
}
}

View File

@ -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" {

View File

@ -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,

View File

@ -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),

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -592,6 +592,7 @@ pub const Op = enum {
else => unreachable,
},
},
.gphi => .r8,
.segment => .sreg,
.x87 => switch (reg) {
.st0 => .st0,

View File

@ -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,

View File

@ -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)),

View File

@ -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,

View File

@ -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,

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'