@@ -419,6 +419,7 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
|
||||
// detecting features using the "-march=native" flag.
|
||||
// For more info, see X86 ISA docs.
|
||||
setFeature(cpu, .pconfig, bit(leaf.edx, 18));
|
||||
setFeature(cpu, .uintr, bit(leaf.edx, 5));
|
||||
|
||||
// TODO I feel unsure about this check.
|
||||
// It doesn't really seem to check for 7.1, just for 7.
|
||||
|
||||
@@ -1375,6 +1375,14 @@ fn asmOps(self: *CodeGen, tag: Mir.Inst.FixedTag, ops: [4]Operand) !void {
|
||||
},
|
||||
.imm => |imm0| switch (ops[1]) {
|
||||
.none => self.asmImmediate(tag, imm0),
|
||||
.reg => |reg1| switch (ops[2]) {
|
||||
.none => self.asmImmediateRegister(tag, imm0, reg1),
|
||||
else => error.InvalidInstruction,
|
||||
},
|
||||
.imm => |imm1| switch (ops[2]) {
|
||||
.none => self.asmImmediateImmediate(tag, imm0, imm1),
|
||||
else => error.InvalidInstruction,
|
||||
},
|
||||
else => error.InvalidInstruction,
|
||||
},
|
||||
.inst => |inst0| switch (ops[1]) {
|
||||
@@ -1491,9 +1499,10 @@ fn asmSetccMemory(self: *CodeGen, cc: Condition, m: Memory) !void {
|
||||
|
||||
fn asmJmpReloc(self: *CodeGen, target: Mir.Inst.Index) !Mir.Inst.Index {
|
||||
return self.addInst(.{
|
||||
.tag = .jmp,
|
||||
.tag = .j,
|
||||
.ops = .inst,
|
||||
.data = .{ .inst = .{
|
||||
.fixes = ._mp,
|
||||
.inst = target,
|
||||
} },
|
||||
});
|
||||
@@ -1753,6 +1762,42 @@ fn asmImmediate(self: *CodeGen, tag: Mir.Inst.FixedTag, imm: Immediate) !void {
|
||||
});
|
||||
}
|
||||
|
||||
fn asmImmediateRegister(self: *CodeGen, tag: Mir.Inst.FixedTag, imm: Immediate, reg: Register) !void {
|
||||
_ = try self.addInst(.{
|
||||
.tag = tag[1],
|
||||
.ops = .ir,
|
||||
.data = .{ .ri = .{
|
||||
.fixes = tag[0],
|
||||
.r1 = reg,
|
||||
.i = @as(u8, switch (imm) {
|
||||
.signed => |s| @bitCast(@as(i8, @intCast(s))),
|
||||
.unsigned => |u| @intCast(u),
|
||||
.reloc => unreachable,
|
||||
}),
|
||||
} },
|
||||
});
|
||||
}
|
||||
|
||||
fn asmImmediateImmediate(self: *CodeGen, tag: Mir.Inst.FixedTag, imm1: Immediate, imm2: Immediate) !void {
|
||||
_ = try self.addInst(.{
|
||||
.tag = tag[1],
|
||||
.ops = .ii,
|
||||
.data = .{ .ii = .{
|
||||
.fixes = tag[0],
|
||||
.i1 = switch (imm1) {
|
||||
.signed => |s| @bitCast(@as(i16, @intCast(s))),
|
||||
.unsigned => |u| @intCast(u),
|
||||
.reloc => unreachable,
|
||||
},
|
||||
.i2 = switch (imm2) {
|
||||
.signed => |s| @bitCast(@as(i8, @intCast(s))),
|
||||
.unsigned => |u| @intCast(u),
|
||||
.reloc => unreachable,
|
||||
},
|
||||
} },
|
||||
});
|
||||
}
|
||||
|
||||
fn asmRegisterRegister(self: *CodeGen, tag: Mir.Inst.FixedTag, reg1: Register, reg2: Register) !void {
|
||||
_ = try self.addInst(.{
|
||||
.tag = tag[1],
|
||||
@@ -4188,8 +4233,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
_ = try cg.asmJmpReloc(loop.target);
|
||||
},
|
||||
.br => try cg.airBr(inst),
|
||||
.trap => try cg.asmOpOnly(.{ ._, .ud2 }),
|
||||
.breakpoint => try cg.asmOpOnly(.{ ._, .int3 }),
|
||||
.trap => try cg.asmOpOnly(.{ ._2, .ud }),
|
||||
.breakpoint => try cg.asmOpOnly(.{ ._3, .int }),
|
||||
.ret_addr => if (use_old) try cg.airRetAddr(inst) else {
|
||||
var slot = try cg.tempInit(.usize, .{ .load_frame = .{
|
||||
.index = .ret_addr,
|
||||
@@ -4233,7 +4278,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.dst_temps = .{.{ .ref = .src0 }},
|
||||
.clobbers = .{ .eflags = true },
|
||||
.each = .{ .once = &.{
|
||||
.{ ._, ._, .inc, .dst0b, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .dst0b, ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
.src_constraints = .{ .{ .exact_unsigned_int = 1 }, .any },
|
||||
@@ -5643,7 +5688,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.{ ._, ._, .lzcnt, .tmp1d, .tmp1d, ._, ._ },
|
||||
.{ ._, ._, .sub, .tmp1b, .sia(32, .src0, .sub_bit_size), ._, ._ },
|
||||
.{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
|
||||
.{ ._, ._, .inc, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
@@ -5695,7 +5740,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.{ ._, ._, .lzcnt, .tmp1d, .tmp1d, ._, ._ },
|
||||
.{ ._, ._, .sub, .tmp1b, .sia(32, .src0, .sub_bit_size), ._, ._ },
|
||||
.{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
|
||||
.{ ._, ._, .inc, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
@@ -5747,7 +5792,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.{ ._, ._, .lzcnt, .tmp1d, .tmp1d, ._, ._ },
|
||||
.{ ._, ._, .sub, .tmp1b, .sia(32, .src0, .sub_bit_size), ._, ._ },
|
||||
.{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
|
||||
.{ ._, ._, .inc, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
@@ -5799,7 +5844,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.{ ._, ._, .lzcnt, .tmp1q, .tmp1q, ._, ._ },
|
||||
.{ ._, ._, .sub, .tmp1b, .sia(64, .src0, .sub_bit_size), ._, ._ },
|
||||
.{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
|
||||
.{ ._, ._, .inc, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
@@ -5857,7 +5902,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ },
|
||||
.{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ },
|
||||
.{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
|
||||
.{ ._, ._, .inc, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
@@ -5915,7 +5960,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.{ ._, ._c, .st, ._, ._, ._, ._ },
|
||||
.{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ },
|
||||
.{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ },
|
||||
.{ ._, ._, .inc, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
@@ -5970,7 +6015,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ },
|
||||
.{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ },
|
||||
.{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
|
||||
.{ ._, ._, .inc, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
@@ -6028,7 +6073,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ },
|
||||
.{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ },
|
||||
.{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
|
||||
.{ ._, ._, .inc, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
@@ -6086,7 +6131,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.{ ._, ._c, .st, ._, ._, ._, ._ },
|
||||
.{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ },
|
||||
.{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ },
|
||||
.{ ._, ._, .inc, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
@@ -6141,7 +6186,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ },
|
||||
.{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ },
|
||||
.{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
|
||||
.{ ._, ._, .inc, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
@@ -6199,7 +6244,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ },
|
||||
.{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ },
|
||||
.{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
|
||||
.{ ._, ._, .inc, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
@@ -6257,7 +6302,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.{ ._, ._c, .st, ._, ._, ._, ._ },
|
||||
.{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ },
|
||||
.{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ },
|
||||
.{ ._, ._, .inc, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
@@ -6312,7 +6357,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ },
|
||||
.{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ },
|
||||
.{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
|
||||
.{ ._, ._, .inc, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
@@ -6370,7 +6415,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ },
|
||||
.{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ },
|
||||
.{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
|
||||
.{ ._, ._, .inc, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
@@ -6428,7 +6473,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.{ ._, ._c, .st, ._, ._, ._, ._ },
|
||||
.{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ },
|
||||
.{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ },
|
||||
.{ ._, ._, .inc, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
@@ -6484,7 +6529,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
.{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ },
|
||||
.{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ },
|
||||
.{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
|
||||
.{ ._, ._, .inc, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
|
||||
.{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
|
||||
} },
|
||||
}, .{
|
||||
@@ -10094,7 +10139,7 @@ fn genLazy(self: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void {
|
||||
data_off += @intCast(tag_name_len + 1);
|
||||
}
|
||||
|
||||
try self.asmOpOnly(.{ ._, .ud2 });
|
||||
try self.asmOpOnly(.{ ._2, .ud });
|
||||
|
||||
for (epilogue_relocs) |reloc| self.performReloc(reloc);
|
||||
try self.asmOpOnly(.{ ._, .ret });
|
||||
@@ -10373,7 +10418,7 @@ fn regClassForType(self: *CodeGen, ty: Type) Register.Class {
|
||||
fn regSetForRegClass(rc: Register.Class) RegisterManager.RegisterBitSet {
|
||||
return switch (rc) {
|
||||
.general_purpose => abi.RegisterClass.gp,
|
||||
.segment, .ip => unreachable,
|
||||
.segment, .ip, .cr, .dr => unreachable,
|
||||
.x87 => abi.RegisterClass.x87,
|
||||
.mmx => @panic("TODO"),
|
||||
.sse => abi.RegisterClass.sse,
|
||||
@@ -12195,8 +12240,8 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[2].to32(), .u(1));
|
||||
try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[3].to32(), .u(1));
|
||||
} else {
|
||||
try self.asmRegister(.{ ._, .inc }, temp_regs[2].to32());
|
||||
try self.asmRegister(.{ ._, .inc }, temp_regs[3].to32());
|
||||
try self.asmRegister(.{ ._c, .in }, temp_regs[2].to32());
|
||||
try self.asmRegister(.{ ._c, .in }, temp_regs[3].to32());
|
||||
}
|
||||
try self.asmRegisterImmediate(.{ ._, .cmp }, temp_regs[3].to32(), .u(limb_len));
|
||||
_ = try self.asmJccReloc(.b, inner_loop);
|
||||
@@ -12209,7 +12254,7 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
if (slow_inc) {
|
||||
try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[2].to32(), .u(1));
|
||||
} else {
|
||||
try self.asmRegister(.{ ._, .inc }, temp_regs[2].to32());
|
||||
try self.asmRegister(.{ ._c, .in }, temp_regs[2].to32());
|
||||
}
|
||||
try self.asmMemoryImmediate(.{ ._, .cmp }, .{
|
||||
.base = .{ .frame = lhs_mcv.load_frame.index },
|
||||
@@ -12236,7 +12281,7 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
if (slow_inc) {
|
||||
try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), .u(1));
|
||||
} else {
|
||||
try self.asmRegister(.{ ._, .inc }, temp_regs[0].to32());
|
||||
try self.asmRegister(.{ ._c, .in }, temp_regs[0].to32());
|
||||
}
|
||||
try self.asmRegisterImmediate(.{ ._, .cmp }, temp_regs[0].to32(), .u(limb_len));
|
||||
_ = try self.asmJccReloc(.b, outer_loop);
|
||||
@@ -13938,7 +13983,7 @@ fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
if (self.hasFeature(.slow_incdec)) {
|
||||
try self.asmRegisterImmediate(.{ ._, .sub }, index_reg.to32(), .u(1));
|
||||
} else {
|
||||
try self.asmRegister(.{ ._, .dec }, index_reg.to32());
|
||||
try self.asmRegister(.{ ._c, .de }, index_reg.to32());
|
||||
}
|
||||
try self.asmMemoryImmediate(.{ ._, .cmp }, .{
|
||||
.base = .{ .frame = src_frame_addr.index },
|
||||
@@ -14133,7 +14178,7 @@ fn airCtz(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
if (self.hasFeature(.slow_incdec)) {
|
||||
try self.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), .u(1));
|
||||
} else {
|
||||
try self.asmRegister(.{ ._, .inc }, index_reg.to32());
|
||||
try self.asmRegister(.{ ._c, .in }, index_reg.to32());
|
||||
}
|
||||
try self.asmRegisterImmediate(.{ ._, .cmp }, index_reg.to32(), .u(limbs_len));
|
||||
const zero = try self.asmJccReloc(.nb, undefined);
|
||||
@@ -14535,8 +14580,8 @@ fn genByteSwap(
|
||||
try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), .u(1));
|
||||
try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), .u(1));
|
||||
} else {
|
||||
try self.asmRegister(.{ ._, .inc }, temp_regs[0].to32());
|
||||
try self.asmRegister(.{ ._, .dec }, temp_regs[1].to32());
|
||||
try self.asmRegister(.{ ._c, .in }, temp_regs[0].to32());
|
||||
try self.asmRegister(.{ ._c, .de }, temp_regs[1].to32());
|
||||
}
|
||||
try self.asmRegisterRegister(.{ ._, .cmp }, temp_regs[0].to32(), temp_regs[1].to32());
|
||||
_ = try self.asmJccReloc(.be, loop);
|
||||
@@ -15113,7 +15158,7 @@ fn airAbs(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
if (self.hasFeature(.slow_incdec)) {
|
||||
try self.asmRegisterImmediate(.{ ._, .add }, tmp_regs[0].to32(), .u(1));
|
||||
} else {
|
||||
try self.asmRegister(.{ ._, .inc }, tmp_regs[0].to32());
|
||||
try self.asmRegister(.{ ._c, .in }, tmp_regs[0].to32());
|
||||
}
|
||||
try self.asmRegisterImmediate(.{ ._, .cmp }, tmp_regs[0].to32(), .u(limb_len));
|
||||
_ = try self.asmJccReloc(.b, neg_loop);
|
||||
@@ -16452,8 +16497,8 @@ fn genShiftBinOpMir(
|
||||
try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), .u(1));
|
||||
try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[0].to32(), .u(1));
|
||||
} else {
|
||||
try self.asmRegister(.{ ._, .dec }, temp_regs[1].to32());
|
||||
try self.asmRegister(.{ ._, .dec }, temp_regs[0].to32());
|
||||
try self.asmRegister(.{ ._c, .de }, temp_regs[1].to32());
|
||||
try self.asmRegister(.{ ._c, .de }, temp_regs[0].to32());
|
||||
}
|
||||
_ = try self.asmJccReloc(.nz, loop);
|
||||
},
|
||||
@@ -16462,8 +16507,8 @@ fn genShiftBinOpMir(
|
||||
try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[1].to32(), .u(1));
|
||||
try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), .u(1));
|
||||
} else {
|
||||
try self.asmRegister(.{ ._, .inc }, temp_regs[1].to32());
|
||||
try self.asmRegister(.{ ._, .inc }, temp_regs[0].to32());
|
||||
try self.asmRegister(.{ ._c, .in }, temp_regs[1].to32());
|
||||
try self.asmRegister(.{ ._c, .in }, temp_regs[0].to32());
|
||||
}
|
||||
try self.asmRegisterImmediate(
|
||||
.{ ._, .cmp },
|
||||
@@ -16532,12 +16577,12 @@ fn genShiftBinOpMir(
|
||||
._l => if (slow_inc_dec) {
|
||||
try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), .u(1));
|
||||
} else {
|
||||
try self.asmRegister(.{ ._, .dec }, temp_regs[1].to32());
|
||||
try self.asmRegister(.{ ._c, .de }, temp_regs[1].to32());
|
||||
},
|
||||
._r => if (slow_inc_dec) {
|
||||
try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[1].to32(), .u(1));
|
||||
} else {
|
||||
try self.asmRegister(.{ ._, .inc }, temp_regs[1].to32());
|
||||
try self.asmRegister(.{ ._c, .in }, temp_regs[1].to32());
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
@@ -17163,8 +17208,8 @@ fn genMulDivBinOp(
|
||||
try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[2].to32(), .u(1));
|
||||
try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[3].to32(), .u(1));
|
||||
} else {
|
||||
try self.asmRegister(.{ ._, .inc }, temp_regs[2].to32());
|
||||
try self.asmRegister(.{ ._, .inc }, temp_regs[3].to32());
|
||||
try self.asmRegister(.{ ._c, .in }, temp_regs[2].to32());
|
||||
try self.asmRegister(.{ ._c, .in }, temp_regs[3].to32());
|
||||
}
|
||||
try self.asmRegisterImmediate(.{ ._, .cmp }, temp_regs[3].to32(), .u(limb_len));
|
||||
_ = try self.asmJccReloc(.b, inner_loop);
|
||||
@@ -17173,7 +17218,7 @@ fn genMulDivBinOp(
|
||||
if (slow_inc) {
|
||||
try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), .u(1));
|
||||
} else {
|
||||
try self.asmRegister(.{ ._, .inc }, temp_regs[0].to32());
|
||||
try self.asmRegister(.{ ._c, .in }, temp_regs[0].to32());
|
||||
}
|
||||
try self.asmRegisterImmediate(.{ ._, .cmp }, temp_regs[0].to32(), .u(limb_len));
|
||||
_ = try self.asmJccReloc(.b, outer_loop);
|
||||
@@ -19765,7 +19810,7 @@ fn airArg(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
if (self.hasFeature(.slow_incdec)) {
|
||||
try self.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), .u(1));
|
||||
} else {
|
||||
try self.asmRegister(.{ ._, .inc }, index_reg.to32());
|
||||
try self.asmRegister(.{ ._c, .in }, index_reg.to32());
|
||||
}
|
||||
try self.asmRegisterImmediate(
|
||||
.{ ._, .cmp },
|
||||
@@ -20042,7 +20087,7 @@ fn genCall(self: *CodeGen, info: union(enum) {
|
||||
if (self.hasFeature(.slow_incdec)) {
|
||||
try self.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), .u(1));
|
||||
} else {
|
||||
try self.asmRegister(.{ ._, .inc }, index_reg.to32());
|
||||
try self.asmRegister(.{ ._c, .in }, index_reg.to32());
|
||||
}
|
||||
try self.asmRegisterImmediate(
|
||||
.{ ._, .cmp },
|
||||
@@ -21423,7 +21468,7 @@ fn lowerSwitchBr(
|
||||
defer if (condition_index_lock) |lock| self.register_manager.unlockReg(lock);
|
||||
try self.truncateRegister(condition_ty, condition_index_reg);
|
||||
const ptr_size = @divExact(self.target.ptrBitWidth(), 8);
|
||||
try self.asmMemory(.{ ._, .jmp }, .{
|
||||
try self.asmMemory(.{ ._mp, .j }, .{
|
||||
.base = .table,
|
||||
.mod = .{ .rm = .{
|
||||
.size = .ptr,
|
||||
@@ -21720,7 +21765,7 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
defer if (condition_index_lock) |lock| self.register_manager.unlockReg(lock);
|
||||
try self.truncateRegister(condition_ty, condition_index_reg);
|
||||
const ptr_size = @divExact(self.target.ptrBitWidth(), 8);
|
||||
try self.asmMemory(.{ ._, .jmp }, .{
|
||||
try self.asmMemory(.{ ._mp, .j }, .{
|
||||
.base = .table,
|
||||
.mod = .{ .rm = .{
|
||||
.size = .ptr,
|
||||
@@ -21777,7 +21822,7 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
fn performReloc(self: *CodeGen, reloc: Mir.Inst.Index) void {
|
||||
const next_inst: u32 = @intCast(self.mir_instructions.len);
|
||||
switch (self.mir_instructions.items(.tag)[reloc]) {
|
||||
.j, .jmp => {},
|
||||
.j => {},
|
||||
.pseudo => switch (self.mir_instructions.items(.ops)[reloc]) {
|
||||
.pseudo_j_z_and_np_inst, .pseudo_j_nz_or_p_inst => {},
|
||||
else => unreachable,
|
||||
@@ -22149,65 +22194,52 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
prefix = .directive;
|
||||
}
|
||||
|
||||
var mnem_size: ?Memory.Size = if (prefix == .directive)
|
||||
null
|
||||
else if (std.mem.endsWith(u8, mnem_str, "b"))
|
||||
.byte
|
||||
else if (std.mem.endsWith(u8, mnem_str, "w"))
|
||||
.word
|
||||
else if (std.mem.endsWith(u8, mnem_str, "l"))
|
||||
.dword
|
||||
else if (std.mem.endsWith(u8, mnem_str, "q") and
|
||||
(std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq")))
|
||||
.qword
|
||||
else if (std.mem.endsWith(u8, mnem_str, "t"))
|
||||
.tbyte
|
||||
else
|
||||
null;
|
||||
const mnem_tag = while (true) break std.meta.stringToEnum(
|
||||
var mnem_size: struct {
|
||||
used: bool,
|
||||
size: ?Memory.Size,
|
||||
fn use(size: *@This()) ?Memory.Size {
|
||||
size.used = true;
|
||||
return size.size;
|
||||
}
|
||||
} = .{
|
||||
.used = false,
|
||||
.size = if (prefix == .directive)
|
||||
null
|
||||
else if (std.mem.endsWith(u8, mnem_str, "b"))
|
||||
.byte
|
||||
else if (std.mem.endsWith(u8, mnem_str, "w"))
|
||||
.word
|
||||
else if (std.mem.endsWith(u8, mnem_str, "l"))
|
||||
.dword
|
||||
else if (std.mem.endsWith(u8, mnem_str, "q") and
|
||||
(std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq")))
|
||||
.qword
|
||||
else if (std.mem.endsWith(u8, mnem_str, "t"))
|
||||
.tbyte
|
||||
else
|
||||
null,
|
||||
};
|
||||
var mnem_tag = while (true) break std.meta.stringToEnum(
|
||||
encoder.Instruction.Mnemonic,
|
||||
mnem_str[0 .. mnem_str.len - @intFromBool(mnem_size != null)],
|
||||
) orelse if (mnem_size) |_| {
|
||||
mnem_size = null;
|
||||
mnem_str[0 .. mnem_str.len - @intFromBool(mnem_size.size != null)],
|
||||
) orelse if (mnem_size.size) |_| {
|
||||
mnem_size.size = null;
|
||||
continue;
|
||||
} else return self.fail("invalid mnemonic: '{s}'", .{mnem_str});
|
||||
if (@as(?Memory.Size, switch (mnem_tag) {
|
||||
.clflush => .byte,
|
||||
.fldcw, .fnstcw, .fstcw, .fnstsw, .fstsw => .word,
|
||||
.fldenv, .fnstenv, .fstenv => .none,
|
||||
.frstor, .fsave, .fnsave, .fxrstor, .fxrstor64, .fxsave, .fxsave64 => .none,
|
||||
.invlpg => .none,
|
||||
.invpcid => .xword,
|
||||
.ldmxcsr, .stmxcsr, .vldmxcsr, .vstmxcsr => .dword,
|
||||
else => null,
|
||||
})) |fixed_mnem_size| {
|
||||
if (mnem_size) |size| if (size != fixed_mnem_size)
|
||||
if (mnem_size.size) |size| if (size != fixed_mnem_size)
|
||||
return self.fail("invalid size: '{s}'", .{mnem_str});
|
||||
mnem_size = fixed_mnem_size;
|
||||
mnem_size.size = fixed_mnem_size;
|
||||
}
|
||||
const mnem_name = @tagName(mnem_tag);
|
||||
const mnem_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive)
|
||||
.{ ._, .pseudo }
|
||||
else for (std.enums.values(Mir.Inst.Fixes)) |fixes| {
|
||||
const fixes_name = @tagName(fixes);
|
||||
const space_i = std.mem.indexOfScalar(u8, fixes_name, ' ');
|
||||
const fixes_prefix = if (space_i) |i|
|
||||
std.meta.stringToEnum(encoder.Instruction.Prefix, fixes_name[0..i]).?
|
||||
else
|
||||
.none;
|
||||
if (fixes_prefix != prefix) continue;
|
||||
const pattern = fixes_name[if (space_i) |i| i + " ".len else 0..];
|
||||
const wildcard_i = std.mem.indexOfScalar(u8, pattern, '_').?;
|
||||
const mnem_prefix = pattern[0..wildcard_i];
|
||||
const mnem_suffix = pattern[wildcard_i + "_".len ..];
|
||||
if (!std.mem.startsWith(u8, mnem_name, mnem_prefix)) continue;
|
||||
if (!std.mem.endsWith(u8, mnem_name, mnem_suffix)) continue;
|
||||
break .{ fixes, std.meta.stringToEnum(
|
||||
Mir.Inst.Tag,
|
||||
mnem_name[mnem_prefix.len .. mnem_name.len - mnem_suffix.len],
|
||||
) orelse continue };
|
||||
} else {
|
||||
assert(prefix != .none); // no combination of fixes produced a known mnemonic
|
||||
return self.fail("invalid prefix for mnemonic: '{s} {s}'", .{
|
||||
@tagName(prefix), mnem_name,
|
||||
});
|
||||
};
|
||||
|
||||
var ops: [4]Operand = @splat(.none);
|
||||
var ops_len: usize = 0;
|
||||
@@ -22236,12 +22268,13 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
op.* = .{ .mem = .{
|
||||
.base = .{ .reg = reg },
|
||||
.mod = .{ .rm = .{
|
||||
.size = mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}),
|
||||
.size = mnem_size.use() orelse
|
||||
return self.fail("unknown size: '{s}'", .{op_str}),
|
||||
.disp = disp,
|
||||
} },
|
||||
} };
|
||||
} else {
|
||||
if (mnem_size) |size| if (reg.bitSize() != size.bitSize(self.target))
|
||||
if (mnem_size.use()) |size| if (reg.bitSize() != size.bitSize(self.target))
|
||||
return self.fail("invalid register size: '{s}'", .{op_str});
|
||||
op.* = .{ .reg = reg };
|
||||
}
|
||||
@@ -22260,14 +22293,17 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
else
|
||||
return self.fail("invalid modifier: '{s}'", .{modifier}),
|
||||
.register => |reg| if (std.mem.eql(u8, modifier, ""))
|
||||
.{ .reg = reg }
|
||||
.{ .reg = if (mnem_size.use()) |size|
|
||||
registerAlias(reg, @intCast(@divExact(size.bitSize(self.target), 8)))
|
||||
else
|
||||
reg }
|
||||
else
|
||||
return self.fail("invalid modifier: '{s}'", .{modifier}),
|
||||
.memory => |addr| if (std.mem.eql(u8, modifier, "") or std.mem.eql(u8, modifier, "P"))
|
||||
.{ .mem = .{
|
||||
.base = .{ .reg = .ds },
|
||||
.mod = .{ .rm = .{
|
||||
.size = mnem_size orelse
|
||||
.size = mnem_size.use() orelse
|
||||
return self.fail("unknown size: '{s}'", .{op_str}),
|
||||
.disp = @intCast(@as(i64, @bitCast(addr))),
|
||||
} },
|
||||
@@ -22278,7 +22314,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
.{ .mem = .{
|
||||
.base = .{ .reg = reg_off.reg },
|
||||
.mod = .{ .rm = .{
|
||||
.size = mnem_size orelse
|
||||
.size = mnem_size.use() orelse
|
||||
return self.fail("unknown size: '{s}'", .{op_str}),
|
||||
.disp = reg_off.off,
|
||||
} },
|
||||
@@ -22289,7 +22325,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
.{ .mem = .{
|
||||
.base = .{ .frame = frame_addr.index },
|
||||
.mod = .{ .rm = .{
|
||||
.size = mnem_size orelse
|
||||
.size = mnem_size.use() orelse
|
||||
return self.fail("unknown size: '{s}'", .{op_str}),
|
||||
.disp = frame_addr.off,
|
||||
} },
|
||||
@@ -22307,21 +22343,12 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
else => return self.fail("invalid constraint: '{s}'", .{op_str}),
|
||||
};
|
||||
} else if (std.mem.startsWith(u8, op_str, "$")) {
|
||||
if (std.fmt.parseInt(i32, op_str["$".len..], 0)) |s| {
|
||||
if (mnem_size) |size| {
|
||||
const max = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - (size.bitSize(self.target) - 1));
|
||||
if ((if (s < 0) ~s else s) > max)
|
||||
return self.fail("invalid immediate size: '{s}'", .{op_str});
|
||||
}
|
||||
op.* = .{ .imm = .s(s) };
|
||||
} else |_| if (std.fmt.parseInt(u64, op_str["$".len..], 0)) |u| {
|
||||
if (mnem_size) |size| {
|
||||
const max = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - size.bitSize(self.target));
|
||||
if (u > max)
|
||||
return self.fail("invalid immediate size: '{s}'", .{op_str});
|
||||
}
|
||||
op.* = .{ .imm = .u(u) };
|
||||
} else |_| return self.fail("invalid immediate: '{s}'", .{op_str});
|
||||
op.* = if (std.fmt.parseInt(u64, op_str["$".len..], 0)) |u|
|
||||
.{ .imm = .u(u) }
|
||||
else |_| if (std.fmt.parseInt(i32, op_str["$".len..], 0)) |s|
|
||||
.{ .imm = .s(s) }
|
||||
else |_|
|
||||
return self.fail("invalid immediate: '{s}'", .{op_str});
|
||||
} else if (std.mem.endsWith(u8, op_str, ")")) {
|
||||
const open = std.mem.indexOfScalar(u8, op_str, '(') orelse
|
||||
return self.fail("invalid operand: '{s}'", .{op_str});
|
||||
@@ -22348,49 +22375,47 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
else
|
||||
.@"1";
|
||||
if (sib_it.next()) |_| return self.fail("invalid memory operand: '{s}'", .{op_str});
|
||||
op.* = .{
|
||||
.mem = .{
|
||||
.base = if (base_str.len > 0)
|
||||
.{ .reg = parseRegName(base_str["%%".len..]) orelse
|
||||
return self.fail("invalid base register: '{s}'", .{base_str}) }
|
||||
op.* = if (std.mem.eql(u8, base_str, "%%dx") and index_str.len == 0) .{ .reg = .dx } else .{ .mem = .{
|
||||
.base = if (base_str.len > 0)
|
||||
.{ .reg = parseRegName(base_str["%%".len..]) orelse
|
||||
return self.fail("invalid base register: '{s}'", .{base_str}) }
|
||||
else
|
||||
.none,
|
||||
.mod = .{ .rm = .{
|
||||
.size = mnem_size.use() orelse return self.fail("unknown size: '{s}'", .{op_str}),
|
||||
.index = if (index_str.len > 0)
|
||||
parseRegName(index_str["%%".len..]) orelse
|
||||
return self.fail("invalid index register: '{s}'", .{op_str})
|
||||
else
|
||||
.none,
|
||||
.mod = .{ .rm = .{
|
||||
.size = mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}),
|
||||
.index = if (index_str.len > 0)
|
||||
parseRegName(index_str["%%".len..]) orelse
|
||||
return self.fail("invalid index register: '{s}'", .{op_str})
|
||||
.scale = scale,
|
||||
.disp = if (std.mem.startsWith(u8, op_str[0..open], "%[") and
|
||||
std.mem.endsWith(u8, op_str[0..open], "]"))
|
||||
disp: {
|
||||
const colon = std.mem.indexOfScalarPos(u8, op_str[0..open], "%[".len, ':');
|
||||
const modifier = if (colon) |colon_pos|
|
||||
op_str[colon_pos + ":".len .. open - "]".len]
|
||||
else
|
||||
.none,
|
||||
.scale = scale,
|
||||
.disp = if (std.mem.startsWith(u8, op_str[0..open], "%[") and
|
||||
std.mem.endsWith(u8, op_str[0..open], "]"))
|
||||
disp: {
|
||||
const colon = std.mem.indexOfScalarPos(u8, op_str[0..open], "%[".len, ':');
|
||||
const modifier = if (colon) |colon_pos|
|
||||
op_str[colon_pos + ":".len .. open - "]".len]
|
||||
"";
|
||||
break :disp switch (args.items[
|
||||
arg_map.get(op_str["%[".len .. colon orelse open - "]".len]) orelse
|
||||
return self.fail("no matching constraint: '{s}'", .{op_str})
|
||||
]) {
|
||||
.immediate => |imm| if (std.mem.eql(u8, modifier, "") or
|
||||
std.mem.eql(u8, modifier, "c"))
|
||||
std.math.cast(i32, @as(i64, @bitCast(imm))) orelse
|
||||
return self.fail("invalid displacement: '{s}'", .{op_str})
|
||||
else
|
||||
"";
|
||||
break :disp switch (args.items[
|
||||
arg_map.get(op_str["%[".len .. colon orelse open - "]".len]) orelse
|
||||
return self.fail("no matching constraint: '{s}'", .{op_str})
|
||||
]) {
|
||||
.immediate => |imm| if (std.mem.eql(u8, modifier, "") or
|
||||
std.mem.eql(u8, modifier, "c"))
|
||||
std.math.cast(i32, @as(i64, @bitCast(imm))) orelse
|
||||
return self.fail("invalid displacement: '{s}'", .{op_str})
|
||||
else
|
||||
return self.fail("invalid modifier: '{s}'", .{modifier}),
|
||||
else => return self.fail("invalid constraint: '{s}'", .{op_str}),
|
||||
};
|
||||
} else if (open > 0)
|
||||
std.fmt.parseInt(i32, op_str[0..open], 0) catch
|
||||
return self.fail("invalid displacement: '{s}'", .{op_str})
|
||||
else
|
||||
0,
|
||||
} },
|
||||
},
|
||||
};
|
||||
return self.fail("invalid modifier: '{s}'", .{modifier}),
|
||||
else => return self.fail("invalid constraint: '{s}'", .{op_str}),
|
||||
};
|
||||
} else if (open > 0)
|
||||
std.fmt.parseInt(i32, op_str[0..open], 0) catch
|
||||
return self.fail("invalid displacement: '{s}'", .{op_str})
|
||||
else
|
||||
0,
|
||||
} },
|
||||
} };
|
||||
} else if (Label.isValid(.reference, op_str)) {
|
||||
const anon = std.ascii.isDigit(op_str[0]);
|
||||
const label_gop = try labels.getOrPut(self.gpa, op_str[0..if (anon) 1 else op_str.len]);
|
||||
@@ -22410,6 +22435,51 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
|
||||
// convert from att syntax to intel syntax
|
||||
std.mem.reverse(Operand, ops[0..ops_len]);
|
||||
if (!mnem_size.used) if (mnem_size.size) |size| {
|
||||
comptime var max_mnem_len: usize = 0;
|
||||
inline for (@typeInfo(encoder.Instruction.Mnemonic).@"enum".fields) |mnem|
|
||||
max_mnem_len = @max(mnem.name.len, max_mnem_len);
|
||||
var intel_mnem_buf: [max_mnem_len + 1]u8 = undefined;
|
||||
const intel_mnem_str = std.fmt.bufPrint(&intel_mnem_buf, "{s}{c}", .{
|
||||
@tagName(mnem_tag),
|
||||
@as(u8, switch (size) {
|
||||
.byte => 'b',
|
||||
.word => 'w',
|
||||
.dword => 'd',
|
||||
.qword => 'q',
|
||||
.tbyte => 't',
|
||||
else => unreachable,
|
||||
}),
|
||||
}) catch unreachable;
|
||||
if (std.meta.stringToEnum(encoder.Instruction.Mnemonic, intel_mnem_str)) |intel_mnem_tag| mnem_tag = intel_mnem_tag;
|
||||
};
|
||||
const mnem_name = @tagName(mnem_tag);
|
||||
const mnem_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive)
|
||||
.{ ._, .pseudo }
|
||||
else for (std.enums.values(Mir.Inst.Fixes)) |fixes| {
|
||||
const fixes_name = @tagName(fixes);
|
||||
const space_i = std.mem.indexOfScalar(u8, fixes_name, ' ');
|
||||
const fixes_prefix = if (space_i) |i|
|
||||
std.meta.stringToEnum(encoder.Instruction.Prefix, fixes_name[0..i]).?
|
||||
else
|
||||
.none;
|
||||
if (fixes_prefix != prefix) continue;
|
||||
const pattern = fixes_name[if (space_i) |i| i + " ".len else 0..];
|
||||
const wildcard_i = std.mem.indexOfScalar(u8, pattern, '_').?;
|
||||
const mnem_prefix = pattern[0..wildcard_i];
|
||||
const mnem_suffix = pattern[wildcard_i + "_".len ..];
|
||||
if (!std.mem.startsWith(u8, mnem_name, mnem_prefix)) continue;
|
||||
if (!std.mem.endsWith(u8, mnem_name, mnem_suffix)) continue;
|
||||
break .{ fixes, std.meta.stringToEnum(
|
||||
Mir.Inst.Tag,
|
||||
mnem_name[mnem_prefix.len .. mnem_name.len - mnem_suffix.len],
|
||||
) orelse continue };
|
||||
} else {
|
||||
assert(prefix != .none); // no combination of fixes produced a known mnemonic
|
||||
return self.fail("invalid prefix for mnemonic: '{s} {s}'", .{
|
||||
@tagName(prefix), mnem_name,
|
||||
});
|
||||
};
|
||||
|
||||
(if (prefix == .directive) switch (mnem_tag) {
|
||||
.@".cfi_def_cfa" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
|
||||
@@ -22815,7 +22885,7 @@ fn moveStrategy(self: *CodeGen, ty: Type, class: Register.Class, aligned: bool)
|
||||
else => {},
|
||||
},
|
||||
},
|
||||
.ip => {},
|
||||
.ip, .cr, .dr => {},
|
||||
}
|
||||
return self.fail("TODO moveStrategy for {}", .{ty.fmt(pt)});
|
||||
}
|
||||
@@ -22900,13 +22970,13 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
|
||||
for (dst_regs, &hazard_regs, 1..) |dst_reg, src_reg, hazard_index| {
|
||||
const dst_id = dst_reg.id();
|
||||
if (dst_id == src_reg.id()) continue;
|
||||
var mir_tag: Mir.Inst.Tag = .mov;
|
||||
var mir_tag: Mir.Inst.FixedTag = .{ ._, .mov };
|
||||
for (hazard_regs[hazard_index..]) |*hazard_reg| {
|
||||
if (dst_id != hazard_reg.id()) continue;
|
||||
mir_tag = .xchg;
|
||||
mir_tag = .{ ._g, .xch };
|
||||
hazard_reg.* = src_reg;
|
||||
}
|
||||
try self.asmRegisterRegister(.{ ._, mir_tag }, dst_reg.to64(), src_reg.to64());
|
||||
try self.asmRegisterRegister(mir_tag, dst_reg.to64(), src_reg.to64());
|
||||
}
|
||||
return;
|
||||
},
|
||||
@@ -23025,7 +23095,7 @@ fn genSetReg(
|
||||
else => unreachable,
|
||||
},
|
||||
.segment, .x87, .mmx, .sse => try self.genSetReg(dst_reg, ty, try self.genTypedValue(try pt.undefValue(ty)), opts),
|
||||
.ip => unreachable,
|
||||
.ip, .cr, .dr => unreachable,
|
||||
},
|
||||
.eflags => |cc| try self.asmSetccRegister(cc, dst_reg.to8()),
|
||||
.immediate => |imm| {
|
||||
@@ -23063,7 +23133,7 @@ fn genSetReg(
|
||||
registerAlias(dst_reg, abi_size),
|
||||
src_reg,
|
||||
),
|
||||
.x87, .mmx, .ip => unreachable,
|
||||
.x87, .mmx, .ip, .cr, .dr => unreachable,
|
||||
.sse => if (self.hasFeature(.sse2)) try self.asmRegisterRegister(
|
||||
switch (abi_size) {
|
||||
1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov },
|
||||
@@ -23092,7 +23162,7 @@ fn genSetReg(
|
||||
dst_reg,
|
||||
switch (src_reg.class()) {
|
||||
.general_purpose, .segment => registerAlias(src_reg, abi_size),
|
||||
.x87, .mmx, .ip => unreachable,
|
||||
.x87, .mmx, .ip, .cr, .dr => unreachable,
|
||||
.sse => try self.copyToTmpRegister(ty, src_mcv),
|
||||
},
|
||||
),
|
||||
@@ -23107,7 +23177,7 @@ fn genSetReg(
|
||||
},
|
||||
else => unreachable,
|
||||
},
|
||||
.mmx, .sse, .ip => unreachable,
|
||||
.mmx, .sse, .ip, .cr, .dr => unreachable,
|
||||
},
|
||||
.mmx => unreachable,
|
||||
.sse => switch (src_reg.class()) {
|
||||
@@ -23126,7 +23196,7 @@ fn genSetReg(
|
||||
.{ .register = try self.copyToTmpRegister(ty, src_mcv) },
|
||||
opts,
|
||||
),
|
||||
.x87, .mmx, .ip => unreachable,
|
||||
.x87, .mmx, .ip, .cr, .dr => unreachable,
|
||||
.sse => try self.asmRegisterRegister(
|
||||
@as(?Mir.Inst.FixedTag, switch (ty.scalarType(zcu).zigTypeTag(zcu)) {
|
||||
else => switch (abi_size) {
|
||||
@@ -23153,7 +23223,7 @@ fn genSetReg(
|
||||
registerAlias(src_reg, abi_size),
|
||||
),
|
||||
},
|
||||
.ip => unreachable,
|
||||
.ip, .cr, .dr => unreachable,
|
||||
},
|
||||
inline .register_pair,
|
||||
.register_triple,
|
||||
@@ -23294,7 +23364,7 @@ fn genSetReg(
|
||||
});
|
||||
return;
|
||||
},
|
||||
.segment, .mmx, .ip => unreachable,
|
||||
.segment, .mmx, .ip, .cr, .dr => unreachable,
|
||||
.x87, .sse => {},
|
||||
},
|
||||
.load_direct => |sym_index| switch (dst_reg.class()) {
|
||||
@@ -23309,7 +23379,7 @@ fn genSetReg(
|
||||
});
|
||||
return;
|
||||
},
|
||||
.segment, .mmx, .ip => unreachable,
|
||||
.segment, .mmx, .ip, .cr, .dr => unreachable,
|
||||
.x87, .sse => {},
|
||||
},
|
||||
.load_got, .load_tlv => {},
|
||||
@@ -23456,7 +23526,7 @@ fn genSetMem(
|
||||
};
|
||||
const src_alias = registerAlias(src_reg, abi_size);
|
||||
const src_size: u32 = @intCast(switch (src_alias.class()) {
|
||||
.general_purpose, .segment, .x87, .ip => @divExact(src_alias.bitSize(), 8),
|
||||
.general_purpose, .segment, .x87, .ip, .cr, .dr => @divExact(src_alias.bitSize(), 8),
|
||||
.mmx, .sse => abi_size,
|
||||
});
|
||||
const src_align: InternPool.Alignment = .fromNonzeroByteUnits(
|
||||
@@ -24240,18 +24310,18 @@ fn atomicOp(
|
||||
};
|
||||
switch (strat) {
|
||||
.lock => {
|
||||
const tag: Mir.Inst.Tag = if (rmw_op) |op| switch (op) {
|
||||
.Xchg => if (unused) .mov else .xchg,
|
||||
.Add => if (unused) .add else .xadd,
|
||||
.Sub => if (unused) .sub else .xadd,
|
||||
.And => .@"and",
|
||||
.Or => .@"or",
|
||||
.Xor => .xor,
|
||||
const mir_tag: Mir.Inst.FixedTag = if (rmw_op) |op| switch (op) {
|
||||
.Xchg => if (unused) .{ ._, .mov } else .{ ._g, .xch },
|
||||
.Add => .{ .@"lock _", if (unused) .add else .xadd },
|
||||
.Sub => .{ .@"lock _", if (unused) .sub else .xadd },
|
||||
.And => .{ .@"lock _", .@"and" },
|
||||
.Or => .{ .@"lock _", .@"or" },
|
||||
.Xor => .{ .@"lock _", .xor },
|
||||
else => unreachable,
|
||||
} else switch (order) {
|
||||
.unordered, .monotonic, .release, .acq_rel => .mov,
|
||||
.unordered, .monotonic, .release, .acq_rel => .{ ._, .mov },
|
||||
.acquire => unreachable,
|
||||
.seq_cst => .xchg,
|
||||
.seq_cst => .{ ._g, .xch },
|
||||
};
|
||||
|
||||
const dst_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
|
||||
@@ -24260,18 +24330,10 @@ fn atomicOp(
|
||||
defer self.register_manager.unlockReg(dst_lock);
|
||||
|
||||
try self.genSetReg(dst_reg, val_ty, val_mcv, .{});
|
||||
if (rmw_op == std.builtin.AtomicRmwOp.Sub and tag == .xadd) {
|
||||
if (rmw_op == std.builtin.AtomicRmwOp.Sub and mir_tag[1] == .xadd) {
|
||||
try self.genUnOpMir(.{ ._, .neg }, val_ty, dst_mcv);
|
||||
}
|
||||
try self.asmMemoryRegister(
|
||||
switch (tag) {
|
||||
.mov, .xchg => .{ ._, tag },
|
||||
.xadd, .add, .sub, .@"and", .@"or", .xor => .{ .@"lock _", tag },
|
||||
else => unreachable,
|
||||
},
|
||||
ptr_mem,
|
||||
registerAlias(dst_reg, val_abi_size),
|
||||
);
|
||||
try self.asmMemoryRegister(mir_tag, ptr_mem, registerAlias(dst_reg, val_abi_size));
|
||||
|
||||
return if (unused) .unreach else dst_mcv;
|
||||
},
|
||||
@@ -27599,7 +27661,7 @@ fn resolveCallingConventionValues(
|
||||
break :return_value .init(.{ .register = registerAlias(ret_gpr[0], ret_size) })
|
||||
else if (ret_gpr.len >= 2 and ret_ty.isSliceAtRuntime(zcu))
|
||||
break :return_value .init(.{ .register_pair = ret_gpr[0..2].* }),
|
||||
.segment, .mmx, .ip => unreachable,
|
||||
.segment, .mmx, .ip, .cr, .dr => unreachable,
|
||||
.x87 => break :return_value .init(.{ .register = .st0 }),
|
||||
.sse => if (ret_size <= self.vectorSize(.float)) break :return_value .init(.{
|
||||
.register = registerAlias(abi.getCAbiSseReturnRegs(cc)[0], @max(ret_size, 16)),
|
||||
@@ -27634,7 +27696,7 @@ fn resolveCallingConventionValues(
|
||||
param_gpr = param_gpr[2..];
|
||||
continue;
|
||||
},
|
||||
.segment, .mmx, .ip => unreachable,
|
||||
.segment, .mmx, .ip, .cr, .dr => unreachable,
|
||||
.x87 => if (param_x87.len >= 1) {
|
||||
arg.* = .{ .register = param_x87[0] };
|
||||
param_x87 = param_x87[1..];
|
||||
@@ -27686,9 +27748,9 @@ fn failMsg(self: *CodeGen, msg: *Zcu.ErrorMsg) error{ OutOfMemory, CodegenFail }
|
||||
}
|
||||
|
||||
fn parseRegName(name: []const u8) ?Register {
|
||||
if (@hasDecl(Register, "parseRegName")) {
|
||||
return Register.parseRegName(name);
|
||||
}
|
||||
if (std.mem.startsWith(u8, name, "db")) return @enumFromInt(
|
||||
@intFromEnum(Register.dr0) + (std.fmt.parseInt(u4, name["db".len..], 0) catch return null),
|
||||
);
|
||||
return std.meta.stringToEnum(Register, name);
|
||||
}
|
||||
|
||||
@@ -27733,6 +27795,14 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {
|
||||
.rip
|
||||
else
|
||||
unreachable,
|
||||
.cr => if (size_bytes <= 8)
|
||||
reg
|
||||
else
|
||||
unreachable,
|
||||
.dr => if (size_bytes <= 8)
|
||||
reg
|
||||
else
|
||||
unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,21 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
|
||||
.op2 = .{ .imm = imm },
|
||||
});
|
||||
},
|
||||
.ii => {
|
||||
const imm1 = try dis.parseImm(enc.data.ops[0]);
|
||||
const imm2 = try dis.parseImm(enc.data.ops[1]);
|
||||
return inst(enc, .{
|
||||
.op1 = .{ .imm = imm1 },
|
||||
.op2 = .{ .imm = imm2 },
|
||||
});
|
||||
},
|
||||
.ia => {
|
||||
const imm = try dis.parseImm(enc.data.ops[0]);
|
||||
return inst(enc, .{
|
||||
.op1 = .{ .imm = imm },
|
||||
.op2 = .{ .reg = .eax },
|
||||
});
|
||||
},
|
||||
.m, .mi, .m1, .mc => {
|
||||
const modrm = try dis.parseModRmByte();
|
||||
const act_enc = Encoding.findByOpcode(enc.opcode(), .{
|
||||
@@ -241,7 +256,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
|
||||
.op3 = op3,
|
||||
});
|
||||
},
|
||||
.rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => unreachable, // TODO
|
||||
.rm0, .vm, .vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => unreachable, // TODO
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,32 @@ pub fn findByMnemonic(
|
||||
next: for (mnemonic_to_encodings_map[@intFromEnum(mnemonic)]) |data| {
|
||||
if (!switch (data.feature) {
|
||||
.none => true,
|
||||
.@"32bit" => switch (target.cpu.arch) {
|
||||
else => unreachable,
|
||||
.x86 => true,
|
||||
.x86_64 => false,
|
||||
},
|
||||
.@"64bit" => switch (target.cpu.arch) {
|
||||
else => unreachable,
|
||||
.x86 => false,
|
||||
.x86_64 => true,
|
||||
},
|
||||
inline .@"invpcid 32bit", .@"rdpid 32bit" => |tag| switch (target.cpu.arch) {
|
||||
else => unreachable,
|
||||
.x86 => std.Target.x86.featureSetHas(
|
||||
target.cpu.features,
|
||||
@field(std.Target.x86.Feature, @tagName(tag)[0 .. @tagName(tag).len - " 32bit".len]),
|
||||
),
|
||||
.x86_64 => false,
|
||||
},
|
||||
inline .@"invpcid 64bit", .@"rdpid 64bit" => |tag| switch (target.cpu.arch) {
|
||||
else => unreachable,
|
||||
.x86 => false,
|
||||
.x86_64 => std.Target.x86.featureSetHas(
|
||||
target.cpu.features,
|
||||
@field(std.Target.x86.Feature, @tagName(tag)[0 .. @tagName(tag).len - " 64bit".len]),
|
||||
),
|
||||
},
|
||||
inline else => |tag| has_features: {
|
||||
comptime var feature_it = std.mem.splitScalar(u8, @tagName(tag), ' ');
|
||||
comptime var features: []const std.Target.x86.Feature = &.{};
|
||||
@@ -126,7 +152,7 @@ pub fn mandatoryPrefix(encoding: *const Encoding) ?u8 {
|
||||
|
||||
pub fn modRmExt(encoding: Encoding) u3 {
|
||||
return switch (encoding.data.op_en) {
|
||||
.m, .mi, .m1, .mc, .vmi => encoding.data.modrm_ext,
|
||||
.ia, .m, .mi, .m1, .mc, .vm, .vmi => encoding.data.modrm_ext,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
@@ -176,7 +202,7 @@ pub fn format(
|
||||
for (opc) |byte| try writer.print("{x:0>2} ", .{byte});
|
||||
|
||||
switch (encoding.data.op_en) {
|
||||
.z, .fd, .td, .i, .zi, .d => {},
|
||||
.z, .fd, .td, .i, .zi, .ii, .d => {},
|
||||
.o, .zo, .oz, .oi => {
|
||||
const op = switch (encoding.data.op_en) {
|
||||
.o, .oz, .oi => encoding.data.ops[0],
|
||||
@@ -192,17 +218,24 @@ pub fn format(
|
||||
};
|
||||
try writer.print("+{s} ", .{tag});
|
||||
},
|
||||
.m, .mi, .m1, .mc, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}),
|
||||
.ia, .m, .mi, .m1, .mc, .vm, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}),
|
||||
.mr, .rm, .rmi, .mri, .mrc, .rm0, .rvm, .rvmr, .rvmi, .mvr, .rmv => try writer.writeAll("/r "),
|
||||
}
|
||||
|
||||
switch (encoding.data.op_en) {
|
||||
.i, .d, .zi, .oi, .mi, .rmi, .mri, .vmi, .rvmi => {
|
||||
const op = switch (encoding.data.op_en) {
|
||||
.i, .d => encoding.data.ops[0],
|
||||
.zi, .oi, .mi => encoding.data.ops[1],
|
||||
.rmi, .mri, .vmi => encoding.data.ops[2],
|
||||
.rvmi => encoding.data.ops[3],
|
||||
.i, .d, .zi, .ii, .ia, .oi, .mi, .rmi, .mri, .vmi, .rvmi => for (0..2) |i| {
|
||||
const op = switch (i) {
|
||||
0 => switch (encoding.data.op_en) {
|
||||
.i, .ii, .ia, .d => encoding.data.ops[0],
|
||||
.zi, .oi, .mi => encoding.data.ops[1],
|
||||
.rmi, .mri, .vmi => encoding.data.ops[2],
|
||||
.rvmi => encoding.data.ops[3],
|
||||
else => unreachable,
|
||||
},
|
||||
1 => switch (encoding.data.op_en) {
|
||||
.ii => encoding.data.ops[1],
|
||||
else => break,
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
const tag = switch (op) {
|
||||
@@ -218,13 +251,13 @@ pub fn format(
|
||||
try writer.print("{s} ", .{tag});
|
||||
},
|
||||
.rvmr => try writer.writeAll("/is4 "),
|
||||
.z, .fd, .td, .o, .zo, .oz, .m, .m1, .mc, .mr, .rm, .mrc, .rm0, .rvm, .mvr, .rmv => {},
|
||||
.z, .fd, .td, .o, .zo, .oz, .m, .m1, .mc, .mr, .rm, .mrc, .rm0, .vm, .rvm, .mvr, .rmv => {},
|
||||
}
|
||||
|
||||
try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
|
||||
|
||||
for (encoding.data.ops) |op| switch (op) {
|
||||
.none, .o16, .o32, .o64 => break,
|
||||
.none => break,
|
||||
else => try writer.print("{s} ", .{@tagName(op)}),
|
||||
};
|
||||
|
||||
@@ -253,48 +286,67 @@ pub const Mnemonic = enum {
|
||||
@".cfi_escape",
|
||||
// zig fmt: off
|
||||
// General-purpose
|
||||
adc, add, @"and",
|
||||
bsf, bsr, bswap, bt, btc, btr, bts,
|
||||
aaa, aad, aam, aas, adc, add, @"and", arpl,
|
||||
bound, bsf, bsr, bswap, bt, btc, btr, bts,
|
||||
call, cbw, cdq, cdqe,
|
||||
clac, clc, cld, clflush, cli, clts, clui,
|
||||
clac, clc, cld, cldemote, clflush, clflushopt, cli, clts, clui, clrssbsy, clwb, cmc,
|
||||
cmova, cmovae, cmovb, cmovbe, cmovc, cmove, cmovg, cmovge, cmovl, cmovle, cmovna,
|
||||
cmovnae, cmovnb, cmovnbe, cmovnc, cmovne, cmovng, cmovnge, cmovnl, cmovnle, cmovno,
|
||||
cmovnp, cmovns, cmovnz, cmovo, cmovp, cmovpe, cmovpo, cmovs, cmovz,
|
||||
cmp,
|
||||
cmps, cmpsb, cmpsd, cmpsq, cmpsw,
|
||||
cmpxchg, cmpxchg8b, cmpxchg16b,
|
||||
cmp, cmps, cmpsb, cmpsd, cmpsq, cmpsw, cmpxchg, cmpxchg8b, cmpxchg16b,
|
||||
cpuid, cqo, cwd, cwde,
|
||||
dec, div, idiv, imul, inc, int3,
|
||||
ja, jae, jb, jbe, jc, jrcxz, je, jg, jge, jl, jle, jna, jnae, jnb, jnbe,
|
||||
jnc, jne, jng, jnge, jnl, jnle, jno, jnp, jns, jnz, jo, jp, jpe, jpo, js, jz,
|
||||
jmp,
|
||||
lea, lfence,
|
||||
daa, das, dec, div,
|
||||
endbr32, endbr64, enqcmd, enqcmds, enter,
|
||||
hlt, hreset,
|
||||
idiv, imul, in, inc, incsspd, incsspq, ins, insb, insd, insw,
|
||||
int, int1, int3, into, invd, invlpg, invpcid, iret, iretd, iretq, iretw,
|
||||
ja, jae, jb, jbe, jc, jcxz, je, jecxz, jg, jge, jl, jle, jmp, jna, jnae, jnb, jnbe,
|
||||
jnc, jne, jng, jnge, jnl, jnle, jno, jnp, jns, jnz, jo, jp, jpe, jpo, jrcxz, js, jz,
|
||||
lahf, lar, lea, leave, lfence, lgdt, lidt, lldt, lmsw, loop, loope, loopne,
|
||||
lods, lodsb, lodsd, lodsq, lodsw,
|
||||
lzcnt,
|
||||
lsl, ltr, lzcnt,
|
||||
mfence, mov, movbe,
|
||||
movs, movsb, movsd, movsq, movsw,
|
||||
movsx, movsxd, movzx, mul,
|
||||
neg, nop, not,
|
||||
@"or",
|
||||
pause, pop, popcnt, popfq, push, pushfq,
|
||||
rcl, rcr, ret, rol, ror, rorx,
|
||||
sal, sar, sarx, sbb,
|
||||
@"or", out, outs, outsb, outsd, outsw,
|
||||
pause, pop, popcnt, popf, popfd, popfq, push, pushfq,
|
||||
rcl, rcr,
|
||||
rdfsbase, rdgsbase, rdmsr, rdpid, rdpkru, rdpmc, rdrand, rdseed, rdssd, rdssq, rdtsc, rdtscp,
|
||||
ret, rol, ror, rorx, rsm,
|
||||
sahf, sal, sar, sarx, sbb,
|
||||
scas, scasb, scasd, scasq, scasw,
|
||||
senduipi, serialize,
|
||||
shl, shld, shlx, shr, shrd, shrx,
|
||||
stac, stc, std, sti, stui,
|
||||
sub, syscall,
|
||||
stac, stc, std, sti, str, stui,
|
||||
sub, swapgs, syscall, sysenter, sysexit, sysret,
|
||||
seta, setae, setb, setbe, setc, sete, setg, setge, setl, setle, setna, setnae,
|
||||
setnb, setnbe, setnc, setne, setng, setnge, setnl, setnle, setno, setnp, setns,
|
||||
setnz, seto, setp, setpe, setpo, sets, setz,
|
||||
sfence,
|
||||
sfence, sidt, sldt, smsw,
|
||||
stos, stosb, stosd, stosq, stosw,
|
||||
@"test", tzcnt,
|
||||
ud2,
|
||||
xadd, xchg, xgetbv, xor,
|
||||
@"test", testui, tpause,
|
||||
ud0, ud1, ud2, uiret, umonitor, umwait,
|
||||
verr, verw, wrfsbase, wrgsbase, wrmsr, wrpkru, wrssd, wrssq, wrussd, wrussq,
|
||||
xadd, xchg, xgetbv, xlat, xlatb, xor,
|
||||
// X87
|
||||
fabs, fchs, ffree, fisttp, fld, fldenv, fnstenv, fst, fstenv, fstp,
|
||||
f2xm1, fabs, fadd, faddp, fbld, fbstp, fchs, fclex,
|
||||
fcmovb, fcmovbe, fcmove, fcmovnb, fcmovnbe, fcmovne, fcmovnu, fcmovu,
|
||||
fcom, fcomi, fcomip, fcomp, fcompp, fcos,
|
||||
fdecstp, fdiv, fdivp, fdivr, fdivrp, ffree,
|
||||
fiadd, ficom, ficomp, fidiv, fidivr, fild, fimul, fincstp, finit,
|
||||
fist, fistp, fisttp, fisub, fisubr,
|
||||
fld, fld1, fldcw, fldenv, fldl2e, fldl2t, fldlg2, fldln2, fldpi, fldz,
|
||||
fmul, fmulp,
|
||||
fnclex, fninit, fnop, fnsave, fnstcw, fnstenv, fnstsw,
|
||||
fpatan, fprem, fprem1, fptan, frndint, frstor,
|
||||
fsave, fscale, fsin, fsincos, fsqrt,
|
||||
fst, fstcw, fstenv, fstp, fstsw,
|
||||
fsub, fsubp, fsubr, fsubrp,
|
||||
ftst, fucom, fucomi, fucomip, fucomp, fucompp,
|
||||
fwait, fxam, fxch, fxtract, fyl2x, fyl2xp1, wait,
|
||||
// MMX
|
||||
movd, movq,
|
||||
emms, movd, movq,
|
||||
packssdw, packsswb, packuswb,
|
||||
paddb, paddd, paddq, paddsb, paddsw, paddusb, paddusw, paddw,
|
||||
pand, pandn, por, pxor,
|
||||
@@ -312,6 +364,7 @@ pub const Mnemonic = enum {
|
||||
cmpps, cmpss,
|
||||
cvtpi2ps, cvtps2pi, cvtsi2ss, cvtss2si, cvttps2pi, cvttss2si,
|
||||
divps, divss,
|
||||
fxrstor, fxrstor64, fxsave, fxsave64,
|
||||
ldmxcsr,
|
||||
maxps, maxss,
|
||||
minps, minss,
|
||||
@@ -333,10 +386,12 @@ pub const Mnemonic = enum {
|
||||
andpd,
|
||||
andnpd,
|
||||
cmppd, //cmpsd,
|
||||
comisd, comiss,
|
||||
cvtdq2pd, cvtdq2ps, cvtpd2dq, cvtpd2pi, cvtpd2ps, cvtpi2pd,
|
||||
cvtps2dq, cvtps2pd, cvtsd2si, cvtsd2ss, cvtsi2sd, cvtss2sd,
|
||||
cvttpd2dq, cvttpd2pi, cvttps2dq, cvttsd2si,
|
||||
divpd, divsd,
|
||||
gf2p8affineinvqb, gf2p8affineqb, gf2p8mulb,
|
||||
maxpd, maxsd,
|
||||
minpd, minsd,
|
||||
movapd,
|
||||
@@ -357,11 +412,12 @@ pub const Mnemonic = enum {
|
||||
ucomisd,
|
||||
xorpd,
|
||||
// SSE3
|
||||
movddup, movshdup, movsldup,
|
||||
addsubpd, addsubps, haddpd, haddps, lddqu, movddup, movshdup, movsldup,
|
||||
// SSSE3
|
||||
pabsb, pabsd, pabsw, palignr, pshufb,
|
||||
// SSE4.1
|
||||
blendpd, blendps, blendvpd, blendvps,
|
||||
dppd, dpps,
|
||||
extractps,
|
||||
insertps,
|
||||
packusdw,
|
||||
@@ -376,28 +432,32 @@ pub const Mnemonic = enum {
|
||||
ptest,
|
||||
roundpd, roundps, roundsd, roundss,
|
||||
// SSE4.2
|
||||
pcmpgtq,
|
||||
crc32, pcmpgtq,
|
||||
// PCLMUL
|
||||
pclmulqdq,
|
||||
// AES
|
||||
aesdec, aesdeclast, aesenc, aesenclast, aesimc, aeskeygenassist,
|
||||
// SHA
|
||||
sha256msg1, sha256msg2, sha256rnds2,
|
||||
sha1rnds4, sha1nexte, sha1msg1, sha1msg2, sha256msg1, sha256msg2, sha256rnds2,
|
||||
// AVX
|
||||
vaddpd, vaddps, vaddsd, vaddss,
|
||||
andn, bextr, blsi, blsmsk, blsr, bzhi, tzcnt,
|
||||
vaddpd, vaddps, vaddsd, vaddss, vaddsubpd, vaddsubps,
|
||||
vaesdec, vaesdeclast, vaesenc, vaesenclast, vaesimc, vaeskeygenassist,
|
||||
vandnpd, vandnps, vandpd, vandps,
|
||||
vblendpd, vblendps, vblendvpd, vblendvps,
|
||||
vbroadcastf128, vbroadcastsd, vbroadcastss,
|
||||
vcmppd, vcmpps, vcmpsd, vcmpss,
|
||||
vcmppd, vcmpps, vcmpsd, vcmpss, vcomisd, vcomiss,
|
||||
vcvtdq2pd, vcvtdq2ps, vcvtpd2dq, vcvtpd2ps,
|
||||
vcvtps2dq, vcvtps2pd, vcvtsd2si, vcvtsd2ss,
|
||||
vcvtsi2sd, vcvtsi2ss, vcvtss2sd, vcvtss2si,
|
||||
vcvttpd2dq, vcvttps2dq, vcvttsd2si, vcvttss2si,
|
||||
vdivpd, vdivps, vdivsd, vdivss,
|
||||
vdppd, vdpps,
|
||||
vextractf128, vextractps,
|
||||
vgf2p8affineinvqb, vgf2p8affineqb, vgf2p8mulb,
|
||||
vhaddpd, vhaddps,
|
||||
vinsertf128, vinsertps,
|
||||
vldmxcsr,
|
||||
vlddqu, vldmxcsr,
|
||||
vmaxpd, vmaxps, vmaxsd, vmaxss,
|
||||
vminpd, vminps, vminsd, vminss,
|
||||
vmovapd, vmovaps,
|
||||
@@ -455,6 +515,12 @@ pub const Mnemonic = enum {
|
||||
// AVX2
|
||||
vbroadcasti128, vpbroadcastb, vpbroadcastd, vpbroadcastq, vpbroadcastw,
|
||||
vextracti128, vinserti128, vpblendd,
|
||||
// ADX
|
||||
adcx, adox,
|
||||
// AESKLE
|
||||
aesdec128kl, aesdec256kl, aesenc128kl, aesenc256kl, encodekey128, encodekey256, loadiwkey,
|
||||
// AESKLEWIDE_KL
|
||||
aesdecwide128kl, aesdecwide256kl, aesencwide128kl, aesencwide256kl,
|
||||
// zig fmt: on
|
||||
};
|
||||
|
||||
@@ -462,24 +528,23 @@ pub const OpEn = enum {
|
||||
// zig fmt: off
|
||||
z,
|
||||
o, zo, oz, oi,
|
||||
i, zi,
|
||||
i, zi, ii, ia,
|
||||
d, m,
|
||||
fd, td,
|
||||
m1, mc, mi, mr, rm,
|
||||
rmi, mri, mrc,
|
||||
rm0, vmi, rvm, rvmr, rvmi, mvr, rmv,
|
||||
rm0, vm, vmi, rvm, rvmr, rvmi, mvr, rmv,
|
||||
// zig fmt: on
|
||||
};
|
||||
|
||||
pub const Op = enum {
|
||||
// zig fmt: off
|
||||
none,
|
||||
o16, o32, o64,
|
||||
unity,
|
||||
imm8, imm16, imm32, imm64,
|
||||
imm8s, imm16s, imm32s,
|
||||
al, ax, eax, rax,
|
||||
cl,
|
||||
cl, dx,
|
||||
rip, eip, ip,
|
||||
r8, r16, r32, r64,
|
||||
rm8, rm16, rm32, rm64,
|
||||
@@ -489,9 +554,10 @@ pub const Op = enum {
|
||||
m,
|
||||
moffs,
|
||||
sreg,
|
||||
st, mm, mm_m64,
|
||||
st0, st, mm, mm_m64,
|
||||
xmm0, xmm, xmm_m8, xmm_m16, xmm_m32, xmm_m64, xmm_m128,
|
||||
ymm, ymm_m256,
|
||||
cr, dr,
|
||||
// zig fmt: on
|
||||
|
||||
pub fn fromOperand(operand: Instruction.Operand, target: *const std.Target) Op {
|
||||
@@ -499,32 +565,34 @@ pub const Op = enum {
|
||||
.none => .none,
|
||||
|
||||
.reg => |reg| switch (reg.class()) {
|
||||
.general_purpose => if (reg.to64() == .rax)
|
||||
switch (reg) {
|
||||
.al => .al,
|
||||
.ax => .ax,
|
||||
.eax => .eax,
|
||||
.rax => .rax,
|
||||
.general_purpose => switch (reg) {
|
||||
.al => .al,
|
||||
.ax => .ax,
|
||||
.eax => .eax,
|
||||
.rax => .rax,
|
||||
.cl => .cl,
|
||||
.dx => .dx,
|
||||
else => switch (reg.bitSize()) {
|
||||
8 => .r8,
|
||||
16 => .r16,
|
||||
32 => .r32,
|
||||
64 => .r64,
|
||||
else => unreachable,
|
||||
}
|
||||
else if (reg == .cl)
|
||||
.cl
|
||||
else switch (reg.bitSize()) {
|
||||
8 => .r8,
|
||||
16 => .r16,
|
||||
32 => .r32,
|
||||
64 => .r64,
|
||||
else => unreachable,
|
||||
},
|
||||
},
|
||||
.segment => .sreg,
|
||||
.x87 => .st,
|
||||
.x87 => switch (reg) {
|
||||
.st0 => .st0,
|
||||
else => .st,
|
||||
},
|
||||
.mmx => .mm,
|
||||
.sse => if (reg == .xmm0)
|
||||
.xmm0
|
||||
else switch (reg.bitSize()) {
|
||||
128 => .xmm,
|
||||
256 => .ymm,
|
||||
else => unreachable,
|
||||
.sse => switch (reg) {
|
||||
.xmm0 => .xmm0,
|
||||
else => switch (reg.bitSize()) {
|
||||
128 => .xmm,
|
||||
256 => .ymm,
|
||||
else => unreachable,
|
||||
},
|
||||
},
|
||||
.ip => switch (reg) {
|
||||
.rip => .rip,
|
||||
@@ -532,6 +600,8 @@ pub const Op = enum {
|
||||
.ip => .ip,
|
||||
else => unreachable,
|
||||
},
|
||||
.cr => .cr,
|
||||
.dr => .dr,
|
||||
},
|
||||
|
||||
.mem => |mem| switch (mem) {
|
||||
@@ -588,24 +658,27 @@ pub const Op = enum {
|
||||
.eax => .eax,
|
||||
.rax => .rax,
|
||||
.cl => .cl,
|
||||
.dx => .dx,
|
||||
.rip => .rip,
|
||||
.eip => .eip,
|
||||
.ip => .ip,
|
||||
.st0 => .st0,
|
||||
.xmm0 => .xmm0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn immBitSize(op: Op) u64 {
|
||||
return switch (op) {
|
||||
.none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
|
||||
.al, .cl, .rip, .eip, .ip, .r8, .rm8, .r32_m8 => unreachable,
|
||||
.none, .moffs, .m, .sreg => unreachable,
|
||||
.al, .cl, .dx, .rip, .eip, .ip, .r8, .rm8, .r32_m8 => unreachable,
|
||||
.ax, .r16, .rm16 => unreachable,
|
||||
.eax, .r32, .rm32, .r32_m16 => unreachable,
|
||||
.rax, .r64, .rm64, .r64_m16 => unreachable,
|
||||
.st, .mm, .mm_m64 => unreachable,
|
||||
.st0, .st, .mm, .mm_m64 => unreachable,
|
||||
.xmm0, .xmm, .xmm_m8, .xmm_m16, .xmm_m32, .xmm_m64, .xmm_m128 => unreachable,
|
||||
.ymm, .ymm_m256 => unreachable,
|
||||
.m8, .m16, .m32, .m64, .m80, .m128, .m256 => unreachable,
|
||||
.cr, .dr => unreachable,
|
||||
.unity => 1,
|
||||
.imm8, .imm8s, .rel8 => 8,
|
||||
.imm16, .imm16s, .rel16 => 16,
|
||||
@@ -616,15 +689,15 @@ pub const Op = enum {
|
||||
|
||||
pub fn regBitSize(op: Op) u64 {
|
||||
return switch (op) {
|
||||
.none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
|
||||
.none, .moffs, .m, .sreg => unreachable,
|
||||
.unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable,
|
||||
.rel8, .rel16, .rel32 => unreachable,
|
||||
.m8, .m16, .m32, .m64, .m80, .m128, .m256 => unreachable,
|
||||
.al, .cl, .r8, .rm8 => 8,
|
||||
.ax, .ip, .r16, .rm16 => 16,
|
||||
.ax, .dx, .ip, .r16, .rm16 => 16,
|
||||
.eax, .eip, .r32, .rm32, .r32_m8, .r32_m16 => 32,
|
||||
.rax, .rip, .r64, .rm64, .r64_m16, .mm, .mm_m64 => 64,
|
||||
.st => 80,
|
||||
.rax, .rip, .r64, .rm64, .r64_m16, .mm, .mm_m64, .cr, .dr => 64,
|
||||
.st0, .st => 80,
|
||||
.xmm0, .xmm, .xmm_m8, .xmm_m16, .xmm_m32, .xmm_m64, .xmm_m128 => 128,
|
||||
.ymm, .ymm_m256 => 256,
|
||||
};
|
||||
@@ -632,11 +705,12 @@ pub const Op = enum {
|
||||
|
||||
pub fn memBitSize(op: Op) u64 {
|
||||
return switch (op) {
|
||||
.none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
|
||||
.none, .moffs, .m, .sreg => unreachable,
|
||||
.unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable,
|
||||
.rel8, .rel16, .rel32 => unreachable,
|
||||
.al, .cl, .r8, .ax, .ip, .r16, .eax, .eip, .r32, .rax, .rip, .r64 => unreachable,
|
||||
.st, .mm, .xmm0, .xmm, .ymm => unreachable,
|
||||
.al, .cl, .r8, .ax, .dx, .ip, .r16, .eax, .eip, .r32, .rax, .rip, .r64 => unreachable,
|
||||
.st0, .st, .mm, .xmm0, .xmm, .ymm => unreachable,
|
||||
.cr, .dr => unreachable,
|
||||
.m8, .rm8, .r32_m8, .xmm_m8 => 8,
|
||||
.m16, .rm16, .r32_m16, .r64_m16, .xmm_m16 => 16,
|
||||
.m32, .rm32, .xmm_m32 => 32,
|
||||
@@ -664,14 +738,15 @@ pub const Op = enum {
|
||||
// zig fmt: off
|
||||
return switch (op) {
|
||||
.al, .ax, .eax, .rax,
|
||||
.cl,
|
||||
.cl, .dx,
|
||||
.ip, .eip, .rip,
|
||||
.r8, .r16, .r32, .r64,
|
||||
.rm8, .rm16, .rm32, .rm64,
|
||||
.r32_m8, .r32_m16, .r64_m16,
|
||||
.st, .mm, .mm_m64,
|
||||
.st0, .st, .mm, .mm_m64,
|
||||
.xmm0, .xmm, .xmm_m8, .xmm_m16, .xmm_m32, .xmm_m64, .xmm_m128,
|
||||
.ymm, .ymm_m256,
|
||||
.cr, .dr,
|
||||
=> true,
|
||||
else => false,
|
||||
};
|
||||
@@ -717,33 +792,34 @@ pub const Op = enum {
|
||||
pub fn class(op: Op) bits.Register.Class {
|
||||
return switch (op) {
|
||||
else => unreachable,
|
||||
.al, .ax, .eax, .rax, .cl => .general_purpose,
|
||||
.al, .ax, .eax, .rax, .cl, .dx => .general_purpose,
|
||||
.r8, .r16, .r32, .r64 => .general_purpose,
|
||||
.rm8, .rm16, .rm32, .rm64 => .general_purpose,
|
||||
.r32_m8, .r32_m16, .r64_m16 => .general_purpose,
|
||||
.sreg => .segment,
|
||||
.st => .x87,
|
||||
.st0, .st => .x87,
|
||||
.mm, .mm_m64 => .mmx,
|
||||
.xmm0, .xmm, .xmm_m8, .xmm_m16, .xmm_m32, .xmm_m64, .xmm_m128 => .sse,
|
||||
.ymm, .ymm_m256 => .sse,
|
||||
.rip, .eip, .ip => .ip,
|
||||
.cr => .cr,
|
||||
.dr => .dr,
|
||||
};
|
||||
}
|
||||
|
||||
/// Given an operand `op` checks if `target` is a subset for the purposes of the encoding.
|
||||
pub fn isSubset(op: Op, target: Op) bool {
|
||||
switch (op) {
|
||||
.o16, .o32, .o64 => unreachable,
|
||||
.moffs, .sreg => return op == target,
|
||||
.none => switch (target) {
|
||||
.o16, .o32, .o64, .none => return true,
|
||||
.none => return true,
|
||||
else => return false,
|
||||
},
|
||||
else => {
|
||||
if (op.isRegister() and target.isRegister()) {
|
||||
return switch (target) {
|
||||
.cl, .al, .ax, .eax, .rax, .xmm0 => op == target,
|
||||
else => op.class() == target.class() and op.regBitSize() == target.regBitSize(),
|
||||
return switch (target.toReg()) {
|
||||
.none => op.class() == target.class() and op.regBitSize() == target.regBitSize(),
|
||||
else => op == target,
|
||||
};
|
||||
}
|
||||
if (op.isMemory() and target.isMemory()) {
|
||||
@@ -779,6 +855,7 @@ pub const Mode = enum {
|
||||
none,
|
||||
short, long,
|
||||
rex, rex_short,
|
||||
wait,
|
||||
vex_128_w0, vex_128_w1, vex_128_wig,
|
||||
vex_256_w0, vex_256_w1, vex_256_wig,
|
||||
vex_lig_w0, vex_lig_w1, vex_lig_wig,
|
||||
@@ -841,20 +918,46 @@ pub const Mode = enum {
|
||||
|
||||
pub const Feature = enum {
|
||||
none,
|
||||
@"32bit",
|
||||
@"64bit",
|
||||
adx,
|
||||
aes,
|
||||
@"aes avx",
|
||||
avx,
|
||||
avx2,
|
||||
bmi,
|
||||
bmi2,
|
||||
cldemote,
|
||||
clflushopt,
|
||||
clwb,
|
||||
cmov,
|
||||
@"cmov x87",
|
||||
crc32,
|
||||
enqcmd,
|
||||
f16c,
|
||||
fma,
|
||||
fsgsbase,
|
||||
fxsr,
|
||||
gfni,
|
||||
@"gfni avx",
|
||||
hreset,
|
||||
@"invpcid 32bit",
|
||||
@"invpcid 64bit",
|
||||
kl,
|
||||
lzcnt,
|
||||
mmx,
|
||||
movbe,
|
||||
pclmul,
|
||||
@"pclmul avx",
|
||||
pku,
|
||||
popcnt,
|
||||
rdrnd,
|
||||
rdseed,
|
||||
@"rdpid 32bit",
|
||||
@"rdpid 64bit",
|
||||
sahf,
|
||||
serialize,
|
||||
shstk,
|
||||
smap,
|
||||
sse,
|
||||
sse2,
|
||||
@@ -866,6 +969,8 @@ pub const Feature = enum {
|
||||
uintr,
|
||||
vaes,
|
||||
vpclmulqdq,
|
||||
waitpkg,
|
||||
widekl,
|
||||
x87,
|
||||
};
|
||||
|
||||
@@ -886,7 +991,7 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
|
||||
}
|
||||
|
||||
const mnemonic_to_encodings_map = init: {
|
||||
@setEvalBranchQuota(5_000);
|
||||
@setEvalBranchQuota(5_600);
|
||||
const mnemonic_count = @typeInfo(Mnemonic).@"enum".fields.len;
|
||||
var mnemonic_map: [mnemonic_count][]Data = @splat(&.{});
|
||||
const encodings = @import("encodings.zig");
|
||||
|
||||
@@ -359,6 +359,8 @@ pub fn imm(lower: *const Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
|
||||
.pseudo_dbg_local_ai_s,
|
||||
=> .s(@bitCast(i)),
|
||||
|
||||
.ii,
|
||||
.ir,
|
||||
.rrri,
|
||||
.rri_u,
|
||||
.ri_u,
|
||||
@@ -548,17 +550,19 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
|
||||
}
|
||||
|
||||
fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
|
||||
@setEvalBranchQuota(2_400);
|
||||
const fixes = switch (inst.ops) {
|
||||
.none => inst.data.none.fixes,
|
||||
.inst => inst.data.inst.fixes,
|
||||
.i_s, .i_u => inst.data.i.fixes,
|
||||
.ii => inst.data.ii.fixes,
|
||||
.r => inst.data.r.fixes,
|
||||
.rr => inst.data.rr.fixes,
|
||||
.rrr => inst.data.rrr.fixes,
|
||||
.rrrr => inst.data.rrrr.fixes,
|
||||
.rrri => inst.data.rrri.fixes,
|
||||
.rri_s, .rri_u => inst.data.rri.fixes,
|
||||
.ri_s, .ri_u, .ri_64 => inst.data.ri.fixes,
|
||||
.ri_s, .ri_u, .ri_64, .ir => inst.data.ri.fixes,
|
||||
.rm, .rmi_s, .mr => inst.data.rx.fixes,
|
||||
.mrr, .rrm, .rmr => inst.data.rrx.fixes,
|
||||
.rmi, .mri => inst.data.rix.fixes,
|
||||
@@ -575,8 +579,6 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
|
||||
else
|
||||
.none,
|
||||
}, mnemonic: {
|
||||
@setEvalBranchQuota(2_000);
|
||||
|
||||
comptime var max_len = 0;
|
||||
inline for (@typeInfo(Mnemonic).@"enum".fields) |field| max_len = @max(field.name.len, max_len);
|
||||
var buf: [max_len]u8 = undefined;
|
||||
@@ -598,6 +600,14 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
|
||||
.i_s, .i_u => &.{
|
||||
.{ .imm = lower.imm(inst.ops, inst.data.i.i) },
|
||||
},
|
||||
.ii => &.{
|
||||
.{ .imm = lower.imm(inst.ops, inst.data.ii.i1) },
|
||||
.{ .imm = lower.imm(inst.ops, inst.data.ii.i2) },
|
||||
},
|
||||
.ir => &.{
|
||||
.{ .imm = lower.imm(inst.ops, inst.data.ri.i) },
|
||||
.{ .reg = inst.data.ri.r1 },
|
||||
},
|
||||
.r => &.{
|
||||
.{ .reg = inst.data.r.r1 },
|
||||
},
|
||||
|
||||
@@ -23,8 +23,82 @@ pub const Inst = struct {
|
||||
/// ___
|
||||
@"_",
|
||||
|
||||
/// ___ 0
|
||||
_0,
|
||||
/// ___ 1
|
||||
_1,
|
||||
/// ___ 2
|
||||
_2,
|
||||
/// ___ 3
|
||||
_3,
|
||||
/// ___ 4
|
||||
_4,
|
||||
|
||||
/// System Call ___
|
||||
sys_,
|
||||
|
||||
/// ___ crement Shadow Stack Pointer Doubleword
|
||||
_csspd,
|
||||
/// ___ crement Shadow Stack Pointer Quadword
|
||||
_csspq,
|
||||
/// ___ FS Segment Base
|
||||
_fsbase,
|
||||
/// ___ GS Segment Base
|
||||
_gsbase,
|
||||
/// ___ Model Specific Register
|
||||
_msr,
|
||||
/// ___ MXCSR
|
||||
_mxcsr,
|
||||
/// ___ Processor ID
|
||||
_pid,
|
||||
/// ___ Protection Key Rights For User Pages
|
||||
_pkru,
|
||||
/// ___ Performance-Monitoring Counters
|
||||
_pmc,
|
||||
/// ___ Rondam Number
|
||||
_rand,
|
||||
/// ___ Rondam Seed
|
||||
_seed,
|
||||
/// ___ Shadow Stack Pointer Doubleword
|
||||
_sspd,
|
||||
/// ___ Shadow Stack Pointer Quadword
|
||||
_sspq,
|
||||
/// ___ Time-Stamp Counter
|
||||
_tsc,
|
||||
/// ___ Time-Stamp Counter And Processor ID
|
||||
_tscp,
|
||||
/// VEX-Encoded ___ MXCSR
|
||||
v_mxcsr,
|
||||
|
||||
/// Interrupt ___
|
||||
/// Integer ___
|
||||
i_,
|
||||
/// Interrupt ___ Word
|
||||
i_w,
|
||||
/// Interrupt ___ Doubleword
|
||||
i_d,
|
||||
/// Interrupt ___ Quadword
|
||||
i_q,
|
||||
/// User-Interrupt ___
|
||||
ui_,
|
||||
|
||||
/// ___ mp
|
||||
_mp,
|
||||
/// ___ if CX register is 0
|
||||
_cxz,
|
||||
/// ___ if ECX register is 0
|
||||
_ecxz,
|
||||
/// ___ if RCX register is 0
|
||||
_rcxz,
|
||||
|
||||
/// ___ Addition
|
||||
_a,
|
||||
/// ___ Subtraction
|
||||
_s,
|
||||
/// ___ Multiply
|
||||
_m,
|
||||
/// ___ Division
|
||||
_d,
|
||||
|
||||
/// ___ Left
|
||||
_l,
|
||||
@@ -33,6 +107,8 @@ pub const Inst = struct {
|
||||
/// ___ Left Without Affecting Flags
|
||||
_lx,
|
||||
/// ___ Right
|
||||
/// ___ For Reading
|
||||
/// ___ Register
|
||||
_r,
|
||||
/// ___ Right Double
|
||||
_rd,
|
||||
@@ -45,7 +121,7 @@ pub const Inst = struct {
|
||||
//_r,
|
||||
|
||||
/// ___ Above
|
||||
_a,
|
||||
//_a,
|
||||
/// ___ Above Or Equal
|
||||
_ae,
|
||||
/// ___ Below
|
||||
@@ -102,7 +178,7 @@ pub const Inst = struct {
|
||||
/// ___ Parity Odd
|
||||
_po,
|
||||
/// ___ Sign
|
||||
_s,
|
||||
//_s,
|
||||
/// ___ Zero
|
||||
_z,
|
||||
/// ___ Alignment Check Flag
|
||||
@@ -111,15 +187,18 @@ pub const Inst = struct {
|
||||
//_d,
|
||||
/// ___ Interrupt Flag
|
||||
_i,
|
||||
/// ___ Task-Switched Flag In CR0
|
||||
_ts,
|
||||
/// ___ User Interrupt Flag
|
||||
_ui,
|
||||
|
||||
/// ___ Byte
|
||||
//_b,
|
||||
/// ___ Word
|
||||
/// ___ For Writing
|
||||
_w,
|
||||
/// ___ Doubleword
|
||||
_d,
|
||||
//_d,
|
||||
/// ___ QuadWord
|
||||
_q,
|
||||
|
||||
@@ -214,8 +293,72 @@ pub const Inst = struct {
|
||||
|
||||
/// Float ___
|
||||
f_,
|
||||
/// Float ___ +1.0
|
||||
/// Float ___ 1
|
||||
f_1,
|
||||
/// Float ___ Below
|
||||
f_b,
|
||||
/// Float ___ Below Or Equal
|
||||
f_be,
|
||||
/// Float ___ Control Word
|
||||
f_cw,
|
||||
/// Float ___ Equal
|
||||
f_e,
|
||||
/// Float ___ Environment
|
||||
f_env,
|
||||
/// Float ___ log_2(e)
|
||||
f_l2e,
|
||||
/// Float ___ log_2(10)
|
||||
f_l2t,
|
||||
/// Float ___ log_10(2)
|
||||
f_lg2,
|
||||
/// Float ___ log_e(2)
|
||||
f_ln2,
|
||||
/// Float ___ Not Below
|
||||
f_nb,
|
||||
/// Float ___ Not Below Or Equal
|
||||
f_nbe,
|
||||
/// Float ___ Not Equal
|
||||
f_ne,
|
||||
/// Float ___ Not Unordered
|
||||
f_nu,
|
||||
/// Float ___ Pop
|
||||
f_p,
|
||||
/// Float ___ +1
|
||||
f_p1,
|
||||
/// Float ___ π
|
||||
f_pi,
|
||||
/// Float ___ Pop Pop
|
||||
f_pp,
|
||||
/// Float ___ stack-top pointer
|
||||
f_stp,
|
||||
/// Float ___ Status Word
|
||||
f_sw,
|
||||
/// Float ___ Unordered
|
||||
f_u,
|
||||
/// Float ___ +0.0
|
||||
f_z,
|
||||
/// Float BCD ___
|
||||
fb_,
|
||||
/// Float BCD ___ Pop
|
||||
fb_p,
|
||||
/// Float And Integer ___
|
||||
fi_,
|
||||
/// Float And Integer ___ Pop
|
||||
fi_p,
|
||||
/// Float No Wait ___
|
||||
fn_,
|
||||
/// Float No Wait ___ Control Word
|
||||
fn_cw,
|
||||
/// Float No Wait ___ Environment
|
||||
fn_env,
|
||||
/// Float No Wait ___ status word
|
||||
fn_sw,
|
||||
|
||||
/// ___ in 32-bit and Compatibility Mode
|
||||
_32,
|
||||
/// ___ in 64-bit Mode
|
||||
_64,
|
||||
|
||||
/// Packed ___
|
||||
p_,
|
||||
@@ -243,6 +386,24 @@ pub const Inst = struct {
|
||||
/// ___ Packed Double-Precision Values
|
||||
_pd,
|
||||
|
||||
/// ___ Internal Caches
|
||||
//_d,
|
||||
/// ___ TLB Entries
|
||||
_lpg,
|
||||
/// ___ Process-Context Identifier
|
||||
_pcid,
|
||||
|
||||
/// Load ___
|
||||
l_,
|
||||
/// Memory ___
|
||||
m_,
|
||||
/// Store ___
|
||||
s_,
|
||||
/// Timed ___
|
||||
t_,
|
||||
/// User Level Monitor ___
|
||||
um_,
|
||||
|
||||
/// VEX-Encoded ___
|
||||
v_,
|
||||
/// VEX-Encoded ___ Byte
|
||||
@@ -282,6 +443,19 @@ pub const Inst = struct {
|
||||
/// VEX-Encoded ___ 128-Bits Of Floating-Point Data
|
||||
v_f128,
|
||||
|
||||
/// ___ 128-bit key with key locker
|
||||
_128,
|
||||
/// ___ 256-bit key with key locker
|
||||
_256,
|
||||
/// ___ with key locker using 128-bit key
|
||||
_128kl,
|
||||
/// ___ with key locker using 256-bit key
|
||||
_256kl,
|
||||
/// ___ with key locker on 8 blocks using 128-bit key
|
||||
_wide128kl,
|
||||
/// ___ with key locker on 8 blocks using 256-bit key
|
||||
_wide256kl,
|
||||
|
||||
/// Mask ___ Byte
|
||||
k_b,
|
||||
/// Mask ___ Word
|
||||
@@ -300,6 +474,12 @@ pub const Inst = struct {
|
||||
};
|
||||
|
||||
pub const Tag = enum(u8) {
|
||||
// General-purpose
|
||||
/// ASCII adjust al after addition
|
||||
/// ASCII adjust ax before division
|
||||
/// ASCII adjust ax after multiply
|
||||
/// ASCII adjust al after subtraction
|
||||
aa,
|
||||
/// Add with carry
|
||||
adc,
|
||||
/// Add
|
||||
@@ -313,6 +493,8 @@ pub const Inst = struct {
|
||||
/// Bitwise logical and of packed single-precision floating-point values
|
||||
/// Bitwise logical and of packed double-precision floating-point values
|
||||
@"and",
|
||||
/// Adjust RPL field of segment selector
|
||||
arpl,
|
||||
/// Bit scan forward
|
||||
/// Bit scan reverse
|
||||
bs,
|
||||
@@ -324,6 +506,7 @@ pub const Inst = struct {
|
||||
/// Bit test and set
|
||||
bt,
|
||||
/// Call
|
||||
/// Fast system call
|
||||
call,
|
||||
/// Convert byte to word
|
||||
cbw,
|
||||
@@ -331,12 +514,25 @@ pub const Inst = struct {
|
||||
cdq,
|
||||
/// Convert doubleword to quadword
|
||||
cdqe,
|
||||
/// Clear AC flag in EFLAGS register
|
||||
/// Clear carry flag
|
||||
/// Clear direction flag
|
||||
/// Clear interrupt flag
|
||||
/// Clear task-switched flag in CR0
|
||||
/// Clear user interrupt flag
|
||||
cl,
|
||||
/// Cache line demote
|
||||
cldemote,
|
||||
/// Flush cache line
|
||||
clflush,
|
||||
/// Flush cache line optimized
|
||||
clflushopt,
|
||||
/// Clear busy flag in a supervisor shadow stack token
|
||||
clrssbsy,
|
||||
/// Cache line write back
|
||||
clwb,
|
||||
/// Complement carry flag
|
||||
cmc,
|
||||
/// Conditional move
|
||||
cmov,
|
||||
/// Logical compare
|
||||
@@ -355,33 +551,79 @@ pub const Inst = struct {
|
||||
cwd,
|
||||
/// Convert word to doubleword
|
||||
cwde,
|
||||
/// Decimal adjust AL after addition
|
||||
/// Decimal adjust AL after subtraction
|
||||
da,
|
||||
/// Decrement by 1
|
||||
dec,
|
||||
/// Decrement shadow stack pointer
|
||||
de,
|
||||
/// Unsigned division
|
||||
/// Signed division
|
||||
/// Divide
|
||||
/// Divide packed single-precision floating-point values
|
||||
/// Divide scalar single-precision floating-point values
|
||||
/// Divide packed double-precision floating-point values
|
||||
/// Divide scalar double-precision floating-point values
|
||||
div,
|
||||
/// Terminate and indirect branch in 32-bit and compatibility mode
|
||||
/// Terminate and indirect branch in 64-bit mode
|
||||
endbr,
|
||||
/// Enqueue command
|
||||
/// Enqueue command supervisor
|
||||
enqcmd,
|
||||
/// Make stack frame for procedure parameters
|
||||
/// Fast system call
|
||||
enter,
|
||||
/// Fast return from fast system call
|
||||
exit,
|
||||
/// Load fence
|
||||
/// Memory fence
|
||||
/// Store fence
|
||||
fence,
|
||||
/// Halt
|
||||
hlt,
|
||||
/// History reset
|
||||
hreset,
|
||||
/// Input from port
|
||||
/// Input from port to string
|
||||
/// Increment by 1
|
||||
inc,
|
||||
/// Increment shadow stack pointer
|
||||
in,
|
||||
/// Call to interrupt procedure
|
||||
int3,
|
||||
int,
|
||||
/// Invalidate internal caches
|
||||
/// Invalidate TLB entries
|
||||
/// Invalidate process-context identifier
|
||||
inv,
|
||||
/// Conditional jump
|
||||
j,
|
||||
/// Jump
|
||||
jmp,
|
||||
j,
|
||||
/// Load status flags into AH register
|
||||
lahf,
|
||||
/// Load access right byte
|
||||
lar,
|
||||
/// Load effective address
|
||||
lea,
|
||||
/// High level procedure exit
|
||||
leave,
|
||||
/// Load global descriptor table register
|
||||
lgdt,
|
||||
/// Load interrupt descriptor table register
|
||||
lidt,
|
||||
/// Load local descriptor table register
|
||||
lldt,
|
||||
/// Load machine status word
|
||||
lmsw,
|
||||
/// Load string
|
||||
lod,
|
||||
/// Load fence
|
||||
lfence,
|
||||
/// Loop according to ECX counter
|
||||
loop,
|
||||
/// Load segment limit
|
||||
lsl,
|
||||
/// Load task register
|
||||
ltr,
|
||||
/// Count the number of leading zero bits
|
||||
lzcnt,
|
||||
/// Memory fence
|
||||
mfence,
|
||||
/// Move
|
||||
/// Move data from string to string
|
||||
/// Move scalar single-precision floating-point value
|
||||
@@ -407,6 +649,7 @@ pub const Inst = struct {
|
||||
/// Two's complement negation
|
||||
neg,
|
||||
/// No-op
|
||||
/// No operation
|
||||
nop,
|
||||
/// One's complement negation
|
||||
not,
|
||||
@@ -414,39 +657,62 @@ pub const Inst = struct {
|
||||
/// Bitwise logical or of packed single-precision floating-point values
|
||||
/// Bitwise logical or of packed double-precision floating-point values
|
||||
@"or",
|
||||
/// Output to port
|
||||
/// Output string to port
|
||||
out,
|
||||
/// Spin loop hint
|
||||
/// Timed pause
|
||||
pause,
|
||||
/// Pop
|
||||
pop,
|
||||
/// Return the count of number of bits set to 1
|
||||
popcnt,
|
||||
/// Pop stack into EFLAGS register
|
||||
popfq,
|
||||
popf,
|
||||
/// Push
|
||||
push,
|
||||
/// Push EFLAGS register onto the stack
|
||||
pushfq,
|
||||
pushf,
|
||||
/// Rotate left through carry
|
||||
/// Rotate right through carry
|
||||
rc,
|
||||
/// Read FS segment base
|
||||
/// Read GS segment base
|
||||
/// Read from model specific register
|
||||
/// Read processor ID
|
||||
/// Read protection key rights for user pages
|
||||
/// Read performance-monitoring counters
|
||||
/// Read random number
|
||||
/// Read random seed
|
||||
/// Read shadow stack pointer
|
||||
/// Read time-stamp counter
|
||||
/// Read time-stamp counter and processor ID
|
||||
rd,
|
||||
/// Return
|
||||
/// Return from fast system call
|
||||
/// Interrupt return
|
||||
/// User-interrupt return
|
||||
ret,
|
||||
/// Rotate left
|
||||
/// Rotate right
|
||||
/// Rotate right logical without affecting flags
|
||||
ro,
|
||||
/// Resume from system management mode
|
||||
rsm,
|
||||
/// Arithmetic shift left
|
||||
/// Arithmetic shift right
|
||||
/// Shift left arithmetic without affecting flags
|
||||
sa,
|
||||
/// Store AH into flags
|
||||
sahf,
|
||||
/// Integer subtraction with borrow
|
||||
sbb,
|
||||
/// Scan string
|
||||
sca,
|
||||
/// Send user interprocessor interrupt
|
||||
senduipi,
|
||||
/// Set byte on condition
|
||||
set,
|
||||
/// Store fence
|
||||
sfence,
|
||||
/// Logical shift left
|
||||
/// Double precision shift left
|
||||
/// Logical shift right
|
||||
@@ -454,6 +720,12 @@ pub const Inst = struct {
|
||||
/// Shift left logical without affecting flags
|
||||
/// Shift right logical without affecting flags
|
||||
sh,
|
||||
/// Store interrupt descriptor table register
|
||||
sidt,
|
||||
/// Store local descriptor table register
|
||||
sldt,
|
||||
/// Store machine status word
|
||||
smsw,
|
||||
/// Subtract
|
||||
/// Subtract packed integers
|
||||
/// Subtract packed single-precision floating-point values
|
||||
@@ -464,46 +736,128 @@ pub const Inst = struct {
|
||||
/// Set carry flag
|
||||
/// Set direction flag
|
||||
/// Set interrupt flag
|
||||
/// Store binary coded decimal integer and pop
|
||||
/// Store floating-point value
|
||||
/// Store integer
|
||||
/// Store x87 FPU control word
|
||||
/// Store x87 FPU environment
|
||||
/// Store x87 FPU status word
|
||||
/// Store MXCSR register state
|
||||
st,
|
||||
/// Store string
|
||||
sto,
|
||||
/// Syscall
|
||||
syscall,
|
||||
/// Swap GS base register
|
||||
swapgs,
|
||||
/// Test condition
|
||||
@"test",
|
||||
/// Count the number of trailing zero bits
|
||||
tzcnt,
|
||||
/// Undefined instruction
|
||||
ud2,
|
||||
ud,
|
||||
/// User level set up monitor address
|
||||
umonitor,
|
||||
/// Verify a segment for reading
|
||||
/// Verify a segment for writing
|
||||
ver,
|
||||
/// Write to model specific register
|
||||
/// Write to model specific register
|
||||
/// Write to model specific register
|
||||
wr,
|
||||
/// Exchange and add
|
||||
xadd,
|
||||
/// Exchange register/memory with register
|
||||
xchg,
|
||||
/// Exchange register contents
|
||||
xch,
|
||||
/// Get value of extended control register
|
||||
xgetbv,
|
||||
/// Table look-up translation
|
||||
xlat,
|
||||
/// Logical exclusive-or
|
||||
/// Bitwise logical xor of packed single-precision floating-point values
|
||||
/// Bitwise logical xor of packed double-precision floating-point values
|
||||
xor,
|
||||
|
||||
// X87
|
||||
/// Compute 2^x-1
|
||||
@"2xm1",
|
||||
/// Absolute value
|
||||
abs,
|
||||
/// Change sign
|
||||
chs,
|
||||
/// Clear exceptions
|
||||
clex,
|
||||
/// Compare floating-point values
|
||||
com,
|
||||
/// Compare floating-point values and set EFLAGS
|
||||
/// Compare scalar ordered single-precision floating-point values
|
||||
/// Compare scalar ordered double-precision floating-point values
|
||||
comi,
|
||||
/// Cosine
|
||||
cos,
|
||||
/// Decrement stack-top pointer
|
||||
decstp,
|
||||
/// Reverse divide
|
||||
divr,
|
||||
/// Free floating-point register
|
||||
free,
|
||||
/// Store integer with truncation
|
||||
istt,
|
||||
/// Increment stack-top pointer
|
||||
incstp,
|
||||
/// Initialize floating-point unit
|
||||
init,
|
||||
/// Load binary coded decimal integer
|
||||
/// Load floating-point value
|
||||
ld,
|
||||
/// Load integer
|
||||
/// Load constant
|
||||
/// Load x87 FPU control word
|
||||
/// Load x87 FPU environment
|
||||
ldenv,
|
||||
/// Store x87 FPU environment
|
||||
nstenv,
|
||||
/// Store x87 FPU environment
|
||||
stenv,
|
||||
/// Load MXCSR register state
|
||||
ld,
|
||||
/// Partial arctangent
|
||||
patan,
|
||||
/// Partial remainder
|
||||
prem,
|
||||
/// Partial tangent
|
||||
ptan,
|
||||
/// Round to integer
|
||||
rndint,
|
||||
/// Restore x87 FPU state
|
||||
rstor,
|
||||
/// Store x87 FPU state
|
||||
save,
|
||||
/// Scale
|
||||
scale,
|
||||
/// Sine
|
||||
sin,
|
||||
/// Sine and cosine
|
||||
sincos,
|
||||
/// Square root
|
||||
/// Square root of packed single-precision floating-point values
|
||||
/// Square root of scalar single-precision floating-point value
|
||||
/// Square root of packed double-precision floating-point values
|
||||
/// Square root of scalar double-precision floating-point value
|
||||
sqrt,
|
||||
/// Store integer with truncation
|
||||
stt,
|
||||
/// Reverse subtract
|
||||
subr,
|
||||
/// Test
|
||||
tst,
|
||||
/// Unordered compare floating-point values
|
||||
ucom,
|
||||
/// Unordered compare floating-point values and set EFLAGS
|
||||
/// Unordered compare scalar single-precision floating-point values
|
||||
/// Unordered compare scalar double-precision floating-point values
|
||||
ucomi,
|
||||
/// Wait
|
||||
/// User level monitor wait
|
||||
wait,
|
||||
/// Examine floating-point
|
||||
xam,
|
||||
/// Extract exponent and significand
|
||||
xtract,
|
||||
/// Compute y * log2x
|
||||
/// Compute y * log2(x + 1)
|
||||
yl2x,
|
||||
|
||||
// MMX
|
||||
/// Pack with signed saturation
|
||||
ackssw,
|
||||
/// Pack with signed saturation
|
||||
@@ -514,6 +868,7 @@ pub const Inst = struct {
|
||||
adds,
|
||||
/// Add packed unsigned integers with unsigned saturation
|
||||
addus,
|
||||
/// Logical and not
|
||||
/// Bitwise logical and not of packed single-precision floating-point values
|
||||
/// Bitwise logical and not of packed double-precision floating-point values
|
||||
andn,
|
||||
@@ -521,18 +876,8 @@ pub const Inst = struct {
|
||||
cmpeq,
|
||||
/// Compare packed data for greater than
|
||||
cmpgt,
|
||||
/// Maximum of packed signed integers
|
||||
maxs,
|
||||
/// Maximum of packed unsigned integers
|
||||
maxu,
|
||||
/// Minimum of packed signed integers
|
||||
mins,
|
||||
/// Minimum of packed unsigned integers
|
||||
minu,
|
||||
/// Move byte mask
|
||||
/// Extract packed single precision floating-point sign mask
|
||||
/// Extract packed double precision floating-point sign mask
|
||||
movmsk,
|
||||
/// Empty MMX technology state
|
||||
emms,
|
||||
/// Multiply packed signed integers and store low result
|
||||
mull,
|
||||
/// Multiply packed signed integers and store high result
|
||||
@@ -547,12 +892,20 @@ pub const Inst = struct {
|
||||
subs,
|
||||
/// Subtract packed unsigned integers with unsigned saturation
|
||||
subus,
|
||||
/// Unpack high data
|
||||
unpckhbw,
|
||||
/// Unpack high data
|
||||
unpckhdq,
|
||||
/// Unpack high data
|
||||
unpckhwd,
|
||||
/// Unpack low data
|
||||
unpcklbw,
|
||||
/// Unpack low data
|
||||
unpckldq,
|
||||
/// Unpack low data
|
||||
unpcklwd,
|
||||
|
||||
/// Load MXCSR register
|
||||
ldmxcsr,
|
||||
/// Store MXCSR register state
|
||||
stmxcsr,
|
||||
|
||||
// SSE
|
||||
/// Convert packed doubleword integers to packed single-precision floating-point values
|
||||
/// Convert packed doubleword integers to packed double-precision floating-point values
|
||||
cvtpi2,
|
||||
@@ -567,17 +920,38 @@ pub const Inst = struct {
|
||||
cvttps2pi,
|
||||
/// Convert with truncation scalar single-precision floating-point value to doubleword integer
|
||||
cvttss2si,
|
||||
|
||||
/// Extract byte
|
||||
/// Extract word
|
||||
/// Extract doubleword
|
||||
/// Extract quadword
|
||||
extr,
|
||||
/// Restore x87 FPU, MMX, XMM, and MXCSR state
|
||||
fxrstor,
|
||||
/// Save x87 FPU, MMX technology, and MXCSR state
|
||||
fxsave,
|
||||
/// Insert byte
|
||||
/// Insert word
|
||||
/// Insert doubleword
|
||||
/// Insert quadword
|
||||
insr,
|
||||
/// Maximum of packed single-precision floating-point values
|
||||
/// Maximum of scalar single-precision floating-point values
|
||||
/// Maximum of packed double-precision floating-point values
|
||||
/// Maximum of scalar double-precision floating-point values
|
||||
max,
|
||||
/// Maximum of packed signed integers
|
||||
maxs,
|
||||
/// Maximum of packed unsigned integers
|
||||
maxu,
|
||||
/// Minimum of packed single-precision floating-point values
|
||||
/// Minimum of scalar single-precision floating-point values
|
||||
/// Minimum of packed double-precision floating-point values
|
||||
/// Minimum of scalar double-precision floating-point values
|
||||
min,
|
||||
/// Minimum of packed signed integers
|
||||
mins,
|
||||
/// Minimum of packed unsigned integers
|
||||
minu,
|
||||
/// Move aligned packed single-precision floating-point values
|
||||
/// Move aligned packed double-precision floating-point values
|
||||
mova,
|
||||
@@ -591,27 +965,18 @@ pub const Inst = struct {
|
||||
movl,
|
||||
/// Move packed single-precision floating-point values low to high
|
||||
movlh,
|
||||
/// Move byte mask
|
||||
/// Extract packed single precision floating-point sign mask
|
||||
/// Extract packed double precision floating-point sign mask
|
||||
movmsk,
|
||||
/// Move unaligned packed single-precision floating-point values
|
||||
/// Move unaligned packed double-precision floating-point values
|
||||
movu,
|
||||
/// Extract byte
|
||||
/// Extract word
|
||||
/// Extract doubleword
|
||||
/// Extract quadword
|
||||
extr,
|
||||
/// Insert byte
|
||||
/// Insert word
|
||||
/// Insert doubleword
|
||||
/// Insert quadword
|
||||
insr,
|
||||
/// Square root of packed single-precision floating-point values
|
||||
/// Square root of scalar single-precision floating-point value
|
||||
/// Square root of packed double-precision floating-point values
|
||||
/// Square root of scalar double-precision floating-point value
|
||||
sqrt,
|
||||
/// Unordered compare scalar single-precision floating-point values
|
||||
/// Unordered compare scalar double-precision floating-point values
|
||||
ucomi,
|
||||
/// Packed interleave shuffle of quadruplets of single-precision floating-point values
|
||||
/// Packed interleave shuffle of pairs of double-precision floating-point values
|
||||
/// Shuffle packed doublewords
|
||||
/// Shuffle packed words
|
||||
shuf,
|
||||
/// Unpack and interleave high packed single-precision floating-point values
|
||||
/// Unpack and interleave high packed double-precision floating-point values
|
||||
unpckh,
|
||||
@@ -619,6 +984,7 @@ pub const Inst = struct {
|
||||
/// Unpack and interleave low packed double-precision floating-point values
|
||||
unpckl,
|
||||
|
||||
// SSE2
|
||||
/// Convert packed doubleword integers to packed single-precision floating-point values
|
||||
/// Convert packed doubleword integers to packed double-precision floating-point values
|
||||
cvtdq2,
|
||||
@@ -646,32 +1012,28 @@ pub const Inst = struct {
|
||||
cvttps2dq,
|
||||
/// Convert with truncation scalar double-precision floating-point value to doubleword integer
|
||||
cvttsd2si,
|
||||
/// Packed interleave shuffle of quadruplets of single-precision floating-point values
|
||||
/// Packed interleave shuffle of pairs of double-precision floating-point values
|
||||
/// Shuffle packed doublewords
|
||||
/// Shuffle packed words
|
||||
shuf,
|
||||
/// Galois field affine transformation inverse
|
||||
gf2p8affineinvq,
|
||||
/// Galois field affine transformation
|
||||
gf2p8affineq,
|
||||
/// Galois field multiply bytes
|
||||
gf2p8mul,
|
||||
/// Shuffle packed high words
|
||||
shufh,
|
||||
/// Shuffle packed low words
|
||||
shufl,
|
||||
/// Unpack high data
|
||||
unpckhbw,
|
||||
/// Unpack high data
|
||||
unpckhdq,
|
||||
/// Unpack high data
|
||||
unpckhqdq,
|
||||
/// Unpack high data
|
||||
unpckhwd,
|
||||
/// Unpack low data
|
||||
unpcklbw,
|
||||
/// Unpack low data
|
||||
unpckldq,
|
||||
/// Unpack low data
|
||||
unpcklqdq,
|
||||
/// Unpack low data
|
||||
unpcklwd,
|
||||
|
||||
// SSE3
|
||||
/// Packed single-precision floating-point add/subtract
|
||||
/// Packed double-precision floating-point add/subtract
|
||||
addsub,
|
||||
/// Packed single-precision floating-point horizontal add
|
||||
/// Packed double-precision floating-point horizontal add
|
||||
hadd,
|
||||
/// Replicate double floating-point values
|
||||
movddup,
|
||||
/// Replicate single floating-point values
|
||||
@@ -679,9 +1041,11 @@ pub const Inst = struct {
|
||||
/// Replicate single floating-point values
|
||||
movsldup,
|
||||
|
||||
// SSSE3
|
||||
/// Packed align right
|
||||
alignr,
|
||||
|
||||
// SSE4.1
|
||||
/// Pack with unsigned saturation
|
||||
ackusd,
|
||||
/// Blend packed single-precision floating-point values
|
||||
@@ -694,6 +1058,9 @@ pub const Inst = struct {
|
||||
/// Variable blend packed double-precision floating-point values
|
||||
/// Variable blend scalar double-precision floating-point values
|
||||
blendv,
|
||||
/// Dot product of packed single-precision floating-point values
|
||||
/// Dot product of packed double-precision floating-point values
|
||||
dp,
|
||||
/// Extract packed floating-point values
|
||||
/// Extract packed integer values
|
||||
extract,
|
||||
@@ -714,14 +1081,28 @@ pub const Inst = struct {
|
||||
/// Round scalar double-precision floating-point value
|
||||
round,
|
||||
|
||||
// SSE4.2
|
||||
/// Accumulate CRC32 value
|
||||
crc32,
|
||||
|
||||
// PCLMUL
|
||||
/// Carry-less multiplication quadword
|
||||
clmulq,
|
||||
|
||||
// AES
|
||||
/// Perform one round of an AES decryption flow
|
||||
/// Perform ten rounds of AES decryption flow with key locker using 128-bit key
|
||||
/// Perform ten rounds of AES decryption flow with key locker using 256-bit key
|
||||
/// Perform ten rounds of AES decryption flow with key locker on 8 blocks using 128-bit key
|
||||
/// Perform ten rounds of AES decryption flow with key locker on 8 blocks using 256-bit key
|
||||
aesdec,
|
||||
/// Perform last round of an AES decryption flow
|
||||
aesdeclast,
|
||||
/// Perform one round of an AES encryption flow
|
||||
/// Perform ten rounds of AES encryption flow with key locker using 128-bit key
|
||||
/// Perform ten rounds of AES encryption flow with key locker using 256-bit key
|
||||
/// Perform ten rounds of AES encryption flow with key locker on 8 blocks using 128-bit key
|
||||
/// Perform ten rounds of AES encryption flow with key locker on 8 blocks using 256-bit key
|
||||
aesenc,
|
||||
/// Perform last round of an AES encryption flow
|
||||
aesenclast,
|
||||
@@ -730,22 +1111,42 @@ pub const Inst = struct {
|
||||
/// AES round key generation assist
|
||||
aeskeygenassist,
|
||||
|
||||
// SHA
|
||||
/// Perform four rounds of SHA1 operation
|
||||
sha1rnds,
|
||||
/// Calculate SHA1 state variable E after four rounds
|
||||
sha1nexte,
|
||||
/// Perform an intermediate calculation for the next four SHA1 message dwords
|
||||
/// Perform a final calculation for the next four SHA1 message dwords
|
||||
sha1msg,
|
||||
/// Perform an intermediate calculation for the next four SHA256 message dwords
|
||||
sha256msg1,
|
||||
/// Perform a final calculation for the next four SHA256 message dwords
|
||||
sha256msg2,
|
||||
sha256msg,
|
||||
/// Perform two rounds of SHA256 operation
|
||||
sha256rnds2,
|
||||
sha256rnds,
|
||||
|
||||
// AVX
|
||||
/// Bit field extract
|
||||
bextr,
|
||||
/// Extract lowest set isolated bit
|
||||
/// Get mask up to lowest set bit
|
||||
/// Reset lowest set bit
|
||||
bls,
|
||||
/// Load with broadcast floating-point data
|
||||
/// Load integer and broadcast
|
||||
broadcast,
|
||||
/// Zero high bits starting with specified bit position
|
||||
bzhi,
|
||||
/// Count the number of trailing zero bits
|
||||
tzcnt,
|
||||
|
||||
// F16C
|
||||
/// Convert 16-bit floating-point values to single-precision floating-point values
|
||||
cvtph2,
|
||||
/// Convert single-precision floating-point values to 16-bit floating-point values
|
||||
cvtps2ph,
|
||||
|
||||
// FMA
|
||||
/// Fused multiply-add of packed single-precision floating-point values
|
||||
/// Fused multiply-add of scalar single-precision floating-point values
|
||||
/// Fused multiply-add of packed double-precision floating-point values
|
||||
@@ -762,6 +1163,19 @@ pub const Inst = struct {
|
||||
/// Fused multiply-add of scalar double-precision floating-point values
|
||||
fmadd231,
|
||||
|
||||
// ADX
|
||||
/// Unsigned integer addition of two operands with carry flag
|
||||
adcx,
|
||||
/// Unsigned integer addition of two operands with overflow flag
|
||||
adox,
|
||||
|
||||
// AESKLE
|
||||
/// Encode 128-bit key with key locker
|
||||
/// Encode 256-bit key with key locker
|
||||
encodekey,
|
||||
/// Load internal wrapping key with key locker
|
||||
loadiwkey,
|
||||
|
||||
/// A pseudo instruction that requires special lowering.
|
||||
/// This should be the only tag in this enum that doesn't
|
||||
/// directly correspond to one or more instruction mnemonics.
|
||||
@@ -804,11 +1218,17 @@ pub const Inst = struct {
|
||||
/// Uses `ri` payload with `i` index of extra data of type `Imm64`.
|
||||
ri_64,
|
||||
/// Immediate (sign-extended) operand.
|
||||
/// Uses `imm` payload.
|
||||
/// Uses `i` payload.
|
||||
i_s,
|
||||
/// Immediate (unsigned) operand.
|
||||
/// Uses `imm` payload.
|
||||
/// Uses `i` payload.
|
||||
i_u,
|
||||
/// Immediate (word), immediate (byte) operands.
|
||||
/// Uses `ii` payload.
|
||||
ii,
|
||||
/// Immediate (byte), register operands.
|
||||
/// Uses `ri` payload.
|
||||
ir,
|
||||
/// Relative displacement operand.
|
||||
/// Uses `reloc` payload.
|
||||
rel,
|
||||
@@ -1036,6 +1456,11 @@ pub const Inst = struct {
|
||||
fixes: Fixes = ._,
|
||||
i: u32,
|
||||
},
|
||||
ii: struct {
|
||||
fixes: Fixes = ._,
|
||||
i1: u16,
|
||||
i2: u8,
|
||||
},
|
||||
r: struct {
|
||||
fixes: Fixes = ._,
|
||||
r1: Register,
|
||||
@@ -1244,7 +1669,7 @@ pub const Memory = struct {
|
||||
size: bits.Memory.Size,
|
||||
index: Register,
|
||||
scale: bits.Memory.Scale,
|
||||
_: u15 = undefined,
|
||||
_: u14 = undefined,
|
||||
};
|
||||
|
||||
pub fn encode(mem: bits.Memory) Memory {
|
||||
|
||||
@@ -177,7 +177,7 @@ pub const Condition = enum(u5) {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Register = enum(u7) {
|
||||
pub const Register = enum(u8) {
|
||||
// zig fmt: off
|
||||
rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi,
|
||||
r8, r9, r10, r11, r12, r13, r14, r15,
|
||||
@@ -207,6 +207,12 @@ pub const Register = enum(u7) {
|
||||
|
||||
rip, eip, ip,
|
||||
|
||||
cr0, cr1, cr2, cr3, cr4, cr5, cr6, cr7,
|
||||
cr8, cr9, cr10, cr11, cr12, cr13, cr14, cr15,
|
||||
|
||||
dr0, dr1, dr2, dr3, dr4, dr5, dr6, dr7,
|
||||
dr8, dr9, dr10, dr11, dr12, dr13, dr14, dr15,
|
||||
|
||||
none,
|
||||
// zig fmt: on
|
||||
|
||||
@@ -217,6 +223,8 @@ pub const Register = enum(u7) {
|
||||
mmx,
|
||||
sse,
|
||||
ip,
|
||||
cr,
|
||||
dr,
|
||||
};
|
||||
|
||||
pub fn class(reg: Register) Class {
|
||||
@@ -235,13 +243,15 @@ pub const Register = enum(u7) {
|
||||
|
||||
@intFromEnum(Register.es) ... @intFromEnum(Register.gs) => .segment,
|
||||
@intFromEnum(Register.rip) ... @intFromEnum(Register.ip) => .ip,
|
||||
@intFromEnum(Register.cr0) ... @intFromEnum(Register.cr15) => .cr,
|
||||
@intFromEnum(Register.dr0) ... @intFromEnum(Register.dr15) => .dr,
|
||||
|
||||
else => unreachable,
|
||||
// zig fmt: on
|
||||
};
|
||||
}
|
||||
|
||||
pub fn id(reg: Register) u6 {
|
||||
pub fn id(reg: Register) u7 {
|
||||
const base = switch (@intFromEnum(reg)) {
|
||||
// zig fmt: off
|
||||
@intFromEnum(Register.rax) ... @intFromEnum(Register.r15) => @intFromEnum(Register.rax),
|
||||
@@ -254,8 +264,9 @@ pub const Register = enum(u7) {
|
||||
@intFromEnum(Register.xmm0) ... @intFromEnum(Register.xmm15) => @intFromEnum(Register.xmm0) - 16,
|
||||
@intFromEnum(Register.mm0) ... @intFromEnum(Register.mm7) => @intFromEnum(Register.mm0) - 32,
|
||||
@intFromEnum(Register.st0) ... @intFromEnum(Register.st7) => @intFromEnum(Register.st0) - 40,
|
||||
|
||||
@intFromEnum(Register.es) ... @intFromEnum(Register.gs) => @intFromEnum(Register.es) - 48,
|
||||
@intFromEnum(Register.cr0) ... @intFromEnum(Register.cr15) => @intFromEnum(Register.cr0) - 54,
|
||||
@intFromEnum(Register.dr0) ... @intFromEnum(Register.dr15) => @intFromEnum(Register.dr0) - 70,
|
||||
|
||||
else => unreachable,
|
||||
// zig fmt: on
|
||||
@@ -279,6 +290,9 @@ pub const Register = enum(u7) {
|
||||
|
||||
@intFromEnum(Register.es) ... @intFromEnum(Register.gs) => 16,
|
||||
|
||||
@intFromEnum(Register.cr0) ... @intFromEnum(Register.cr15) => 64,
|
||||
@intFromEnum(Register.dr0) ... @intFromEnum(Register.dr15) => 64,
|
||||
|
||||
else => unreachable,
|
||||
// zig fmt: on
|
||||
};
|
||||
@@ -295,6 +309,9 @@ pub const Register = enum(u7) {
|
||||
@intFromEnum(Register.ymm8) ... @intFromEnum(Register.ymm15) => true,
|
||||
@intFromEnum(Register.xmm8) ... @intFromEnum(Register.xmm15) => true,
|
||||
|
||||
@intFromEnum(Register.cr8) ... @intFromEnum(Register.cr15) => true,
|
||||
@intFromEnum(Register.dr8) ... @intFromEnum(Register.dr15) => true,
|
||||
|
||||
else => false,
|
||||
// zig fmt: on
|
||||
};
|
||||
@@ -316,6 +333,9 @@ pub const Register = enum(u7) {
|
||||
|
||||
@intFromEnum(Register.es) ... @intFromEnum(Register.gs) => @intFromEnum(Register.es),
|
||||
|
||||
@intFromEnum(Register.cr0) ... @intFromEnum(Register.cr15) => @intFromEnum(Register.cr0),
|
||||
@intFromEnum(Register.dr0) ... @intFromEnum(Register.dr15) => @intFromEnum(Register.dr0),
|
||||
|
||||
else => unreachable,
|
||||
// zig fmt: on
|
||||
};
|
||||
@@ -397,6 +417,7 @@ pub const Register = enum(u7) {
|
||||
.mmx => 41 + @as(u6, reg.enc()),
|
||||
.segment => 50 + @as(u6, reg.enc()),
|
||||
.ip => 16,
|
||||
.cr, .dr => unreachable,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -389,6 +389,7 @@ pub const Instruction = struct {
|
||||
const enc = inst.encoding;
|
||||
const data = enc.data;
|
||||
|
||||
try inst.encodeWait(encoder);
|
||||
if (data.mode.isVex()) {
|
||||
try inst.encodeVexPrefix(encoder);
|
||||
const opc = inst.encoding.opcode();
|
||||
@@ -404,19 +405,24 @@ pub const Instruction = struct {
|
||||
.z, .o, .zo, .oz => {},
|
||||
.i, .d => try encodeImm(inst.ops[0].imm, data.ops[0], encoder),
|
||||
.zi, .oi => try encodeImm(inst.ops[1].imm, data.ops[1], encoder),
|
||||
.ii => {
|
||||
try encodeImm(inst.ops[0].imm, data.ops[0], encoder);
|
||||
try encodeImm(inst.ops[1].imm, data.ops[1], encoder);
|
||||
},
|
||||
.fd => try encoder.imm64(inst.ops[1].mem.moffs.offset),
|
||||
.td => try encoder.imm64(inst.ops[0].mem.moffs.offset),
|
||||
else => {
|
||||
const mem_op = switch (data.op_en) {
|
||||
const mem_op: Operand = switch (data.op_en) {
|
||||
.ia => .{ .reg = .eax },
|
||||
.m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
|
||||
.rm, .rmi, .rm0, .vmi, .rmv => inst.ops[1],
|
||||
.rm, .rmi, .rm0, .vm, .vmi, .rmv => inst.ops[1],
|
||||
.rvm, .rvmr, .rvmi => inst.ops[2],
|
||||
else => unreachable,
|
||||
};
|
||||
switch (mem_op) {
|
||||
.reg => |reg| {
|
||||
const rm = switch (data.op_en) {
|
||||
.m, .mi, .m1, .mc, .vmi => enc.modRmExt(),
|
||||
.ia, .m, .mi, .m1, .mc, .vm, .vmi => enc.modRmExt(),
|
||||
.mr, .mri, .mrc => inst.ops[1].reg.lowEnc(),
|
||||
.rm, .rmi, .rm0, .rvm, .rvmr, .rvmi, .rmv => inst.ops[0].reg.lowEnc(),
|
||||
.mvr => inst.ops[2].reg.lowEnc(),
|
||||
@@ -426,7 +432,7 @@ pub const Instruction = struct {
|
||||
},
|
||||
.mem => |mem| {
|
||||
const op = switch (data.op_en) {
|
||||
.m, .mi, .m1, .mc, .vmi => .none,
|
||||
.m, .mi, .m1, .mc, .vm, .vmi => .none,
|
||||
.mr, .mri, .mrc => inst.ops[1],
|
||||
.rm, .rmi, .rm0, .rvm, .rvmr, .rvmi, .rmv => inst.ops[0],
|
||||
.mvr => inst.ops[2],
|
||||
@@ -438,6 +444,7 @@ pub const Instruction = struct {
|
||||
}
|
||||
|
||||
switch (data.op_en) {
|
||||
.ia => try encodeImm(inst.ops[0].imm, data.ops[0], encoder),
|
||||
.mi => try encodeImm(inst.ops[1].imm, data.ops[1], encoder),
|
||||
.rmi, .mri, .vmi => try encodeImm(inst.ops[2].imm, data.ops[2], encoder),
|
||||
.rvmr => try encoder.imm8(@as(u8, inst.ops[3].reg.enc()) << 4),
|
||||
@@ -460,6 +467,13 @@ pub const Instruction = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn encodeWait(inst: Instruction, encoder: anytype) !void {
|
||||
switch (inst.encoding.data.mode) {
|
||||
.wait => try encoder.opcode_1byte(0x9b),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn encodeLegacyPrefixes(inst: Instruction, encoder: anytype) !void {
|
||||
const enc = inst.encoding;
|
||||
const data = enc.data;
|
||||
@@ -481,7 +495,7 @@ pub const Instruction = struct {
|
||||
}
|
||||
|
||||
const segment_override: ?Register = switch (op_en) {
|
||||
.z, .i, .zi, .o, .zo, .oz, .oi, .d => null,
|
||||
.z, .i, .zi, .ii, .ia, .o, .zo, .oz, .oi, .d => null,
|
||||
.fd => inst.ops[1].mem.base().reg,
|
||||
.td => inst.ops[0].mem.base().reg,
|
||||
.rm, .rmi, .rm0 => if (inst.ops[1].isSegmentRegister())
|
||||
@@ -500,7 +514,7 @@ pub const Instruction = struct {
|
||||
}
|
||||
else
|
||||
null,
|
||||
.vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => unreachable,
|
||||
.vm, .vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => unreachable,
|
||||
};
|
||||
if (segment_override) |seg| {
|
||||
legacy.setSegmentOverride(seg);
|
||||
@@ -517,7 +531,7 @@ pub const Instruction = struct {
|
||||
rex.w = inst.encoding.data.mode == .long;
|
||||
|
||||
switch (op_en) {
|
||||
.z, .i, .zi, .fd, .td, .d => {},
|
||||
.z, .i, .zi, .ii, .ia, .fd, .td, .d => {},
|
||||
.o, .oz, .oi => rex.b = inst.ops[0].reg.isExtended(),
|
||||
.zo => rex.b = inst.ops[1].reg.isExtended(),
|
||||
.m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0, .rmv => {
|
||||
@@ -536,7 +550,7 @@ pub const Instruction = struct {
|
||||
rex.b = b_x_op.isBaseExtended();
|
||||
rex.x = b_x_op.isIndexExtended();
|
||||
},
|
||||
.vmi, .rvm, .rvmr, .rvmi, .mvr => unreachable,
|
||||
.vm, .vmi, .rvm, .rvmr, .rvmi, .mvr => unreachable,
|
||||
}
|
||||
|
||||
try encoder.rex(rex);
|
||||
@@ -552,21 +566,19 @@ pub const Instruction = struct {
|
||||
vex.w = inst.encoding.data.mode.isLong();
|
||||
|
||||
switch (op_en) {
|
||||
.z, .i, .zi, .fd, .td, .d => {},
|
||||
.o, .oz, .oi => vex.b = inst.ops[0].reg.isExtended(),
|
||||
.zo => vex.b = inst.ops[1].reg.isExtended(),
|
||||
.m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => {
|
||||
.z, .i, .zi, .ii, .ia, .fd, .td, .d, .o, .oz, .oi, .zo => unreachable,
|
||||
.m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0, .vm, .vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => {
|
||||
const r_op = switch (op_en) {
|
||||
.rm, .rmi, .rm0, .rvm, .rvmr, .rvmi, .rmv => inst.ops[0],
|
||||
.mr, .mri, .mrc => inst.ops[1],
|
||||
.mvr => inst.ops[2],
|
||||
.m, .mi, .m1, .mc, .vmi => .none,
|
||||
.m, .mi, .m1, .mc, .vm, .vmi => .none,
|
||||
else => unreachable,
|
||||
};
|
||||
vex.r = r_op.isBaseExtended();
|
||||
|
||||
const b_x_op = switch (op_en) {
|
||||
.rm, .rmi, .rm0, .vmi, .rmv => inst.ops[1],
|
||||
.rm, .rmi, .rm0, .vm, .vmi, .rmv => inst.ops[1],
|
||||
.m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
|
||||
.rvm, .rvmr, .rvmi => inst.ops[2],
|
||||
else => unreachable,
|
||||
@@ -595,7 +607,7 @@ pub const Instruction = struct {
|
||||
|
||||
switch (op_en) {
|
||||
else => {},
|
||||
.vmi => vex.v = inst.ops[0].reg,
|
||||
.vm, .vmi => vex.v = inst.ops[0].reg,
|
||||
.rvm, .rvmr, .rvmi => vex.v = inst.ops[1].reg,
|
||||
.rmv => vex.v = inst.ops[2].reg,
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user