x86_64: testing

This commit is contained in:
Jacob Young 2024-12-01 23:53:22 -05:00
parent 7c713251ca
commit c4b93555b0
12 changed files with 2403 additions and 955 deletions

View file

@ -1229,7 +1229,7 @@ pub const VectorCmp = struct {
op: u32, op: u32,
pub fn compareOperator(self: VectorCmp) std.math.CompareOperator { pub fn compareOperator(self: VectorCmp) std.math.CompareOperator {
return @as(std.math.CompareOperator, @enumFromInt(@as(u3, @truncate(self.op)))); return @enumFromInt(@as(u3, @intCast(self.op)));
} }
pub fn encodeOp(compare_operator: std.math.CompareOperator) u32 { pub fn encodeOp(compare_operator: std.math.CompareOperator) u32 {
@ -1274,11 +1274,11 @@ pub const Cmpxchg = struct {
flags: u32, flags: u32,
pub fn successOrder(self: Cmpxchg) std.builtin.AtomicOrder { pub fn successOrder(self: Cmpxchg) std.builtin.AtomicOrder {
return @as(std.builtin.AtomicOrder, @enumFromInt(@as(u3, @truncate(self.flags)))); return @enumFromInt(@as(u3, @truncate(self.flags)));
} }
pub fn failureOrder(self: Cmpxchg) std.builtin.AtomicOrder { pub fn failureOrder(self: Cmpxchg) std.builtin.AtomicOrder {
return @as(std.builtin.AtomicOrder, @enumFromInt(@as(u3, @truncate(self.flags >> 3)))); return @enumFromInt(@as(u3, @intCast(self.flags >> 3)));
} }
}; };
@ -1289,11 +1289,11 @@ pub const AtomicRmw = struct {
flags: u32, flags: u32,
pub fn ordering(self: AtomicRmw) std.builtin.AtomicOrder { pub fn ordering(self: AtomicRmw) std.builtin.AtomicOrder {
return @as(std.builtin.AtomicOrder, @enumFromInt(@as(u3, @truncate(self.flags)))); return @enumFromInt(@as(u3, @truncate(self.flags)));
} }
pub fn op(self: AtomicRmw) std.builtin.AtomicRmwOp { pub fn op(self: AtomicRmw) std.builtin.AtomicRmwOp {
return @as(std.builtin.AtomicRmwOp, @enumFromInt(@as(u4, @truncate(self.flags >> 3)))); return @enumFromInt(@as(u4, @intCast(self.flags >> 3)));
} }
}; };

File diff suppressed because it is too large Load diff

View file

@ -223,7 +223,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
.op3 = op3, .op3 = op3,
}); });
}, },
.rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr => unreachable, // TODO .rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => unreachable, // TODO
} }
} }

View file

