Skip to content

Commit 2543e2d

Browse files
committed
x86_64: implement integer @divFloor and @mod
Closes #24039
1 parent f4f4460 commit 2543e2d

File tree

7 files changed

+1024
-214
lines changed

7 files changed

+1024
-214
lines changed

src/arch/x86_64/CodeGen.zig

Lines changed: 987 additions & 188 deletions
Large diffs are not rendered by default.

src/arch/x86_64/abi.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -575,22 +575,22 @@ const RegisterBitSet = RegisterManager.RegisterBitSet;
575575
pub const RegisterClass = struct {
576576
pub const gp: RegisterBitSet = blk: {
577577
var set = RegisterBitSet.initEmpty();
578-
for (allocatable_regs, 0..) |reg, index| if (reg.class() == .general_purpose) set.set(index);
578+
for (allocatable_regs, 0..) |reg, index| if (reg.isClass(.general_purpose)) set.set(index);
579579
break :blk set;
580580
};
581581
pub const gphi: RegisterBitSet = blk: {
582582
var set = RegisterBitSet.initEmpty();
583-
for (allocatable_regs, 0..) |reg, index| if (reg.hasHi8()) set.set(index);
583+
for (allocatable_regs, 0..) |reg, index| if (reg.isClass(.gphi)) set.set(index);
584584
break :blk set;
585585
};
586586
pub const x87: RegisterBitSet = blk: {
587587
var set = RegisterBitSet.initEmpty();
588-
for (allocatable_regs, 0..) |reg, index| if (reg.class() == .x87) set.set(index);
588+
for (allocatable_regs, 0..) |reg, index| if (reg.isClass(.x87)) set.set(index);
589589
break :blk set;
590590
};
591591
pub const sse: RegisterBitSet = blk: {
592592
var set = RegisterBitSet.initEmpty();
593-
for (allocatable_regs, 0..) |reg, index| if (reg.class() == .sse) set.set(index);
593+
for (allocatable_regs, 0..) |reg, index| if (reg.isClass(.sse)) set.set(index);
594594
break :blk set;
595595
};
596596
};

src/arch/x86_64/bits.zig

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,16 @@ pub const Register = enum(u8) {
429429
};
430430
}
431431

