Skip to content

Commit 7a2963e

Browse files
committed
x86_64: add avx512 registers
1 parent bbf8abf commit 7a2963e

File tree

3 files changed

+82
-64
lines changed

3 files changed

+82
-64
lines changed

src/arch/x86_64/Encoding.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ pub fn findByMnemonic(
5050
else => {},
5151
} else false;
5252
const rex_extended = for (ops) |op| {
53-
if (op.isBaseExtended() or op.isIndexExtended()) break true;
53+
if (op.baseExtEnc() != 0b00 or op.indexExtEnc() != 0b00) break true;
5454
} else false;
5555

5656
if ((rex_required or rex_extended) and rex_invalid) return error.CannotEncode;

src/arch/x86_64/bits.zig

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -360,11 +360,20 @@ pub const Register = enum(u8) {
360360

361361
ah, ch, dh, bh,
362362

363-
ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7,
364-
ymm8, ymm9, ymm10, ymm11, ymm12, ymm13, ymm14, ymm15,
363+
zmm0, zmm1, zmm2, zmm3, zmm4, zmm5, zmm6, zmm7,
364+
zmm8, zmm9, zmm10, zmm11, zmm12, zmm13, zmm14, zmm15,
365+
zmm16, zmm17,zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
366+
zmm24, zmm25,zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
365367

366-
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
367-
xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
368+
ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7,
369+
ymm8, ymm9, ymm10, ymm11, ymm12, ymm13, ymm14, ymm15,
370+
ymm16, ymm17,ymm18, ymm19, ymm20, ymm21, ymm22, ymm23,
371+
ymm24, ymm25,ymm26, ymm27, ymm28, ymm29, ymm30, ymm31,
372+
373+
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
374+
xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
375+
xmm16, xmm17,xmm18, xmm19, xmm20, xmm21, xmm22, xmm23,
376+
xmm24, xmm25,xmm26, xmm27, xmm28, xmm29, xmm30, xmm31,
368377

369378
mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
370379

@@ -404,8 +413,9 @@ pub const Register = enum(u8) {
404413
@intFromEnum(Register.al) ... @intFromEnum(Register.r15b) => .general_purpose,
405414
@intFromEnum(Register.ah) ... @intFromEnum(Register.bh) => .gphi,
406415

407-
@intFromEnum(Register.ymm0) ... @intFromEnum(Register.ymm15) => .sse,
408-
@intFromEnum(Register.xmm0) ... @intFromEnum(Register.xmm15) => .sse,
416+
@intFromEnum(Register.zmm0) ... @intFromEnum(Register.zmm31) => .sse,
417+
@intFromEnum(Register.ymm0) ... @intFromEnum(Register.ymm31) => .sse,
418+
@intFromEnum(Register.xmm0) ... @intFromEnum(Register.xmm31) => .sse,
409419
@intFromEnum(Register.mm0) ... @intFromEnum(Register.mm7) => .mmx,
410420
@intFromEnum(Register.st0) ... @intFromEnum(Register.st7) => .x87,
411421

@@ -428,13 +438,14 @@ pub const Register = enum(u8) {
428438
@intFromEnum(Register.al) ... @intFromEnum(Register.r15b) => @intFromEnum(Register.al),
429439
@intFromEnum(Register.ah) ... @intFromEnum(Register.bh) => @intFromEnum(Register.ah),
430440

431-
@intFromEnum(Register.ymm0) ... @intFromEnum(Register.ymm15) => @intFromEnum(Register.ymm0) - 16,
432-
@intFromEnum(Register.xmm0) ... @intFromEnum(Register.xmm15) => @intFromEnum(Register.xmm0) - 16,
433-
@intFromEnum(Register.mm0) ... @intFromEnum(Register.mm7) => @intFromEnum(Register.mm0) - 32,
434-
@intFromEnum(Register.st0) ... @intFromEnum(Register.st7) => @intFromEnum(Register.st0) - 40,
435-
@intFromEnum(Register.es) ... @intFromEnum(Register.gs) => @intFromEnum(Register.es) - 48,
436-
@intFromEnum(Register.cr0) ... @intFromEnum(Register.cr15) => @intFromEnum(Register.cr0) - 54,
437-
@intFromEnum(Register.dr0) ... @intFromEnum(Register.dr15) => @intFromEnum(Register.dr0) - 70,
441+
@intFromEnum(Register.zmm0) ... @intFromEnum(Register.zmm31) => @intFromEnum(Register.zmm0) - 16,
442+
@intFromEnum(Register.ymm0) ... @intFromEnum(Register.ymm31) => @intFromEnum(Register.ymm0) - 16,
443+
@intFromEnum(Register.xmm0) ... @intFromEnum(Register.xmm31) => @intFromEnum(Register.xmm0) - 16,
444+
@intFromEnum(Register.mm0) ... @intFromEnum(Register.mm7) => @intFromEnum(Register.mm0) - 48,
445+
@intFromEnum(Register.st0) ... @intFromEnum(Register.st7) => @intFromEnum(Register.st0) - 56,
446+
@intFromEnum(Register.es) ... @intFromEnum(Register.gs) => @intFromEnum(Register.es) - 64,
447+
@intFromEnum(Register.cr0) ... @intFromEnum(Register.cr15) => @intFromEnum(Register.cr0) - 70,
448+
@intFromEnum(Register.dr0) ... @intFromEnum(Register.dr15) => @intFromEnum(Register.dr0) - 86,
438449

439450
else => unreachable,
440451
// zig fmt: on
@@ -451,6 +462,7 @@ pub const Register = enum(u8) {
451462
@intFromEnum(Register.al) ... @intFromEnum(Register.r15b) => 8,
452463
@intFromEnum(Register.ah) ... @intFromEnum(Register.bh) => 8,
453464

465+
@intFromEnum(Register.zmm0) ... @intFromEnum(Register.zmm15) => 512,
454466
@intFromEnum(Register.ymm0) ... @intFromEnum(Register.ymm15) => 256,
455467
@intFromEnum(Register.xmm0) ... @intFromEnum(Register.xmm15) => 128,
456468
@intFromEnum(Register.mm0) ... @intFromEnum(Register.mm7) => 64,
@@ -474,8 +486,9 @@ pub const Register = enum(u8) {
474486
@intFromEnum(Register.r8w) ... @intFromEnum(Register.r15w) => true,
475487
@intFromEnum(Register.r8b) ... @intFromEnum(Register.r15b) => true,
476488

477-
@intFromEnum(Register.ymm8) ... @intFromEnum(Register.ymm15) => true,
478-
@intFromEnum(Register.xmm8) ... @intFromEnum(Register.xmm15) => true,
489+
@intFromEnum(Register.zmm8) ... @intFromEnum(Register.zmm31) => true,
490+
@intFromEnum(Register.ymm8) ... @intFromEnum(Register.ymm31) => true,
491+
@intFromEnum(Register.xmm8) ... @intFromEnum(Register.xmm31) => true,
479492

480493
@intFromEnum(Register.cr8) ... @intFromEnum(Register.cr15) => true,
481494
@intFromEnum(Register.dr8) ... @intFromEnum(Register.dr15) => true,
@@ -485,7 +498,7 @@ pub const Register = enum(u8) {
485498
};
486499
}
487500

488-
pub fn enc(reg: Register) u4 {
501+
pub fn enc(reg: Register) u5 {
489502
const base = switch (@intFromEnum(reg)) {
490503
// zig fmt: off
491504
@intFromEnum(Register.rax) ... @intFromEnum(Register.r15) => @intFromEnum(Register.rax),
@@ -510,10 +523,6 @@ pub const Register = enum(u8) {
510523
return @truncate(@intFromEnum(reg) - base);
511524
}
512525

513-
pub fn lowEnc(reg: Register) u3 {
514-
return @truncate(reg.enc());
515-
}
516-
517526
pub fn toBitSize(reg: Register, bit_size: u64) Register {
518527
return switch (bit_size) {
519528
8 => reg.to8(),
@@ -558,11 +567,12 @@ pub const Register = enum(u8) {
558567
};
559568
}
560569

561-
fn sseBase(reg: Register) u7 {
570+
fn sseBase(reg: Register) u8 {
562571
assert(reg.class() == .sse);
563572
return switch (@intFromEnum(reg)) {
564-
@intFromEnum(Register.ymm0)...@intFromEnum(Register.ymm15) => @intFromEnum(Register.ymm0),
565-
@intFromEnum(Register.xmm0)...@intFromEnum(Register.xmm15) => @intFromEnum(Register.xmm0),
573+
@intFromEnum(Register.zmm0)...@intFromEnum(Register.zmm31) => @intFromEnum(Register.zmm0),
574+
@intFromEnum(Register.ymm0)...@intFromEnum(Register.ymm31) => @intFromEnum(Register.ymm0),
575+
@intFromEnum(Register.xmm0)...@intFromEnum(Register.xmm31) => @intFromEnum(Register.xmm0),
566576
else => unreachable,
567577
};
568578
}
@@ -682,13 +692,6 @@ pub const Memory = struct {
682692
rip_inst: Mir.Inst.Index,
683693

684694
pub const Tag = @typeInfo(Base).@"union".tag_type.?;
685-
686-
pub fn isExtended(self: Base) bool {
687-
return switch (self) {
688-
.none, .frame, .table, .reloc, .rip_inst => false, // rsp, rbp, and rip are not extended
689-
.reg => |reg| reg.isExtended(),
690-
};
691-
}
692695
};
693696

694697
pub const Mod = union(enum(u1)) {

src/arch/x86_64/encoder.zig

Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -206,19 +206,22 @@ pub const Instruction = struct {
206206
};
207207
}
208208

209-
pub fn isBaseExtended(op: Operand) bool {
209+
pub fn baseExtEnc(op: Operand) u2 {
210210
return switch (op) {
211-
.none, .imm => false,
212-
.reg => |reg| reg.isExtended(),
213-
.mem => |mem| mem.base().isExtended(),
211+
.none, .imm => 0b00,
212+
.reg => |reg| @truncate(reg.enc() >> 3),
213+
.mem => |mem| switch (mem.base()) {
214+
.none, .frame, .table, .reloc, .rip_inst => 0b00, // rsp, rbp, and rip are not extended
215+
.reg => |reg| @truncate(reg.enc() >> 3),
216+
},
214217
.bytes => unreachable,
215218
};
216219
}
217220

218-
pub fn isIndexExtended(op: Operand) bool {
221+
pub fn indexExtEnc(op: Operand) u2 {
219222
return switch (op) {
220-
.none, .reg, .imm => false,
221-
.mem => |mem| if (mem.scaleIndex()) |si| si.index.isExtended() else false,
223+
.none, .reg, .imm => 0b00,
224+
.mem => |mem| if (mem.scaleIndex()) |si| @truncate(si.index.enc() >> 3) else 0b00,
222225
.bytes => unreachable,
223226
};
224227
}
@@ -422,14 +425,14 @@ pub const Instruction = struct {
422425
};
423426
switch (mem_op) {
424427
.reg => |reg| {
425-
const rm = switch (data.op_en) {
428+
const rm: u3 = switch (data.op_en) {
426429
.ia, .m, .mi, .m1, .mc, .vm, .vmi => enc.modRmExt(),
427-
.mr, .mri, .mrc => inst.ops[1].reg.lowEnc(),
428-
.rm, .rmi, .rm0, .rvm, .rvmr, .rvmi, .rmv => inst.ops[0].reg.lowEnc(),
429-
.mvr => inst.ops[2].reg.lowEnc(),
430+
.mr, .mri, .mrc => @truncate(inst.ops[1].reg.enc()),
431+
.rm, .rmi, .rm0, .rvm, .rvmr, .rvmi, .rmv => @truncate(inst.ops[0].reg.enc()),
432+
.mvr => @truncate(inst.ops[2].reg.enc()),
430433
else => unreachable,
431434
};
432-
try encoder.modRm_direct(rm, reg.lowEnc());
435+
try encoder.modRm_direct(rm, @truncate(reg.enc()));
433436
},
434437
.mem => |mem| {
435438
const op = switch (data.op_en) {
@@ -448,7 +451,7 @@ pub const Instruction = struct {
448451
.ia => try encodeImm(inst.ops[0].imm, data.ops[0], encoder),
449452
.mi => try encodeImm(inst.ops[1].imm, data.ops[1], encoder),
450453
.rmi, .mri, .vmi => try encodeImm(inst.ops[2].imm, data.ops[2], encoder),
451-
.rvmr => try encoder.imm8(@as(u8, inst.ops[3].reg.enc()) << 4),
454+
.rvmr => try encoder.imm8(@as(u8, @as(u4, @intCast(inst.ops[3].reg.enc()))) << 4),
452455
.rvmi => try encodeImm(inst.ops[3].imm, data.ops[3], encoder),
453456
else => {},
454457
}
@@ -462,8 +465,8 @@ pub const Instruction = struct {
462465
const final = opcode.len - 1;
463466
for (opcode[first..final]) |byte| try encoder.opcode_1byte(byte);
464467
switch (inst.encoding.data.op_en) {
465-
.o, .oz, .oi => try encoder.opcode_withReg(opcode[final], inst.ops[0].reg.lowEnc()),
466-
.zo => try encoder.opcode_withReg(opcode[final], inst.ops[1].reg.lowEnc()),
468+
.o, .oz, .oi => try encoder.opcode_withReg(opcode[final], @truncate(inst.ops[0].reg.enc())),
469+
.zo => try encoder.opcode_withReg(opcode[final], @truncate(inst.ops[1].reg.enc())),
467470
else => try encoder.opcode_1byte(opcode[final]),
468471
}
469472
}
@@ -533,23 +536,29 @@ pub const Instruction = struct {
533536

534537
switch (op_en) {
535538
.z, .i, .zi, .ii, .ia, .fd, .td, .d => {},
536-
.o, .oz, .oi => rex.b = inst.ops[0].reg.isExtended(),
537-
.zo => rex.b = inst.ops[1].reg.isExtended(),
539+
.o, .oz, .oi => rex.b = inst.ops[0].reg.enc() & 0b01000 != 0,
540+
.zo => rex.b = inst.ops[1].reg.enc() & 0b01000 != 0,
538541
.m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0, .rmv => {
539542
const r_op = switch (op_en) {
540543
.rm, .rmi, .rm0, .rmv => inst.ops[0],
541544
.mr, .mri, .mrc => inst.ops[1],
542545
else => .none,
543546
};
544-
rex.r = r_op.isBaseExtended();
547+
const r_op_base_ext_enc = r_op.baseExtEnc();
548+
rex.r = r_op_base_ext_enc & 0b01 != 0;
549+
assert(r_op_base_ext_enc & 0b10 == 0);
545550

546551
const b_x_op = switch (op_en) {
547552
.rm, .rmi, .rm0 => inst.ops[1],
548553
.m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0],
549554
else => unreachable,
550555
};
551-
rex.b = b_x_op.isBaseExtended();
552-
rex.x = b_x_op.isIndexExtended();
556+
const b_x_op_base_ext_enc = b_x_op.baseExtEnc();
557+
rex.b = b_x_op_base_ext_enc & 0b01 != 0;
558+
assert(b_x_op_base_ext_enc & 0b10 == 0);
559+
const b_x_op_index_ext_enc = b_x_op.indexExtEnc();
560+
rex.x = b_x_op_index_ext_enc & 0b01 != 0;
561+
assert(b_x_op_index_ext_enc & 0b10 == 0);
553562
},
554563
.vm, .vmi, .rvm, .rvmr, .rvmi, .mvr => unreachable,
555564
}
@@ -576,16 +585,22 @@ pub const Instruction = struct {
576585
.m, .mi, .m1, .mc, .vm, .vmi => .none,
577586
else => unreachable,
578587
};
579-
vex.r = r_op.isBaseExtended();
588+
const r_op_base_ext_enc = r_op.baseExtEnc();
589+
vex.r = r_op_base_ext_enc & 0b01 != 0;
590+
assert(r_op_base_ext_enc & 0b10 == 0);
580591

581592
const b_x_op = switch (op_en) {
582593
.rm, .rmi, .rm0, .vm, .vmi, .rmv => inst.ops[1],
583594
.m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
584595
.rvm, .rvmr, .rvmi => inst.ops[2],
585596
else => unreachable,
586597
};
587-
vex.b = b_x_op.isBaseExtended();
588-
vex.x = b_x_op.isIndexExtended();
598+
const b_x_op_base_ext_enc = b_x_op.baseExtEnc();
599+
vex.b = b_x_op_base_ext_enc & 0b01 != 0;
600+
assert(b_x_op_base_ext_enc & 0b10 == 0);
601+
const b_x_op_index_ext_enc = b_x_op.indexExtEnc();
602+
vex.x = b_x_op_index_ext_enc & 0b01 != 0;
603+
assert(b_x_op_index_ext_enc & 0b10 == 0);
589604
},
590605
}
591606

@@ -622,8 +637,8 @@ pub const Instruction = struct {
622637
}
623638

624639
fn encodeMemory(encoding: Encoding, mem: Memory, operand: Operand, encoder: anytype) !void {
625-
const operand_enc = switch (operand) {
626-
.reg => |reg| reg.lowEnc(),
640+
const operand_enc: u3 = switch (operand) {
641+
.reg => |reg| @truncate(reg.enc()),
627642
.none => encoding.modRmExt(),
628643
else => unreachable,
629644
};
@@ -635,7 +650,7 @@ pub const Instruction = struct {
635650
try encoder.modRm_SIBDisp0(operand_enc);
636651
if (mem.scaleIndex()) |si| {
637652
const scale = math.log2_int(u4, si.scale);
638-
try encoder.sib_scaleIndexDisp32(scale, si.index.lowEnc());
653+
try encoder.sib_scaleIndexDisp32(scale, @truncate(si.index.enc()));
639654
} else {
640655
try encoder.sib_disp32();
641656
}
@@ -647,29 +662,29 @@ pub const Instruction = struct {
647662
try encoder.modRm_SIBDisp0(operand_enc);
648663
if (mem.scaleIndex()) |si| {
649664
const scale = math.log2_int(u4, si.scale);
650-
try encoder.sib_scaleIndexDisp32(scale, si.index.lowEnc());
665+
try encoder.sib_scaleIndexDisp32(scale, @truncate(si.index.enc()));
651666
} else {
652667
try encoder.sib_disp32();
653668
}
654669
try encoder.disp32(sib.disp);
655670
},
656671
.general_purpose => {
657-
const dst = base.lowEnc();
672+
const dst: u3 = @truncate(base.enc());
658673
const src = operand_enc;
659674
if (dst == 4 or mem.scaleIndex() != null) {
660675
if (sib.disp == 0 and dst != 5) {
661676
try encoder.modRm_SIBDisp0(src);
662677
if (mem.scaleIndex()) |si| {
663678
const scale = math.log2_int(u4, si.scale);
664-
try encoder.sib_scaleIndexBase(scale, si.index.lowEnc(), dst);
679+
try encoder.sib_scaleIndexBase(scale, @truncate(si.index.enc()), dst);
665680
} else {
666681
try encoder.sib_base(dst);
667682
}
668683
} else if (math.cast(i8, sib.disp)) |_| {
669684
try encoder.modRm_SIBDisp8(src);
670685
if (mem.scaleIndex()) |si| {
671686
const scale = math.log2_int(u4, si.scale);
672-
try encoder.sib_scaleIndexBaseDisp8(scale, si.index.lowEnc(), dst);
687+
try encoder.sib_scaleIndexBaseDisp8(scale, @truncate(si.index.enc()), dst);
673688
} else {
674689
try encoder.sib_baseDisp8(dst);
675690
}
@@ -678,7 +693,7 @@ pub const Instruction = struct {
678693
try encoder.modRm_SIBDisp32(src);
679694
if (mem.scaleIndex()) |si| {
680695
const scale = math.log2_int(u4, si.scale);
681-
try encoder.sib_scaleIndexBaseDisp32(scale, si.index.lowEnc(), dst);
696+
try encoder.sib_scaleIndexBaseDisp32(scale, @truncate(si.index.enc()), dst);
682697
} else {
683698
try encoder.sib_baseDisp32(dst);
684699
}
@@ -867,15 +882,15 @@ fn Encoder(comptime T: type, comptime opts: Options) type {
867882

868883
try self.writer.writeByte(
869884
@as(u8, @intFromBool(fields.w)) << 7 |
870-
@as(u8, ~fields.v.enc()) << 3 |
885+
@as(u8, ~@as(u4, @intCast(fields.v.enc()))) << 3 |
871886
@as(u8, @intFromBool(fields.l)) << 2 |
872887
@as(u8, @intFromEnum(fields.p)) << 0,
873888
);
874889
} else {
875890
try self.writer.writeByte(0b1100_0101);
876891
try self.writer.writeByte(
877892
@as(u8, ~@intFromBool(fields.r)) << 7 |
878-
@as(u8, ~fields.v.enc()) << 3 |
893+
@as(u8, ~@as(u4, @intCast(fields.v.enc()))) << 3 |
879894
@as(u8, @intFromBool(fields.l)) << 2 |
880895
@as(u8, @intFromEnum(fields.p)) << 0,
881896
);

0 commit comments

Comments
 (0)