@ -177,7 +177,7 @@ pub fn format(
try writer.print("+{s} ", .{tag}); try writer.print("+{s} ", .{tag});
}, },
.m, .mi, .m1, .mc, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}), .m, .mi, .m1, .mc, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}),
.mr, .rm, .rmi, .mri, .mrc, .rm0, .rvm, .rvmr, .rvmi, .mvr => try writer.writeAll("/r "), .mr, .rm, .rmi, .mri, .mrc, .rm0, .rvm, .rvmr, .rvmi, .mvr, .rmv => try writer.writeAll("/r "),
} }
switch (encoding.data.op_en) { switch (encoding.data.op_en) {
@ -202,7 +202,7 @@ pub fn format(
try writer.print("{s} ", .{tag}); try writer.print("{s} ", .{tag});
}, },
.rvmr => try writer.writeAll("/is4 "), .rvmr => try writer.writeAll("/is4 "),
.zo, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc, .rm0, .rvm, .mvr => {}, .zo, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc, .rm0, .rvm, .mvr, .rmv => {},
} }
try writer.print("{s} ", .{@tagName(encoding.mnemonic)}); try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
@ -260,10 +260,10 @@ pub const Mnemonic = enum {
neg, nop, not, neg, nop, not,
@"or", @"or",
pause, pop, popcnt, popfq, push, pushfq, pause, pop, popcnt, popfq, push, pushfq,
rcl, rcr, ret, rol, ror, rcl, rcr, ret, rol, ror, rorx,
sal, sar, sbb, sal, sar, sarx, sbb,
scas, scasb, scasd, scasq, scasw, scas, scasb, scasd, scasq, scasw,
shl, shld, shr, shrd, sub, syscall, shl, shld, shlx, shr, shrd, shrx, sub, syscall,
seta, setae, setb, setbe, setc, sete, setg, setge, setl, setle, setna, setnae, seta, setae, setb, setbe, setc, sete, setg, setge, setl, setle, setna, setnae,
setnb, setnbe, setnc, setne, setng, setnge, setnl, setnle, setno, setnp, setns, setnb, setnbe, setnc, setne, setng, setnge, setnl, setnle, setno, setnp, setns,
setnz, seto, setp, setpe, setpo, sets, setz, setnz, seto, setp, setpe, setpo, sets, setz,
@ -444,7 +444,7 @@ pub const OpEn = enum {
fd, td, fd, td,
m1, mc, mi, mr, rm, m1, mc, mi, mr, rm,
rmi, mri, mrc, rmi, mri, mrc,
rm0, vmi, rvm, rvmr, rvmi, mvr, rm0, vmi, rvm, rvmr, rvmi, mvr, rmv,
// zig fmt: on // zig fmt: on
}; };
@ -808,6 +808,7 @@ pub const Feature = enum {
avx, avx,
avx2, avx2,
bmi, bmi,
bmi2,
f16c, f16c,
fma, fma,
lzcnt, lzcnt,

View file

@ -29,10 +29,14 @@ pub const Inst = struct {
_l, _l,
/// ___ Left Double /// ___ Left Double
_ld, _ld,
/// ___ Left Without Affecting Flags
_lx,
/// ___ Right /// ___ Right
_r, _r,
/// ___ Right Double /// ___ Right Double
_rd, _rd,
/// ___ Right Without Affecting Flags
_rx,
/// ___ Above /// ___ Above
_a, _a,
@ -401,9 +405,11 @@ pub const Inst = struct {
ret, ret,
/// Rotate left /// Rotate left
/// Rotate right /// Rotate right
/// Rotate right logical without affecting flags
ro, ro,
/// Arithmetic shift left /// Arithmetic shift left
/// Arithmetic shift right /// Arithmetic shift right
/// Shift left arithmetic without affecting flags
sa, sa,
/// Integer subtraction with borrow /// Integer subtraction with borrow
sbb, sbb,
@ -417,6 +423,8 @@ pub const Inst = struct {
/// Double precision shift left /// Double precision shift left
/// Logical shift right /// Logical shift right
/// Double precision shift right /// Double precision shift right
/// Shift left logical without affecting flags
/// Shift right logical without affecting flags
sh, sh,
/// Subtract /// Subtract
/// Subtract packed integers /// Subtract packed integers

View file

@ -242,8 +242,12 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: std.Target, ctx: Context) [8
.sse, .sseup, .sseup, .sseup, .sse, .sseup, .sseup, .sseup,
.sseup, .sseup, .sseup, .none, .sseup, .sseup, .sseup, .none,
}; };
// LLVM always returns vectors byval if (bits <= 512 or (ctx == .ret and bits <= @as(u64, if (std.Target.x86.featureSetHas(target.cpu.features, .avx512f))
if (bits <= 512 or ctx == .ret) return .{ 2048
else if (std.Target.x86.featureSetHas(target.cpu.features, .avx))
1024
else
512))) return .{
.sse, .sseup, .sseup, .sseup, .sse, .sseup, .sseup, .sseup,
.sseup, .sseup, .sseup, .sseup, .sseup, .sseup, .sseup, .sseup,
}; };
@ -416,7 +420,7 @@ pub const SysV = struct {
pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 }; pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
pub const c_abi_sse_param_regs = sse_avx_regs[0..8].*; pub const c_abi_sse_param_regs = sse_avx_regs[0..8].*;
pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx }; pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
pub const c_abi_sse_return_regs = sse_avx_regs[0..2].*; pub const c_abi_sse_return_regs = sse_avx_regs[0..4].*;
}; };
pub const Win64 = struct { pub const Win64 = struct {
@ -496,7 +500,7 @@ pub fn getCAbiSseReturnRegs(cc: std.builtin.CallingConvention) []const Register
} }
const gp_regs = [_]Register{ const gp_regs = [_]Register{
.rax, .rcx, .rdx, .rbx, .rsi, .rdi, .r8, .r9, .r10, .r11, .r12, .r13, .r14, .r15, .rax, .rdx, .rbx, .rcx, .rsi, .rdi, .r8, .r9, .r10, .r11, .r12, .r13, .r14, .r15,
}; };
const x87_regs = [_]Register{ const x87_regs = [_]Register{
.st0, .st1, .st2, .st3, .st4, .st5, .st6, .st7, .st0, .st1, .st2, .st3, .st4, .st5, .st6, .st7,

View file

@ -403,7 +403,7 @@ pub const Instruction = struct {
else => { else => {
const mem_op = switch (data.op_en) { const mem_op = switch (data.op_en) {
.m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0], .m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
.rm, .rmi, .rm0, .vmi => inst.ops[1], .rm, .rmi, .rm0, .vmi, .rmv => inst.ops[1],
.rvm, .rvmr, .rvmi => inst.ops[2], .rvm, .rvmr, .rvmi => inst.ops[2],
else => unreachable, else => unreachable,
}; };
@ -412,7 +412,7 @@ pub const Instruction = struct {
const rm = switch (data.op_en) { const rm = switch (data.op_en) {
.m, .mi, .m1, .mc, .vmi => enc.modRmExt(), .m, .mi, .m1, .mc, .vmi => enc.modRmExt(),
.mr, .mri, .mrc => inst.ops[1].reg.lowEnc(), .mr, .mri, .mrc => inst.ops[1].reg.lowEnc(),
.rm, .rmi, .rm0, .rvm, .rvmr, .rvmi => inst.ops[0].reg.lowEnc(), .rm, .rmi, .rm0, .rvm, .rvmr, .rvmi, .rmv => inst.ops[0].reg.lowEnc(),
.mvr => inst.ops[2].reg.lowEnc(), .mvr => inst.ops[2].reg.lowEnc(),
else => unreachable, else => unreachable,
}; };
@ -422,7 +422,7 @@ pub const Instruction = struct {
const op = switch (data.op_en) { const op = switch (data.op_en) {
.m, .mi, .m1, .mc, .vmi => .none, .m, .mi, .m1, .mc, .vmi => .none,
.mr, .mri, .mrc => inst.ops[1], .mr, .mri, .mrc => inst.ops[1],
.rm, .rmi, .rm0, .rvm, .rvmr, .rvmi => inst.ops[0], .rm, .rmi, .rm0, .rvm, .rvmr, .rvmi, .rmv => inst.ops[0],
.mvr => inst.ops[2], .mvr => inst.ops[2],
else => unreachable, else => unreachable,
}; };
@ -493,7 +493,7 @@ pub const Instruction = struct {
} }
else else
null, null,
.vmi, .rvm, .rvmr, .rvmi, .mvr => unreachable, .vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => unreachable,
}; };
if (segment_override) |seg| { if (segment_override) |seg| {
legacy.setSegmentOverride(seg); legacy.setSegmentOverride(seg);
@ -512,9 +512,9 @@ pub const Instruction = struct {
switch (op_en) { switch (op_en) {
.zo, .i, .zi, .fd, .td, .d => {}, .zo, .i, .zi, .fd, .td, .d => {},
.o, .oi => rex.b = inst.ops[0].reg.isExtended(), .o, .oi => rex.b = inst.ops[0].reg.isExtended(),
.m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0 => { .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0, .rmv => {
const r_op = switch (op_en) { const r_op = switch (op_en) {
.rm, .rmi, .rm0 => inst.ops[0], .rm, .rmi, .rm0, .rmv => inst.ops[0],
.mr, .mri, .mrc => inst.ops[1], .mr, .mri, .mrc => inst.ops[1],
else => .none, else => .none,
}; };
@ -546,9 +546,9 @@ pub const Instruction = struct {
switch (op_en) { switch (op_en) {
.zo, .i, .zi, .fd, .td, .d => {}, .zo, .i, .zi, .fd, .td, .d => {},
.o, .oi => vex.b = inst.ops[0].reg.isExtended(), .o, .oi => vex.b = inst.ops[0].reg.isExtended(),
.m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr => { .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => {
const r_op = switch (op_en) { const r_op = switch (op_en) {
.rm, .rmi, .rm0, .rvm, .rvmr, .rvmi => inst.ops[0], .rm, .rmi, .rm0, .rvm, .rvmr, .rvmi, .rmv => inst.ops[0],
.mr, .mri, .mrc => inst.ops[1], .mr, .mri, .mrc => inst.ops[1],
.mvr => inst.ops[2], .mvr => inst.ops[2],
.m, .mi, .m1, .mc, .vmi => .none, .m, .mi, .m1, .mc, .vmi => .none,
@ -557,7 +557,7 @@ pub const Instruction = struct {
vex.r = r_op.isBaseExtended(); vex.r = r_op.isBaseExtended();
const b_x_op = switch (op_en) { const b_x_op = switch (op_en) {
.rm, .rmi, .rm0, .vmi => inst.ops[1], .rm, .rmi, .rm0, .vmi, .rmv => inst.ops[1],
.m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0], .m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
.rvm, .rvmr, .rvmi => inst.ops[2], .rvm, .rvmr, .rvmi => inst.ops[2],
else => unreachable, else => unreachable,
@ -588,6 +588,7 @@ pub const Instruction = struct {
else => {}, else => {},
.vmi => vex.v = inst.ops[0].reg, .vmi => vex.v = inst.ops[0].reg,
.rvm, .rvmr, .rvmi => vex.v = inst.ops[1].reg, .rvm, .rvmr, .rvmi => vex.v = inst.ops[1].reg,
.rmv => vex.v = inst.ops[2].reg,
} }
try encoder.vex(vex); try encoder.vex(vex);

View file

@ -1287,6 +1287,16 @@ pub const table = [_]Entry{
.{ .sha256rnds2, .rm0, &.{ .xmm, .xmm_m128, .xmm0 }, &.{ 0x0f, 0x38, 0xcb }, 0, .none, .sha }, .{ .sha256rnds2, .rm0, &.{ .xmm, .xmm_m128, .xmm0 }, &.{ 0x0f, 0x38, 0xcb }, 0, .none, .sha },
// AVX // AVX
.{ .rorx, .rmi, &.{ .r32, .rm32, .imm8 }, &.{ 0xf2, 0x0f, 0x3a }, 0, .vex_lz_w0, .bmi2 },
.{ .rorx, .rmi, &.{ .r64, .rm64, .imm8 }, &.{ 0xf2, 0x0f, 0x3a }, 0, .vex_lz_w1, .bmi2 },
.{ .sarx, .rmv, &.{ .r32, .rm32, .r32 }, &.{ 0xf3, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w0, .bmi2 },
.{ .shlx, .rmv, &.{ .r32, .rm32, .r32 }, &.{ 0x66, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w0, .bmi2 },
.{ .shrx, .rmv, &.{ .r32, .rm32, .r32 }, &.{ 0xf2, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w0, .bmi2 },
.{ .sarx, .rmv, &.{ .r64, .rm64, .r64 }, &.{ 0xf3, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w1, .bmi2 },
.{ .shlx, .rmv, &.{ .r64, .rm64, .r64 }, &.{ 0x66, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w1, .bmi2 },
.{ .shrx, .rmv, &.{ .r64, .rm64, .r64 }, &.{ 0xf2, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w1, .bmi2 },
.{ .vaddpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x58 }, 0, .vex_128_wig, .avx }, .{ .vaddpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x58 }, 0, .vex_128_wig, .avx },
.{ .vaddpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x58 }, 0, .vex_256_wig, .avx }, .{ .vaddpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x58 }, 0, .vex_256_wig, .avx },

View file

@ -112,6 +112,9 @@ pub fn RegisterManager(
pub fn indexOfRegIntoTracked(reg: Register) ?TrackedIndex { pub fn indexOfRegIntoTracked(reg: Register) ?TrackedIndex {
return indexOfReg(tracked_registers, reg); return indexOfReg(tracked_registers, reg);
} }
pub inline fn indexOfKnownRegIntoTracked(comptime reg: Register) ?TrackedIndex {
return comptime indexOfRegIntoTracked(reg);
}
pub fn regAtTrackedIndex(tracked_index: TrackedIndex) Register { pub fn regAtTrackedIndex(tracked_index: TrackedIndex) Register {
return tracked_registers[tracked_index]; return tracked_registers[tracked_index];
@ -124,6 +127,9 @@ pub fn RegisterManager(
pub fn isRegFree(self: Self, reg: Register) bool { pub fn isRegFree(self: Self, reg: Register) bool {
return self.isRegIndexFree(indexOfRegIntoTracked(reg) orelse return true); return self.isRegIndexFree(indexOfRegIntoTracked(reg) orelse return true);
} }
pub fn isKnownRegFree(self: Self, comptime reg: Register) bool {
return self.isRegIndexFree(indexOfKnownRegIntoTracked(reg) orelse return true);
}
/// Returns whether this register was allocated in the course /// Returns whether this register was allocated in the course
/// of this function. /// of this function.
@ -143,6 +149,9 @@ pub fn RegisterManager(
pub fn isRegLocked(self: Self, reg: Register) bool { pub fn isRegLocked(self: Self, reg: Register) bool {
return self.isRegIndexLocked(indexOfRegIntoTracked(reg) orelse return false); return self.isRegIndexLocked(indexOfRegIntoTracked(reg) orelse return false);
} }
pub fn isKnownRegLocked(self: Self, comptime reg: Register) bool {
return self.isRegIndexLocked(indexOfKnownRegIntoTracked(reg) orelse return false);
}
pub const RegisterLock = struct { tracked_index: TrackedIndex }; pub const RegisterLock = struct { tracked_index: TrackedIndex };
@ -176,6 +185,9 @@ pub fn RegisterManager(
pub fn lockRegAssumeUnused(self: *Self, reg: Register) RegisterLock { pub fn lockRegAssumeUnused(self: *Self, reg: Register) RegisterLock {
return self.lockRegIndexAssumeUnused(indexOfRegIntoTracked(reg) orelse unreachable); return self.lockRegIndexAssumeUnused(indexOfRegIntoTracked(reg) orelse unreachable);
} }
pub fn lockKnownRegAssumeUnused(self: *Self, comptime reg: Register) RegisterLock {
return self.lockRegIndexAssumeUnused(indexOfKnownRegIntoTracked(reg) orelse unreachable);
}
/// Like `lockReg` but locks multiple registers. /// Like `lockReg` but locks multiple registers.
pub fn lockRegs( pub fn lockRegs(
@ -366,7 +378,7 @@ pub fn RegisterManager(
comptime reg: Register, comptime reg: Register,
inst: ?Air.Inst.Index, inst: ?Air.Inst.Index,
) AllocationError!void { ) AllocationError!void {
return self.getRegIndex((comptime indexOfRegIntoTracked(reg)) orelse return, inst); return self.getRegIndex(indexOfKnownRegIntoTracked(reg) orelse return, inst);
} }
/// Allocates the specified register with the specified /// Allocates the specified register with the specified

View file

@ -110,6 +110,8 @@ test {
_ = @import("behavior/widening.zig"); _ = @import("behavior/widening.zig");
_ = @import("behavior/abs.zig"); _ = @import("behavior/abs.zig");
_ = @import("behavior/x86_64.zig");
if (builtin.cpu.arch == .wasm32) { if (builtin.cpu.arch == .wasm32) {
_ = @import("behavior/wasm.zig"); _ = @import("behavior/wasm.zig");
} }

9
test/behavior/x86_64.zig Normal file
View file

@ -0,0 +1,9 @@
//! CodeGen tests for the x86_64 backend.
const builtin = @import("builtin");
test {
if (builtin.zig_backend != .stage2_x86_64) return error.SkipZigTest;
if (builtin.object_format == .coff) return error.SkipZigTest;
_ = @import("x86_64/math.zig");
}

View file

@ -0,0 +1,230 @@
fn testBinary(comptime op: anytype) !void {
const testType = struct {
fn testType(comptime Type: type, comptime imm_lhs: Type, comptime imm_rhs: Type) !void {
const expected = op(Type, imm_lhs, imm_rhs);
try struct {
fn testOne(actual: @TypeOf(expected)) !void {
if (switch (@typeInfo(@TypeOf(expected))) {
else => actual != expected,
.vector => @reduce(.Or, actual != expected),
}) return error.Unexpected;
}
noinline fn testOps(mem_lhs: Type, mem_rhs: Type) !void {
var reg_lhs = mem_lhs;
var reg_rhs = mem_rhs;
_ = .{ &reg_lhs, &reg_rhs };
try testOne(op(Type, reg_lhs, reg_rhs));
try testOne(op(Type, reg_lhs, mem_rhs));
try testOne(op(Type, reg_lhs, imm_rhs));
try testOne(op(Type, mem_lhs, reg_rhs));
try testOne(op(Type, mem_lhs, mem_rhs));
try testOne(op(Type, mem_lhs, imm_rhs));
try testOne(op(Type, imm_lhs, reg_rhs));
try testOne(op(Type, imm_lhs, mem_rhs));
}
}.testOps(imm_lhs, imm_rhs);
}
}.testType;
try testType(u8, 0xbb, 0x43);
try testType(u16, 0xb8bf, 0x626d);
try testType(u32, 0x80d7a2c6, 0xbff6a402);
try testType(u64, 0x71138bc6b4a38898, 0x1bc4043de9438c7b);
try testType(u128, 0xe05fc132ef2cd8affee00a907f0a851f, 0x29f912a72cfc6a7c6973426a9636da9a);
try testType(@Vector(16, u8), .{
0xea, 0x80, 0xbb, 0xe8, 0x74, 0x81, 0xc8, 0x66, 0x7b, 0x41, 0x90, 0xcb, 0x30, 0x70, 0x4b, 0x0f,
}, .{
0x61, 0x26, 0xbe, 0x47, 0x00, 0x9c, 0x55, 0xa5, 0x59, 0xf0, 0xb2, 0x20, 0x30, 0xaf, 0x82, 0x3e,
});
try testType(@Vector(32, u8), .{
0xa1, 0x88, 0xc4, 0xf4, 0x77, 0x0b, 0xf5, 0xbb, 0x09, 0x03, 0xbf, 0xf5, 0xcc, 0x7f, 0x6b, 0x2a,
0x4c, 0x05, 0x37, 0xc9, 0x8a, 0xcb, 0x91, 0x23, 0x09, 0x5f, 0xb8, 0x99, 0x4a, 0x75, 0x26, 0xe4,
}, .{
0xff, 0x0f, 0x99, 0x49, 0xa6, 0x25, 0xa7, 0xd4, 0xc9, 0x2f, 0x97, 0x6a, 0x01, 0xd6, 0x6e, 0x41,
0xa4, 0xb5, 0x3c, 0x03, 0xea, 0x82, 0x9c, 0x5f, 0xac, 0x07, 0x16, 0x15, 0x1c, 0x64, 0x25, 0x2f,
});
try testType(@Vector(64, u8), .{
0xaa, 0x08, 0xeb, 0xb2, 0xd7, 0x89, 0x0f, 0x98, 0xda, 0x9f, 0xa6, 0x4e, 0x3c, 0xce, 0x1b, 0x1b,
0x9e, 0x5f, 0x2b, 0xd6, 0x59, 0x26, 0x47, 0x05, 0x2a, 0xb7, 0xd1, 0x10, 0xde, 0xd9, 0x84, 0x00,
0x07, 0xc0, 0xaa, 0x6e, 0xfa, 0x3b, 0x97, 0x85, 0xa8, 0x42, 0xd7, 0xa5, 0x90, 0xe6, 0x10, 0x1a,
0x47, 0x84, 0xe1, 0x3e, 0xb0, 0x70, 0x26, 0x3f, 0xea, 0x24, 0xb8, 0x5f, 0xe3, 0xe3, 0x4c, 0xed,
}, .{
0x3b, 0xc5, 0xe0, 0x3d, 0x4f, 0x2e, 0x1d, 0xa9, 0xf7, 0x7b, 0xc7, 0xc1, 0x48, 0xc6, 0xe5, 0x9e,
0x4d, 0xa8, 0x21, 0x37, 0xa1, 0x1a, 0x95, 0x69, 0x89, 0x2f, 0x15, 0x07, 0x3d, 0x7b, 0x69, 0x89,
0xea, 0x87, 0xf0, 0x94, 0x67, 0xf2, 0x3d, 0x04, 0x96, 0x8a, 0xd6, 0x70, 0x7c, 0x16, 0xe7, 0x62,
0xf0, 0x8d, 0x96, 0x65, 0xd1, 0x4a, 0x35, 0x3e, 0x7a, 0x67, 0xa6, 0x1f, 0x37, 0x66, 0xe3, 0x45,
});
try testType(@Vector(128, u8), .{
0xa1, 0xd0, 0x7b, 0xf9, 0x7b, 0x77, 0x7b, 0x3d, 0x2d, 0x68, 0xc2, 0x7b, 0xb0, 0xb8, 0xd4, 0x7c,
0x1a, 0x1f, 0xd2, 0x92, 0x3e, 0xcb, 0xc1, 0x6b, 0xb9, 0x4d, 0xf1, 0x67, 0x58, 0x8e, 0x77, 0xa6,
0xb9, 0xdf, 0x10, 0x6f, 0xbe, 0xe3, 0x33, 0xb6, 0x93, 0x77, 0x80, 0xef, 0x09, 0x9d, 0x61, 0x40,
0xa2, 0xf4, 0x52, 0x18, 0x9d, 0xe4, 0xb0, 0xaf, 0x0a, 0xa7, 0x0b, 0x09, 0x67, 0x38, 0x71, 0x04,
0x72, 0xa1, 0xd2, 0xfd, 0xf8, 0xf0, 0xa7, 0x23, 0x24, 0x5b, 0x7d, 0xfb, 0x43, 0xba, 0x6c, 0xc4,
0x83, 0x46, 0x0e, 0x4d, 0x6c, 0x92, 0xab, 0x4f, 0xd2, 0x70, 0x9d, 0xfe, 0xce, 0xf8, 0x05, 0x9f,
0x98, 0x36, 0x9c, 0x90, 0x9a, 0xd0, 0xb5, 0x76, 0x16, 0xe8, 0x25, 0xc2, 0xbd, 0x91, 0xab, 0xf9,
0x6f, 0x6c, 0xc5, 0x60, 0xe5, 0x30, 0xf2, 0xb7, 0x59, 0xc4, 0x9c, 0xdd, 0xdf, 0x04, 0x65, 0xd9,
}, .{
0xed, 0xe1, 0x8a, 0xf6, 0xf3, 0x8b, 0xfd, 0x1d, 0x3c, 0x87, 0xbf, 0xfe, 0x04, 0x52, 0x15, 0x82,
0x0b, 0xb0, 0xcf, 0xcf, 0xf8, 0x03, 0x9c, 0xef, 0xc1, 0x76, 0x7e, 0xe3, 0xe9, 0xa8, 0x18, 0x90,
0xd4, 0xc4, 0x91, 0x15, 0x68, 0x7f, 0x65, 0xd8, 0xe1, 0xb3, 0x23, 0xc2, 0x7d, 0x84, 0x3b, 0xaf,
0x74, 0x69, 0x07, 0x2a, 0x1b, 0x5f, 0x0e, 0x44, 0x0d, 0x2b, 0x9c, 0x82, 0x41, 0xf9, 0x7f, 0xb5,
0xc4, 0xd9, 0xcb, 0xd3, 0xc5, 0x31, 0x8b, 0x5f, 0xda, 0x09, 0x9b, 0x29, 0xa3, 0xb7, 0x13, 0x0d,
0x55, 0x9b, 0x59, 0x33, 0x2a, 0x59, 0x3a, 0x44, 0x1f, 0xd3, 0x40, 0x4e, 0xde, 0x2c, 0xe4, 0x16,
0xfd, 0xc3, 0x02, 0x74, 0xaa, 0x65, 0xfd, 0xc8, 0x2a, 0x8a, 0xdb, 0xae, 0x44, 0x28, 0x62, 0xa4,
0x56, 0x4f, 0xf1, 0xaa, 0x0a, 0x0f, 0xdb, 0x1b, 0xc8, 0x45, 0x9b, 0x12, 0xb4, 0x1a, 0xe4, 0xa3,
});
try testType(@Vector(8, u16), .{
0xcf61, 0xb121, 0x3cf1, 0x3e9f, 0x43a7, 0x8d69, 0x96f5, 0xc11e,
}, .{
0xee30, 0x82f0, 0x270b, 0x1498, 0x4c60, 0x6e72, 0x0b64, 0x02d4,
});
try testType(@Vector(16, u16), .{
0x9191, 0xd23e, 0xf844, 0xd84a, 0xe907, 0xf1e8, 0x712d, 0x90af,
0x6541, 0x3fa6, 0x92eb, 0xe35a, 0xc0c9, 0xcb47, 0xb790, 0x4453,
}, .{
0x21c3, 0x4039, 0x9b71, 0x60bd, 0xcd7f, 0x2ec8, 0x50ba, 0xe810,
0xebd4, 0x06e5, 0xed18, 0x2f66, 0x7e31, 0xe282, 0xad63, 0xb25e,
});
try testType(@Vector(32, u16), .{
0x6b6a, 0x30a9, 0xc267, 0x2231, 0xbf4c, 0x00bc, 0x9c2c, 0x2928,
0xecad, 0x82df, 0xcfb0, 0xa4e5, 0x909b, 0x1b05, 0xaf40, 0x1fd9,
0xcec6, 0xd8dc, 0xd4b5, 0x6d59, 0x8e3f, 0x4d8a, 0xb83a, 0x808e,
0x47e2, 0x5782, 0x59bf, 0xcefc, 0x5179, 0x3f48, 0x93dc, 0x66d2,
}, .{
0x1be8, 0xe98c, 0xf9b3, 0xb008, 0x2f8d, 0xf087, 0xc9b9, 0x75aa,
0xbd16, 0x9540, 0xc5bd, 0x2b2c, 0xd43f, 0x9394, 0x3e1d, 0xf695,
0x167d, 0xff7a, 0xf09d, 0xdff8, 0xdfa2, 0xc779, 0x70b7, 0x01bd,
0x46b3, 0x995a, 0xb7bc, 0xa79d, 0x5542, 0x961e, 0x37cd, 0x9c2a,
});
try testType(@Vector(64, u16), .{
0x6b87, 0xfd84, 0x436b, 0xe345, 0xfb82, 0x81fc, 0x0992, 0x45f9,
0x5527, 0x1f6d, 0xda46, 0x6a16, 0xf6e1, 0x8fb7, 0x3619, 0xdfe3,
0x64ce, 0x8ac6, 0x3ae8, 0x30e3, 0xec3b, 0x4ba7, 0x02a4, 0xa694,
0x8e68, 0x8f0c, 0x5e30, 0x0e55, 0x6538, 0x9852, 0xea35, 0x7be2,
0xdabd, 0x57e6, 0x5b38, 0x0fb2, 0x2604, 0x85e7, 0x6595, 0x8de9,
0x49b1, 0xe9a2, 0x3758, 0xa4d9, 0x505b, 0xc9d3, 0xddc5, 0x9a43,
0xfd44, 0x50f5, 0x379e, 0x03b6, 0x6375, 0x692f, 0x5586, 0xc717,
0x94dd, 0xee06, 0xb32d, 0x0bb9, 0x0e35, 0x5f8f, 0x0ba4, 0x19a8,
}, .{
0xbeeb, 0x3e54, 0x6486, 0x5167, 0xe432, 0x57cf, 0x9cac, 0x922e,
0xd2f8, 0x5614, 0x2e7f, 0x19cf, 0x9a07, 0x0524, 0x168f, 0x4464,
0x4def, 0x83ce, 0x97b4, 0xf269, 0xda5f, 0x28c1, 0x9cc3, 0xfa7c,
0x25a0, 0x912d, 0x25b2, 0xd60d, 0xcd82, 0x0e03, 0x40cc, 0xc9dc,
0x18eb, 0xc609, 0xb06d, 0x29e0, 0xf3c7, 0x997b, 0x8ca2, 0xa750,
0xc9bc, 0x8f0e, 0x3916, 0xd905, 0x94f8, 0x397f, 0x98b5, 0xc61d,
0x05db, 0x3e7a, 0xf750, 0xe8de, 0x3225, 0x81d9, 0x612e, 0x0a7e,
0x2c02, 0xff5b, 0x19ca, 0xbbf5, 0x870e, 0xc9ca, 0x47bb, 0xcfcc,
});
try testType(@Vector(4, u32), .{
0x234d576e, 0x4151cc9c, 0x39f558e4, 0xba935a32,
}, .{
0x398f2a9d, 0x4540f093, 0x9225551c, 0x3bac865b,
});
try testType(@Vector(8, u32), .{
0xb8336635, 0x2fc3182c, 0x27a00123, 0x71587fbe,
0x9cbc65d2, 0x6f4bb0e6, 0x362594ce, 0x9971df38,
}, .{
0x5727e734, 0x972b0313, 0xff25f5dc, 0x924f8e55,
0x04920a61, 0xa1c3b334, 0xf52df4b6, 0x5ef72ecc,
});
try testType(@Vector(16, u32), .{
0xfb566f9e, 0x9ad4691a, 0x5b5f9ec0, 0x5a572d2a,
0x8f2f226b, 0x2dfc7e33, 0x9fb07e32, 0x9d672a2e,
0xbedc3cee, 0x6872428d, 0xbc73a9fd, 0xd4d5f055,
0x69c1e9ee, 0x65038deb, 0x1449061a, 0x48412ec2,
}, .{
0x96cbe946, 0x3f24f60b, 0xaeacdc53, 0x7611a8b4,
0x031a67a8, 0x52a26828, 0x75646f4b, 0xb75902c3,
0x1f881f08, 0x834e02a4, 0x5e5b40eb, 0xc75c264d,
0xa8251e09, 0x28e46bbd, 0x12cb1f31, 0x9a2af615,
});
try testType(@Vector(32, u32), .{
0x131bbb7b, 0xa7311026, 0x9d5e59a0, 0x99b090d6,
0xfe969e2e, 0x04547697, 0x357d3250, 0x43be6d7a,
0x16ecf5c5, 0xf60febcc, 0x1d1e2602, 0x138a96d2,
0x9117ba72, 0x9f185b32, 0xc10e23fd, 0x3e6b7fd8,
0x4dc9be70, 0x2ee30047, 0xaffeab60, 0x7172d362,
0x6154bfcf, 0x5388dc3e, 0xd6e5a76e, 0x8b782f2d,
0xacbef4a2, 0x843aca71, 0x25d8ab5c, 0xe1a63a39,
0xc26212e5, 0x0847b84b, 0xb53541e5, 0x0c8e44db,
}, .{
0x4ad92822, 0x715b623f, 0xa5bed8a7, 0x937447a9,
0x7ecb38eb, 0x0a2f3dfc, 0x96f467a2, 0xec882793,
0x41a8707f, 0xf7310656, 0x76217b80, 0x2058e5fc,
0x26682154, 0x87313e31, 0x4bdc480a, 0x193572ff,
0x60b03c75, 0x0fe45908, 0x56c73703, 0xdb86554c,
0xdda2dd7d, 0x34371b27, 0xe4e6ad50, 0x422d1828,
0x1de3801b, 0xdce268d3, 0x20af9ec8, 0x188a591f,
0xf080e943, 0xc8718d14, 0x3f920382, 0x18d101b5,
});
// TODO: implement fallback for pcmpeqq
if (!comptime @import("std").Target.x86.featureSetHas(@import("builtin").cpu.features, .sse4_1)) return;
try testType(@Vector(2, u64), .{
0x4cd89a317b03d430, 0x28998f61842f63a9,
}, .{
0x6c34db64af0e217e, 0x57aa5d02cd45dceb,
});
try testType(@Vector(4, u64), .{
0x946cf7e7484691c9, 0xf4fc5be2a762fcbf,
0x71cc83bc25abaf14, 0xc69cef44c6f833a1,
}, .{
0x9f90cbd6c3ce1d4e, 0x182f65295dff4e84,
0x4dfe62c59fed0040, 0x18402347c1db1999,
});
try testType(@Vector(8, u64), .{
0x92c6281333943e2c, 0xa97750504668efb5,
0x234be51057c0181f, 0xefbc1f407f3df4fb,
0x8da6cc7c39cebb94, 0xb408f7e56feee497,
0x2363f1f8821592ed, 0x01716e800c0619e1,
}, .{
0xa617426684147e7e, 0x7542da7ebe093a7b,
0x3f21d99ac57606b7, 0x65cd36d697d22de4,
0xed23d6bdf176c844, 0x2d4573f100ff7b58,
0x4968f4d21b49f8ab, 0xf5d9a205d453e933,
});
try testType(@Vector(16, u64), .{
0x2f61a4ee66177b4a, 0xf13b286b279f6a93,
0x36b46beb63665318, 0x74294dbde0da98d2,
0x3aa872ba60b936eb, 0xe8f698b36e62600b,
0x9e8930c21a6a1a76, 0x876998b09b8eb03c,
0xa0244771a2ec0adb, 0xb4c72bff3d3ac1a2,
0xd70677210830eced, 0x6622abc1734dd72d,
0x157e2bb0d57d6596, 0x2aac8192fb7ef973,
0xc4a0ca92f34d7b13, 0x04300f8ad1845246,
}, .{
0xeaf71dcf0eb76f5d, 0x0e84b1b63dc97139,
0x0f64cc38d23c94a1, 0x12775cf0816349b7,
0xfdcf13387ba48d54, 0xf8d3c672cacd8779,
0xe728c1f5eb56ab1e, 0x05931a34877f7a69,
0x1861a763c8dafd1f, 0x4ac97573ecd5739f,
0x3384414c9bf77b8c, 0x32c15bbd04a5ddc4,
0xbfd88aee1d82ed32, 0x20e91c15b701059a,
0xed533d18f8657f3f, 0x1ddd7cd7f6bab957,
});
}
inline fn bitAnd(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs & rhs) {
return lhs & rhs;
}
test bitAnd {
try testBinary(bitAnd);
}
inline fn bitOr(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs | rhs) {
return lhs | rhs;
}
test bitOr {
try testBinary(bitOr);
}
inline fn bitXor(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs ^ rhs) {
return lhs ^ rhs;
}
test bitXor {
try testBinary(bitXor);
}