432+
pub inline fn isClass(reg: Register, rc: Class) bool {
433+
switch (rc) {
434+
else => return reg.class() == rc,
435+
.gphi => {
436+
const reg_id = reg.id();
437+
return (reg_id >= comptime Register.ah.id()) and reg_id <= comptime Register.bh.id();
438+
},
439+
}
440+
}
441+
432442
pub fn id(reg: Register) u7 {
433443
const base = switch (@intFromEnum(reg)) {
434444
// zig fmt: off
@@ -615,22 +625,17 @@ pub const Register = enum(u8) {
615625
}
616626

617627
pub fn toHi8(reg: Register) Register {
618-
assert(reg.hasHi8());
628+
assert(reg.isClass(.gphi));
619629
return @enumFromInt(@intFromEnum(reg) - reg.gpBase() + @intFromEnum(Register.ah));
620630
}
621631

622-
pub fn hasHi8(reg: Register) bool {
623-
const reg_id = reg.id();
624-
return (reg_id >= comptime Register.ah.id()) and reg_id <= comptime Register.bh.id();
625-
}
626-
627632
pub fn to80(reg: Register) Register {
628-
assert(reg.class() == .x87);
633+
assert(reg.isClass(.x87));
629634
return reg;
630635
}
631636

632637
fn sseBase(reg: Register) u8 {
633-
assert(reg.class() == .sse);
638+
assert(reg.isClass(.sse));
634639
return switch (@intFromEnum(reg)) {
635640
@intFromEnum(Register.zmm0)...@intFromEnum(Register.zmm31) => @intFromEnum(Register.zmm0),
636641
@intFromEnum(Register.ymm0)...@intFromEnum(Register.ymm31) => @intFromEnum(Register.ymm0),
@@ -694,11 +699,13 @@ test "Register enc - different classes" {
694699
}
695700

696701
test "Register classes" {
697-
try expect(Register.r11.class() == .general_purpose);
698-
try expect(Register.ymm11.class() == .sse);
699-
try expect(Register.mm3.class() == .mmx);
700-
try expect(Register.st3.class() == .x87);
701-
try expect(Register.fs.class() == .segment);
702+
try expect(Register.r11.isClass(.general_purpose));
703+
try expect(Register.rdx.isClass(.gphi));
704+
try expect(!Register.dil.isClass(.gphi));
705+
try expect(Register.ymm11.isClass(.sse));
706+
try expect(Register.mm3.isClass(.mmx));
707+
try expect(Register.st3.isClass(.x87));
708+
try expect(Register.fs.isClass(.segment));
702709
}
703710

704711
pub const FrameIndex = enum(u32) {

src/arch/x86_64/encoder.zig

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ pub const Instruction = struct {
111111
};
112112

113113
pub fn initMoffs(reg: Register, offset: u64) Memory {
114-
assert(reg.class() == .segment);
114+
assert(reg.isClass(.segment));
115115
return .{ .moffs = .{ .seg = reg, .offset = offset } };
116116
}
117117

@@ -139,7 +139,7 @@ pub const Instruction = struct {
139139
.rip => false,
140140
.sib => |s| switch (s.base) {
141141
.none, .frame, .table, .reloc, .rip_inst => false,
142-
.reg => |reg| reg.class() == .segment,
142+
.reg => |reg| reg.isClass(.segment),
143143
},
144144
};
145145
}
@@ -199,7 +199,7 @@ pub const Instruction = struct {
199199
pub fn isSegmentRegister(op: Operand) bool {
200200
return switch (op) {
201201
.none => unreachable,
202-
.reg => |reg| reg.class() == .segment,
202+
.reg => |reg| reg.isClass(.segment),
203203
.mem => |mem| mem.isSegmentRegister(),
204204
.imm => unreachable,
205205
.bytes => unreachable,
@@ -776,7 +776,7 @@ pub const LegacyPrefixes = packed struct {
776776
padding: u5 = 0,
777777

778778
pub fn setSegmentOverride(self: *LegacyPrefixes, reg: Register) void {
779-
assert(reg.class() == .segment);
779+
assert(reg.isClass(.segment));
780780
switch (reg) {
781781
.cs => self.prefix_2e = true,
782782
.ss => self.prefix_36 = true,
@@ -2457,7 +2457,7 @@ const Assembler = struct {
24572457
.general_purpose, .segment => {
24582458
const tok = try as.expect(.string);
24592459
const base = registerFromString(as.source(tok)) orelse return error.InvalidMemoryOperand;
2460-
if (base.class() != cond) return error.InvalidMemoryOperand;
2460+
if (!base.isClass(cond)) return error.InvalidMemoryOperand;
24612461
res.base = base;
24622462
},
24632463
.rip => {
@@ -2498,7 +2498,7 @@ const Assembler = struct {
24982498
error.Overflow => {
24992499
if (is_neg) return err;
25002500
if (res.base) |base| {
2501-
if (base.class() != .segment) return err;
2501+
if (!base.isClass(.segment)) return err;
25022502
}
25032503
const offset = try std.fmt.parseInt(u64, as.source(tok), 0);
25042504
res.offset = offset;

test/behavior/math.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1893,13 +1893,13 @@ test "float divide by zero" {
18931893

18941894
test "partially-runtime integer vector division would be illegal if vector elements were reordered" {
18951895
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1896-
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
18971896
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18981897
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18991898
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19001899
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
19011900
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
19021901
if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest;
1902+
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
19031903

19041904
var lhs: @Vector(2, i8) = .{ -128, 5 };
19051905
const rhs: @Vector(2, i8) = .{ 1, -1 };

test/behavior/vector.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,12 +559,12 @@ test "vector comparison operators" {
559559

560560
test "vector division operators" {
561561
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
562-
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
563562
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
564563
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
565564
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
566565
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
567566
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
567+
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
568568

569569
const S = struct {
570570
fn doTheTestDiv(comptime T: type, x: @Vector(4, T), y: @Vector(4, T)) !void {

test/behavior/x86_64/binary.zig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5181,6 +5181,8 @@ inline fn divFloor(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(@divFloor(
51815181
}
51825182
test divFloor {
51835183
const test_div_floor = binary(divFloor, .{ .compare = .approx_int });
5184+
try test_div_floor.testInts();
5185+
try test_div_floor.testIntVectors();
51845186
try test_div_floor.testFloats();
51855187
try test_div_floor.testFloatVectors();
51865188
}
@@ -5198,7 +5200,7 @@ test rem {
51985200

51995201
inline fn mod(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(@mod(lhs, rhs)) {
52005202
// workaround llvm backend bugs
5201-
if (@inComptime()) {
5203+
if (@inComptime() and @typeInfo(Scalar(Type)) == .float) {
52025204
const scalarMod = struct {
52035205
fn scalarMod(scalar_lhs: Scalar(Type), scalar_rhs: Scalar(Type)) Scalar(Type) {
52045206
const scalar_rem = @rem(scalar_lhs, scalar_rhs);
@@ -5218,6 +5220,8 @@ inline fn mod(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(@mod(lhs, rhs))
52185220
}
52195221
test mod {
52205222
const test_mod = binary(mod, .{});
5223+
try test_mod.testInts();
5224+
try test_mod.testIntVectors();
52215225
try test_mod.testFloats();
52225226
try test_mod.testFloatVectors();
52235227
}

0 commit comments

Comments
 (0)