authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-03-27 12:44:58-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-04-10 02:04:52-04:00
log7a2963efabfed7cf7e356b698a425cd30aa5620a
tree818f6e79bfd834ec89699172a1638998c91aca3c
parentbbf8abf5d3eb6870b2235f5c18e23239872cda69

x86_64: add avx512 registers


3 files changed, 82 insertions(+), 64 deletions(-)

src/arch/x86_64/Encoding.zig+1-1
......@@ -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+33-30
......@@ -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+48-33
......@@ -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,7 +585,9 @@ 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],
......@@ -584,8 +595,12 @@ pub const Instruction = struct {
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,21 +662,21 @@ 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 }
......@@ -669,7 +684,7 @@ pub const Instruction = struct {
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,7 +882,7 @@ 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 );
......@@ -875,7 +890,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type {
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 );