Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,175 changes: 987 additions & 188 deletions src/arch/x86_64/CodeGen.zig

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/arch/x86_64/abi.zig
Original file line number Diff line number Diff line change
Expand Up @@ -575,22 +575,22 @@ const RegisterBitSet = RegisterManager.RegisterBitSet;
pub const RegisterClass = struct {
pub const gp: RegisterBitSet = blk: {
var set = RegisterBitSet.initEmpty();
for (allocatable_regs, 0..) |reg, index| if (reg.class() == .general_purpose) set.set(index);
for (allocatable_regs, 0..) |reg, index| if (reg.isClass(.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);
for (allocatable_regs, 0..) |reg, index| if (reg.isClass(.gphi)) 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);
for (allocatable_regs, 0..) |reg, index| if (reg.isClass(.x87)) set.set(index);
break :blk set;
};
pub const sse: RegisterBitSet = blk: {
var set = RegisterBitSet.initEmpty();
for (allocatable_regs, 0..) |reg, index| if (reg.class() == .sse) set.set(index);
for (allocatable_regs, 0..) |reg, index| if (reg.isClass(.sse)) set.set(index);
break :blk set;
};
};
Expand Down
33 changes: 20 additions & 13 deletions src/arch/x86_64/bits.zig
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,16 @@ pub const Register = enum(u8) {
};
}

pub inline fn isClass(reg: Register, rc: Class) bool {
switch (rc) {
else => return reg.class() == rc,
.gphi => {
const reg_id = reg.id();
return (reg_id >= comptime Register.ah.id()) and reg_id <= comptime Register.bh.id();
},
}
}

pub fn id(reg: Register) u7 {
const base = switch (@intFromEnum(reg)) {
// zig fmt: off
Expand Down Expand Up @@ -615,22 +625,17 @@ pub const Register = enum(u8) {
}

pub fn toHi8(reg: Register) Register {
assert(reg.hasHi8());
assert(reg.isClass(.gphi));
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);
assert(reg.isClass(.x87));
return reg;
}

fn sseBase(reg: Register) u8 {
assert(reg.class() == .sse);
assert(reg.isClass(.sse));
return switch (@intFromEnum(reg)) {
@intFromEnum(Register.zmm0)...@intFromEnum(Register.zmm31) => @intFromEnum(Register.zmm0),
@intFromEnum(Register.ymm0)...@intFromEnum(Register.ymm31) => @intFromEnum(Register.ymm0),
Expand Down Expand Up @@ -694,11 +699,13 @@ test "Register enc - different classes" {
}

test "Register classes" {
try expect(Register.r11.class() == .general_purpose);
try expect(Register.ymm11.class() == .sse);
try expect(Register.mm3.class() == .mmx);
try expect(Register.st3.class() == .x87);
try expect(Register.fs.class() == .segment);
try expect(Register.r11.isClass(.general_purpose));
try expect(Register.rdx.isClass(.gphi));
try expect(!Register.dil.isClass(.gphi));
try expect(Register.ymm11.isClass(.sse));
try expect(Register.mm3.isClass(.mmx));
try expect(Register.st3.isClass(.x87));
try expect(Register.fs.isClass(.segment));
}

pub const FrameIndex = enum(u32) {
Expand Down
12 changes: 6 additions & 6 deletions src/arch/x86_64/encoder.zig
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ pub const Instruction = struct {
};

pub fn initMoffs(reg: Register, offset: u64) Memory {
assert(reg.class() == .segment);
assert(reg.isClass(.segment));
return .{ .moffs = .{ .seg = reg, .offset = offset } };
}

Expand Down Expand Up @@ -139,7 +139,7 @@ pub const Instruction = struct {
.rip => false,
.sib => |s| switch (s.base) {
.none, .frame, .table, .reloc, .rip_inst => false,
.reg => |reg| reg.class() == .segment,
.reg => |reg| reg.isClass(.segment),
},
};
}
Expand Down Expand Up @@ -199,7 +199,7 @@ pub const Instruction = struct {
pub fn isSegmentRegister(op: Operand) bool {
return switch (op) {
.none => unreachable,
.reg => |reg| reg.class() == .segment,
.reg => |reg| reg.isClass(.segment),
.mem => |mem| mem.isSegmentRegister(),
.imm => unreachable,
.bytes => unreachable,
Expand Down Expand Up @@ -776,7 +776,7 @@ pub const LegacyPrefixes = packed struct {
padding: u5 = 0,

pub fn setSegmentOverride(self: *LegacyPrefixes, reg: Register) void {
assert(reg.class() == .segment);
assert(reg.isClass(.segment));
switch (reg) {
.cs => self.prefix_2e = true,
.ss => self.prefix_36 = true,
Expand Down Expand Up @@ -2457,7 +2457,7 @@ const Assembler = struct {
.general_purpose, .segment => {
const tok = try as.expect(.string);
const base = registerFromString(as.source(tok)) orelse return error.InvalidMemoryOperand;
if (base.class() != cond) return error.InvalidMemoryOperand;
if (!base.isClass(cond)) return error.InvalidMemoryOperand;
res.base = base;
},
.rip => {
Expand Down Expand Up @@ -2498,7 +2498,7 @@ const Assembler = struct {
error.Overflow => {
if (is_neg) return err;
if (res.base) |base| {
if (base.class() != .segment) return err;
if (!base.isClass(.segment)) return err;
}
const offset = try std.fmt.parseInt(u64, as.source(tok), 0);
res.offset = offset;
Expand Down
2 changes: 1 addition & 1 deletion test/behavior/math.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1893,13 +1893,13 @@ test "float divide by zero" {

test "partially-runtime integer vector division would be illegal if vector elements were reordered" {
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_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;

var lhs: @Vector(2, i8) = .{ -128, 5 };
const rhs: @Vector(2, i8) = .{ 1, -1 };
Expand Down
2 changes: 1 addition & 1 deletion test/behavior/vector.zig
Original file line number Diff line number Diff line change
Expand Up @@ -559,12 +559,12 @@ test "vector comparison operators" {

test "vector division operators" {
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_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;

const S = struct {
fn doTheTestDiv(comptime T: type, x: @Vector(4, T), y: @Vector(4, T)) !void {
Expand Down
6 changes: 5 additions & 1 deletion test/behavior/x86_64/binary.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5181,6 +5181,8 @@ inline fn divFloor(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(@divFloor(
}
test divFloor {
const test_div_floor = binary(divFloor, .{ .compare = .approx_int });
try test_div_floor.testInts();
try test_div_floor.testIntVectors();
try test_div_floor.testFloats();
try test_div_floor.testFloatVectors();
}
Expand All @@ -5198,7 +5200,7 @@ test rem {

inline fn mod(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(@mod(lhs, rhs)) {
// workaround llvm backend bugs
if (@inComptime()) {
if (@inComptime() and @typeInfo(Scalar(Type)) == .float) {
const scalarMod = struct {
fn scalarMod(scalar_lhs: Scalar(Type), scalar_rhs: Scalar(Type)) Scalar(Type) {
const scalar_rem = @rem(scalar_lhs, scalar_rhs);
Expand All @@ -5218,6 +5220,8 @@ inline fn mod(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(@mod(lhs, rhs))
}
test mod {
const test_mod = binary(mod, .{});
try test_mod.testInts();
try test_mod.testIntVectors();
try test_mod.testFloats();
try test_mod.testFloatVectors();
}
Expand Down