x86_64: rewrite scalar *|

This commit is contained in:
Jacob Young
2025-05-14 07:42:58 -04:00
parent 96e35b3652
commit d3dfe61eaa
5 changed files with 5676 additions and 335 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -578,6 +578,11 @@ pub const RegisterClass = struct {
for (allocatable_regs, 0..) |reg, index| if (reg.class() == .general_purpose) set.set(index);
break :blk set;
};
pub const gphi: RegisterBitSet = blk: {
var set = RegisterBitSet.initEmpty();
for (allocatable_regs, 0..) |reg, index| if (reg.hasHi8()) set.set(index);
break :blk set;
};
pub const x87: RegisterBitSet = blk: {
var set = RegisterBitSet.initEmpty();
for (allocatable_regs, 0..) |reg, index| if (reg.class() == .x87) set.set(index);

View File

@@ -529,12 +529,36 @@ pub const Register = enum(u8) {
16 => reg.to16(),
32 => reg.to32(),
64 => reg.to64(),
80 => reg.to80(),
128 => reg.to128(),
256 => reg.to256(),
512 => reg.to512(),
else => unreachable,
};
}
pub fn toSize(reg: Register, size: Memory.Size, target: *const std.Target) Register {
return switch (size) {
.none => unreachable,
.ptr => reg.toBitSize(target.ptrBitWidth()),
.gpr => switch (target.cpu.arch) {
else => unreachable,
.x86 => reg.to32(),
.x86_64 => reg.to64(),
},
.low_byte => reg.toLo8(),
.high_byte => reg.toHi8(),
.byte => reg.to8(),
.word => reg.to16(),
.dword => reg.to32(),
.qword => reg.to64(),
.tbyte => reg.to80(),
.xword => reg.to128(),
.yword => reg.to256(),
.zword => reg.to512(),
};
}
fn gpBase(reg: Register) u7 {
return switch (@intFromEnum(reg)) {
// zig fmt: off
@@ -549,24 +573,62 @@ pub const Register = enum(u8) {
}
pub fn to64(reg: Register) Register {
return @enumFromInt(@intFromEnum(reg) - reg.gpBase() + @intFromEnum(Register.rax));
return switch (reg.class()) {
.general_purpose, .gphi => @enumFromInt(@intFromEnum(reg) - reg.gpBase() + @intFromEnum(Register.rax)),
.segment => unreachable,
.x87, .mmx, .cr, .dr => reg,
.sse => reg.to128(),
.ip => .rip,
};
}
pub fn to32(reg: Register) Register {
return @enumFromInt(@intFromEnum(reg) - reg.gpBase() + @intFromEnum(Register.eax));
return switch (reg.class()) {
.general_purpose, .gphi => @enumFromInt(@intFromEnum(reg) - reg.gpBase() + @intFromEnum(Register.eax)),
.segment => unreachable,
.x87, .mmx, .cr, .dr => reg,
.sse => reg.to128(),
.ip => .eip,
};
}
pub fn to16(reg: Register) Register {
return @enumFromInt(@intFromEnum(reg) - reg.gpBase() + @intFromEnum(Register.ax));
return switch (reg.class()) {
.general_purpose, .gphi => @enumFromInt(@intFromEnum(reg) - reg.gpBase() + @intFromEnum(Register.ax)),
.segment, .x87, .mmx, .cr, .dr => reg,
.sse => reg.to128(),
.ip => .ip,
};
}
pub fn to8(reg: Register) Register {
return switch (@intFromEnum(reg)) {
else => @enumFromInt(@intFromEnum(reg) - reg.gpBase() + @intFromEnum(Register.al)),
@intFromEnum(Register.ah)...@intFromEnum(Register.bh) => reg,
return switch (reg.class()) {
.general_purpose => reg.toLo8(),
.gphi, .segment, .x87, .mmx, .cr, .dr => reg,
.sse => reg.to128(),
.ip => .ip,
};
}
pub fn toLo8(reg: Register) Register {
return @enumFromInt(@intFromEnum(reg) - reg.gpBase() + @intFromEnum(Register.al));
}
pub fn toHi8(reg: Register) Register {
assert(reg.hasHi8());
return @enumFromInt(@intFromEnum(reg) - reg.gpBase() + @intFromEnum(Register.ah));
}
pub fn hasHi8(reg: Register) bool {
const reg_id = reg.id();
return (reg_id >= comptime Register.ah.id()) and reg_id <= comptime Register.bh.id();
}
pub fn to80(reg: Register) Register {
assert(reg.class() == .x87);
return reg;
}
fn sseBase(reg: Register) u8 {
assert(reg.class() == .sse);
return switch (@intFromEnum(reg)) {
@@ -577,6 +639,10 @@ pub const Register = enum(u8) {
};
}
pub fn to512(reg: Register) Register {
return @enumFromInt(@intFromEnum(reg) - reg.sseBase() + @intFromEnum(Register.zmm0));
}
pub fn to256(reg: Register) Register {
return @enumFromInt(@intFromEnum(reg) - reg.sseBase() + @intFromEnum(Register.ymm0));
}
@@ -710,6 +776,8 @@ pub const Memory = struct {
none,
ptr,
gpr,
low_byte,
high_byte,
byte,
word,
dword,
@@ -755,7 +823,7 @@ pub const Memory = struct {
.x86 => 32,
.x86_64 => 64,
},
.byte => 8,
.low_byte, .high_byte, .byte => 8,
.word => 16,
.dword => 32,
.qword => 64,

View File

@@ -259,13 +259,13 @@ test "saturating mul i64, i128, wasm only" {
test "saturating multiplication" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isWasm()) {
// https://github.com/ziglang/zig/issues/9660

View File

@@ -5134,6 +5134,14 @@ test mulWrap {
try test_mul_wrap.testIntVectors();
}
inline fn mulSat(comptime Type: type, lhs: Type, rhs: Type) Type {
return lhs *| rhs;
}
test mulSat {
const test_mul_sat = binary(mulSat, .{});
try test_mul_sat.testInts();
}
inline fn multiply(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs * rhs) {
return lhs * rhs;
}