x86_64: rewrite scalar shifts

This commit is contained in:
Jacob Young 2025-03-12 22:09:46 -04:00
parent aff2be01c9
commit 2361468e23
5 changed files with 1071 additions and 64 deletions

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -384,6 +384,7 @@ pub const Register = enum(u8) {
pub const Class = enum { pub const Class = enum {
general_purpose, general_purpose,
gphi,
segment, segment,
x87, x87,
mmx, mmx,
@ -400,7 +401,7 @@ pub const Register = enum(u8) {
@intFromEnum(Register.eax) ... @intFromEnum(Register.r15d) => .general_purpose, @intFromEnum(Register.eax) ... @intFromEnum(Register.r15d) => .general_purpose,
@intFromEnum(Register.ax) ... @intFromEnum(Register.r15w) => .general_purpose, @intFromEnum(Register.ax) ... @intFromEnum(Register.r15w) => .general_purpose,
@intFromEnum(Register.al) ... @intFromEnum(Register.r15b) => .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.ymm0) ... @intFromEnum(Register.ymm15) => .sse,
@intFromEnum(Register.xmm0) ... @intFromEnum(Register.xmm15) => .sse, @intFromEnum(Register.xmm0) ... @intFromEnum(Register.xmm15) => .sse,
@ -525,7 +526,6 @@ pub const Register = enum(u8) {
} }
fn gpBase(reg: Register) u7 { fn gpBase(reg: Register) u7 {
assert(reg.class() == .general_purpose);
return switch (@intFromEnum(reg)) { return switch (@intFromEnum(reg)) {
// zig fmt: off // zig fmt: off
@intFromEnum(Register.rax) ... @intFromEnum(Register.r15) => @intFromEnum(Register.rax), @intFromEnum(Register.rax) ... @intFromEnum(Register.r15) => @intFromEnum(Register.rax),
@ -577,7 +577,7 @@ pub const Register = enum(u8) {
/// DWARF register encoding /// DWARF register encoding
pub fn dwarfNum(reg: Register) u6 { pub fn dwarfNum(reg: Register) u6 {
return switch (reg.class()) { return switch (reg.class()) {
.general_purpose => if (reg.isExtended()) .general_purpose, .gphi => if (reg.isExtended())
reg.enc() reg.enc()
else else
@as(u3, @truncate(@as(u24, 0o54673120) >> @as(u5, reg.enc()) * 3)), @as(u3, @truncate(@as(u24, 0o54673120) >> @as(u5, reg.enc()) * 3)),

View File

@ -1,4 +1,5 @@
const AddOneBit = math.AddOneBit; const AddOneBit = math.AddOneBit;
const cast = math.cast;
const checkExpected = math.checkExpected; const checkExpected = math.checkExpected;
const Compare = math.Compare; const Compare = math.Compare;
const DoubleBits = math.DoubleBits; const DoubleBits = math.DoubleBits;
@ -6,6 +7,7 @@ const fmax = math.fmax;
const fmin = math.fmin; const fmin = math.fmin;
const Gpr = math.Gpr; const Gpr = math.Gpr;
const inf = math.inf; const inf = math.inf;
const Log2Int = math.Log2Int;
const math = @import("math.zig"); const math = @import("math.zig");
const nan = math.nan; const nan = math.nan;
const Scalar = math.Scalar; const Scalar = math.Scalar;
@ -5582,6 +5584,28 @@ test mod {
try test_mod.testFloatVectors(); try test_mod.testFloatVectors();
} }
inline fn max(comptime Type: type, lhs: Type, rhs: Type) Type {
return @max(lhs, rhs);
}
test max {
const test_max = binary(max, .{});
try test_max.testInts();
try test_max.testIntVectors();
try test_max.testFloats();
try test_max.testFloatVectors();
}
inline fn min(comptime Type: type, lhs: Type, rhs: Type) Type {
return @min(lhs, rhs);
}
test min {
const test_min = binary(min, .{});
try test_min.testInts();
try test_min.testIntVectors();
try test_min.testFloats();
try test_min.testFloatVectors();
}
inline fn equal(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs == rhs) { inline fn equal(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs == rhs) {
return lhs == rhs; return lhs == rhs;
} }
@ -5654,6 +5678,48 @@ test bitOr {
try test_bit_or.testIntVectors(); try test_bit_or.testIntVectors();
} }
inline fn shr(comptime Type: type, lhs: Type, rhs: Type) Type {
const bit_cast_rhs: @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(Type) } }) = @bitCast(rhs);
const truncate_rhs: Log2Int(Type) = @truncate(bit_cast_rhs);
return lhs >> if (comptime cast(Log2Int(Type), @bitSizeOf(Type))) |bits| truncate_rhs % bits else truncate_rhs;
}
test shr {
const test_shr = binary(shr, .{});
try test_shr.testInts();
}
inline fn shrExact(comptime Type: type, lhs: Type, rhs: Type) Type {
const bit_cast_rhs: @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(Type) } }) = @bitCast(rhs);
const truncate_rhs: Log2Int(Type) = @truncate(bit_cast_rhs);
const final_rhs = if (comptime cast(Log2Int(Type), @bitSizeOf(Type))) |bits| truncate_rhs % bits else truncate_rhs;
return @shrExact(lhs >> final_rhs << final_rhs, final_rhs);
}
test shrExact {
const test_shr_exact = binary(shrExact, .{});
try test_shr_exact.testInts();
}
inline fn shl(comptime Type: type, lhs: Type, rhs: Type) Type {
const bit_cast_rhs: @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(Type) } }) = @bitCast(rhs);
const truncate_rhs: Log2Int(Type) = @truncate(bit_cast_rhs);
return lhs << if (comptime cast(Log2Int(Type), @bitSizeOf(Type))) |bits| truncate_rhs % bits else truncate_rhs;
}
test shl {
const test_shl = binary(shl, .{});
try test_shl.testInts();
}
inline fn shlExact(comptime Type: type, lhs: Type, rhs: Type) Type {
const bit_cast_rhs: @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(Type) } }) = @bitCast(rhs);
const truncate_rhs: Log2Int(Type) = @truncate(bit_cast_rhs);
const final_rhs = if (comptime cast(Log2Int(Type), @bitSizeOf(Type))) |bits| truncate_rhs % bits else truncate_rhs;
return @shlExact(lhs << final_rhs >> final_rhs, final_rhs);
}
test shlExact {
const test_shl_exact = binary(shlExact, .{});
try test_shl_exact.testInts();
}
inline fn bitXor(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs ^ rhs) { inline fn bitXor(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs ^ rhs) {
return lhs ^ rhs; return lhs ^ rhs;
} }
@ -5663,28 +5729,6 @@ test bitXor {
try test_bit_xor.testIntVectors(); try test_bit_xor.testIntVectors();
} }
inline fn min(comptime Type: type, lhs: Type, rhs: Type) Type {
return @min(lhs, rhs);
}
test min {
const test_min = binary(min, .{});
try test_min.testInts();
try test_min.testIntVectors();
try test_min.testFloats();
try test_min.testFloatVectors();
}
inline fn max(comptime Type: type, lhs: Type, rhs: Type) Type {
return @max(lhs, rhs);
}
test max {
const test_max = binary(max, .{});
try test_max.testInts();
try test_max.testIntVectors();
try test_max.testFloats();
try test_max.testFloatVectors();
}
inline fn optionalsEqual(comptime Type: type, lhs: Type, rhs: Type) bool { inline fn optionalsEqual(comptime Type: type, lhs: Type, rhs: Type) bool {
if (@inComptime()) return lhs == rhs; // workaround https://github.com/ziglang/zig/issues/22636 if (@inComptime()) return lhs == rhs; // workaround https://github.com/ziglang/zig/issues/22636
return @as(?Type, lhs) == rhs; return @as(?Type, lhs) == rhs;

View File

@ -2,6 +2,7 @@ const builtin = @import("builtin");
const math = std.math; const math = std.math;
const std = @import("std"); const std = @import("std");
pub const cast = math.cast;
pub const fmax = math.floatMax; pub const fmax = math.floatMax;
pub const fmin = math.floatMin; pub const fmin = math.floatMin;
pub const imax = math.maxInt; pub const imax = math.maxInt;