Move Intel recipe_* bodies into intel/recipes.py.
Use a PUT_OP macro in the TailRecipe Python class to replace the code snippet that emits the prefixes + opcode part of the instruction encoding. Prepare for the addition of REX prefixes by giving the PUT_OP functions a third argument representing the REX prefix. For the non-REX encodings, verify that no REX bits wold be needed.
This commit is contained in:
@@ -43,7 +43,9 @@ OPCODE_PREFIX = {
|
|||||||
(0xf2, 0x0f, 0x3a): ('Mp3', 0b1111)
|
(0xf2, 0x0f, 0x3a): ('Mp3', 0b1111)
|
||||||
}
|
}
|
||||||
|
|
||||||
# VEX/XOP and EVEX prefixes are not yet supported.
|
# The table above does not include the REX prefix which goes after the
|
||||||
|
# mandatory prefix. VEX/XOP and EVEX prefixes are not yet supported. Encodings
|
||||||
|
# using any of these prefixes are represented by separate recipes.
|
||||||
#
|
#
|
||||||
# The encoding bits are:
|
# The encoding bits are:
|
||||||
#
|
#
|
||||||
@@ -79,6 +81,18 @@ def decode_ops(ops, rrr=0, w=0):
|
|||||||
return (name, op | (mmpp << 8) | (rrr << 12) | (w << 15))
|
return (name, op | (mmpp << 8) | (rrr << 12) | (w << 15))
|
||||||
|
|
||||||
|
|
||||||
|
def replace_put_op(emit, prefix):
|
||||||
|
# type: (str, str) -> str
|
||||||
|
"""
|
||||||
|
Given a snippet of Rust code (or None), replace the `PUT_OP` macro with the
|
||||||
|
corresponding `put_*` function from the `binemit.rs` module.
|
||||||
|
"""
|
||||||
|
if emit is None:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return emit.replace('PUT_OP', 'put_' + prefix.lower())
|
||||||
|
|
||||||
|
|
||||||
class TailRecipe:
|
class TailRecipe:
|
||||||
"""
|
"""
|
||||||
Generate encoding recipes on demand.
|
Generate encoding recipes on demand.
|
||||||
@@ -92,6 +106,10 @@ class TailRecipe:
|
|||||||
|
|
||||||
The arguments are the same as for an `EncRecipe`, except for `size` which
|
The arguments are the same as for an `EncRecipe`, except for `size` which
|
||||||
does not include the size of the opcode.
|
does not include the size of the opcode.
|
||||||
|
|
||||||
|
The `emit` parameter contains Rust code to actually emit an encoding, like
|
||||||
|
`EncRecipe` does it. Additionally, the text `PUT_OP` is substituted with
|
||||||
|
the proper `put_*` function from the `intel/binemit.rs` module.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -103,7 +121,8 @@ class TailRecipe:
|
|||||||
outs, # type: ConstraintSeq
|
outs, # type: ConstraintSeq
|
||||||
branch_range=None, # type: BranchRange
|
branch_range=None, # type: BranchRange
|
||||||
instp=None, # type: PredNode
|
instp=None, # type: PredNode
|
||||||
isap=None # type: PredNode
|
isap=None, # type: PredNode
|
||||||
|
emit=None # type: str
|
||||||
):
|
):
|
||||||
# type: (...) -> None
|
# type: (...) -> None
|
||||||
self.name = name
|
self.name = name
|
||||||
@@ -114,6 +133,7 @@ class TailRecipe:
|
|||||||
self.branch_range = branch_range
|
self.branch_range = branch_range
|
||||||
self.instp = instp
|
self.instp = instp
|
||||||
self.isap = isap
|
self.isap = isap
|
||||||
|
self.emit = emit
|
||||||
|
|
||||||
# Cached recipes, keyed by name prefix.
|
# Cached recipes, keyed by name prefix.
|
||||||
self.recipes = dict() # type: Dict[str, EncRecipe]
|
self.recipes = dict() # type: Dict[str, EncRecipe]
|
||||||
@@ -136,34 +156,69 @@ class TailRecipe:
|
|||||||
outs=self.outs,
|
outs=self.outs,
|
||||||
branch_range=self.branch_range,
|
branch_range=self.branch_range,
|
||||||
instp=self.instp,
|
instp=self.instp,
|
||||||
isap=self.isap)
|
isap=self.isap,
|
||||||
|
emit=replace_put_op(self.emit, name))
|
||||||
return (self.recipes[name], bits)
|
return (self.recipes[name], bits)
|
||||||
|
|
||||||
|
|
||||||
# XX /r
|
# XX /r
|
||||||
rr = TailRecipe('rr', Binary, size=1, ins=(GPR, GPR), outs=0)
|
rr = TailRecipe(
|
||||||
|
'rr', Binary, size=1, ins=(GPR, GPR), outs=0,
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||||
|
modrm_rr(in_reg0, in_reg1, sink);
|
||||||
|
''')
|
||||||
|
|
||||||
# XX /r, but for a unary operator with separate input/output register, like
|
# XX /r, but for a unary operator with separate input/output register, like
|
||||||
# copies.
|
# copies.
|
||||||
ur = TailRecipe('ur', Unary, size=1, ins=GPR, outs=GPR)
|
ur = TailRecipe(
|
||||||
|
'ur', Unary, size=1, ins=GPR, outs=GPR,
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, rex2(out_reg0, in_reg0), sink);
|
||||||
|
modrm_rr(out_reg0, in_reg0, sink);
|
||||||
|
''')
|
||||||
|
|
||||||
# XX /n with one arg in %rcx, for shifts.
|
# XX /n with one arg in %rcx, for shifts.
|
||||||
rc = TailRecipe('rc', Binary, size=1, ins=(GPR, GPR.rcx), outs=0)
|
rc = TailRecipe(
|
||||||
|
'rc', Binary, size=1, ins=(GPR, GPR.rcx), outs=0,
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, rex1(in_reg0), sink);
|
||||||
|
modrm_r_bits(in_reg0, bits, sink);
|
||||||
|
''')
|
||||||
|
|
||||||
# XX /n ib with 8-bit immediate sign-extended.
|
# XX /n ib with 8-bit immediate sign-extended.
|
||||||
rib = TailRecipe(
|
rib = TailRecipe(
|
||||||
'rib', BinaryImm, size=2, ins=GPR, outs=0,
|
'rib', BinaryImm, size=2, ins=GPR, outs=0,
|
||||||
instp=IsSignedInt(BinaryImm.imm, 8))
|
instp=IsSignedInt(BinaryImm.imm, 8),
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, rex1(in_reg0), sink);
|
||||||
|
modrm_r_bits(in_reg0, bits, sink);
|
||||||
|
let imm: i64 = imm.into();
|
||||||
|
sink.put1(imm as u8);
|
||||||
|
''')
|
||||||
|
|
||||||
# XX /n id with 32-bit immediate sign-extended.
|
# XX /n id with 32-bit immediate sign-extended.
|
||||||
rid = TailRecipe(
|
rid = TailRecipe(
|
||||||
'rid', BinaryImm, size=5, ins=GPR, outs=0,
|
'rid', BinaryImm, size=5, ins=GPR, outs=0,
|
||||||
instp=IsSignedInt(BinaryImm.imm, 32))
|
instp=IsSignedInt(BinaryImm.imm, 32),
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, rex1(in_reg0), sink);
|
||||||
|
modrm_r_bits(in_reg0, bits, sink);
|
||||||
|
let imm: i64 = imm.into();
|
||||||
|
sink.put4(imm as u32);
|
||||||
|
''')
|
||||||
|
|
||||||
# XX+rd id unary with 32-bit immediate.
|
# XX+rd id unary with 32-bit immediate.
|
||||||
uid = TailRecipe(
|
uid = TailRecipe(
|
||||||
'uid', UnaryImm, size=4, ins=(), outs=GPR,
|
'uid', UnaryImm, size=4, ins=(), outs=GPR,
|
||||||
instp=IsSignedInt(UnaryImm.imm, 32))
|
instp=IsSignedInt(UnaryImm.imm, 32),
|
||||||
|
emit='''
|
||||||
|
// The destination register is encoded in the low bits of the opcode.
|
||||||
|
// No ModR/M.
|
||||||
|
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
|
||||||
|
let imm: i64 = imm.into();
|
||||||
|
sink.put4(imm as u32);
|
||||||
|
''')
|
||||||
|
|
||||||
#
|
#
|
||||||
# Store recipes.
|
# Store recipes.
|
||||||
@@ -172,26 +227,59 @@ uid = TailRecipe(
|
|||||||
# XX /r register-indirect store with no offset.
|
# XX /r register-indirect store with no offset.
|
||||||
st = TailRecipe(
|
st = TailRecipe(
|
||||||
'st', Store, size=1, ins=(GPR, GPR), outs=(),
|
'st', Store, size=1, ins=(GPR, GPR), outs=(),
|
||||||
instp=IsEqual(Store.offset, 0))
|
instp=IsEqual(Store.offset, 0),
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||||
|
modrm_rm(in_reg1, in_reg0, sink);
|
||||||
|
''')
|
||||||
|
|
||||||
# XX /r register-indirect store with no offset.
|
# XX /r register-indirect store with no offset.
|
||||||
# Only ABCD allowed for stored value. This is for byte stores.
|
# Only ABCD allowed for stored value. This is for byte stores.
|
||||||
st_abcd = TailRecipe(
|
st_abcd = TailRecipe(
|
||||||
'st_abcd', Store, size=1, ins=(ABCD, GPR), outs=(),
|
'st_abcd', Store, size=1, ins=(ABCD, GPR), outs=(),
|
||||||
instp=IsEqual(Store.offset, 0))
|
instp=IsEqual(Store.offset, 0),
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||||
|
modrm_rm(in_reg1, in_reg0, sink);
|
||||||
|
''')
|
||||||
|
|
||||||
# XX /r register-indirect store with 8-bit offset.
|
# XX /r register-indirect store with 8-bit offset.
|
||||||
stDisp8 = TailRecipe(
|
stDisp8 = TailRecipe(
|
||||||
'stDisp8', Store, size=2, ins=(GPR, GPR), outs=(),
|
'stDisp8', Store, size=2, ins=(GPR, GPR), outs=(),
|
||||||
instp=IsSignedInt(Store.offset, 8))
|
instp=IsSignedInt(Store.offset, 8),
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||||
|
modrm_disp8(in_reg1, in_reg0, sink);
|
||||||
|
let offset: i32 = offset.into();
|
||||||
|
sink.put1(offset as u8);
|
||||||
|
''')
|
||||||
stDisp8_abcd = TailRecipe(
|
stDisp8_abcd = TailRecipe(
|
||||||
'stDisp8_abcd', Store, size=2, ins=(ABCD, GPR), outs=(),
|
'stDisp8_abcd', Store, size=2, ins=(ABCD, GPR), outs=(),
|
||||||
instp=IsSignedInt(Store.offset, 8))
|
instp=IsSignedInt(Store.offset, 8),
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||||
|
modrm_disp8(in_reg1, in_reg0, sink);
|
||||||
|
let offset: i32 = offset.into();
|
||||||
|
sink.put1(offset as u8);
|
||||||
|
''')
|
||||||
|
|
||||||
# XX /r register-indirect store with 32-bit offset.
|
# XX /r register-indirect store with 32-bit offset.
|
||||||
stDisp32 = TailRecipe('stDisp32', Store, size=5, ins=(GPR, GPR), outs=())
|
stDisp32 = TailRecipe(
|
||||||
|
'stDisp32', Store, size=5, ins=(GPR, GPR), outs=(),
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||||
|
modrm_disp32(in_reg1, in_reg0, sink);
|
||||||
|
let offset: i32 = offset.into();
|
||||||
|
sink.put4(offset as u32);
|
||||||
|
''')
|
||||||
stDisp32_abcd = TailRecipe(
|
stDisp32_abcd = TailRecipe(
|
||||||
'stDisp32_abcd', Store, size=5, ins=(ABCD, GPR), outs=())
|
'stDisp32_abcd', Store, size=5, ins=(ABCD, GPR), outs=(),
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||||
|
modrm_disp32(in_reg1, in_reg0, sink);
|
||||||
|
let offset: i32 = offset.into();
|
||||||
|
sink.put4(offset as u32);
|
||||||
|
''')
|
||||||
|
|
||||||
#
|
#
|
||||||
# Load recipes
|
# Load recipes
|
||||||
@@ -200,21 +288,54 @@ stDisp32_abcd = TailRecipe(
|
|||||||
# XX /r load with no offset.
|
# XX /r load with no offset.
|
||||||
ld = TailRecipe(
|
ld = TailRecipe(
|
||||||
'ld', Load, size=1, ins=(GPR), outs=(GPR),
|
'ld', Load, size=1, ins=(GPR), outs=(GPR),
|
||||||
instp=IsEqual(Load.offset, 0))
|
instp=IsEqual(Load.offset, 0),
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, rex2(out_reg0, in_reg0), sink);
|
||||||
|
modrm_rm(in_reg0, out_reg0, sink);
|
||||||
|
''')
|
||||||
|
|
||||||
# XX /r load with 8-bit offset.
|
# XX /r load with 8-bit offset.
|
||||||
ldDisp8 = TailRecipe(
|
ldDisp8 = TailRecipe(
|
||||||
'ldDisp8', Load, size=2, ins=(GPR), outs=(GPR),
|
'ldDisp8', Load, size=2, ins=(GPR), outs=(GPR),
|
||||||
instp=IsSignedInt(Load.offset, 8))
|
instp=IsSignedInt(Load.offset, 8),
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, rex2(out_reg0, in_reg0), sink);
|
||||||
|
modrm_disp8(in_reg0, out_reg0, sink);
|
||||||
|
let offset: i32 = offset.into();
|
||||||
|
sink.put1(offset as u8);
|
||||||
|
''')
|
||||||
|
|
||||||
# XX /r load with 32-bit offset.
|
# XX /r load with 32-bit offset.
|
||||||
ldDisp32 = TailRecipe(
|
ldDisp32 = TailRecipe(
|
||||||
'ldDisp32', Load, size=5, ins=(GPR), outs=(GPR),
|
'ldDisp32', Load, size=5, ins=(GPR), outs=(GPR),
|
||||||
instp=IsSignedInt(Load.offset, 32))
|
instp=IsSignedInt(Load.offset, 32),
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, rex2(out_reg0, in_reg0), sink);
|
||||||
|
modrm_disp32(in_reg0, out_reg0, sink);
|
||||||
|
let offset: i32 = offset.into();
|
||||||
|
sink.put4(offset as u32);
|
||||||
|
''')
|
||||||
|
|
||||||
#
|
#
|
||||||
# Call/return
|
# Call/return
|
||||||
#
|
#
|
||||||
call_id = TailRecipe('call_id', Call, size=4, ins=(), outs=())
|
call_id = TailRecipe(
|
||||||
call_r = TailRecipe('call_r', IndirectCall, size=1, ins=GPR, outs=())
|
'call_id', Call, size=4, ins=(), outs=(),
|
||||||
ret = TailRecipe('ret', MultiAry, size=0, ins=(), outs=())
|
emit='''
|
||||||
|
PUT_OP(bits, BASE_REX, sink);
|
||||||
|
sink.reloc_func(RelocKind::PCRel4.into(), func_ref);
|
||||||
|
sink.put4(0);
|
||||||
|
''')
|
||||||
|
|
||||||
|
call_r = TailRecipe(
|
||||||
|
'call_r', IndirectCall, size=1, ins=GPR, outs=(),
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, rex1(in_reg0), sink);
|
||||||
|
modrm_r_bits(in_reg0, bits, sink);
|
||||||
|
''')
|
||||||
|
|
||||||
|
ret = TailRecipe(
|
||||||
|
'ret', MultiAry, size=0, ins=(), outs=(),
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, BASE_REX, sink);
|
||||||
|
''')
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
//! Emitting binary Intel machine code.
|
//! Emitting binary Intel machine code.
|
||||||
|
|
||||||
use binemit::{CodeSink, Reloc, bad_encoding};
|
use binemit::{CodeSink, Reloc, bad_encoding};
|
||||||
use ir::{self, Function, Inst, InstructionData, MemFlags};
|
use ir::{Function, Inst, InstructionData};
|
||||||
use ir::immediates::{Imm64, Offset32};
|
|
||||||
use isa::RegUnit;
|
use isa::RegUnit;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/binemit-intel.rs"));
|
include!(concat!(env!("OUT_DIR"), "/binemit-intel.rs"));
|
||||||
@@ -21,27 +20,51 @@ impl Into<Reloc> for RelocKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit single-byte opcode.
|
// Mandatory prefix bytes for Mp* opcodes.
|
||||||
fn put_op1<CS: CodeSink + ?Sized>(bits: u16, sink: &mut CS) {
|
const PREFIX: [u8; 3] = [0x66, 0xf3, 0xf2];
|
||||||
debug_assert_eq!(bits & 0x0f00, 0, "Invalid encoding bits for Op1*");
|
|
||||||
|
// A REX prefix with no bits set: 0b0100WRXB.
|
||||||
|
const BASE_REX: u8 = 0b0100_0000;
|
||||||
|
|
||||||
|
// Create a single-register REX prefix, setting the B bit to bit 3 of the register.
|
||||||
|
// This is used for instructions that encode a register in the low 3 bits of the opcode and for
|
||||||
|
// instructions that use the ModR/M `reg` field for something else.
|
||||||
|
fn rex1(reg_b: RegUnit) -> u8 {
|
||||||
|
let b = ((reg_b >> 3) & 1) as u8;
|
||||||
|
BASE_REX | b
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a dual-register REX prefix, setting:
|
||||||
|
//
|
||||||
|
// REX.B = bit 3 of r/m register.
|
||||||
|
// REX.R = bit 3 of reg register.
|
||||||
|
fn rex2(rm: RegUnit, reg: RegUnit) -> u8 {
|
||||||
|
let b = ((rm >> 3) & 1) as u8;
|
||||||
|
let r = ((reg >> 3) & 1) as u8;
|
||||||
|
BASE_REX | b | (r << 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit a single-byte opcode with no REX prefix.
|
||||||
|
fn put_op1<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||||
|
debug_assert_eq!(bits & 0x8f00, 0, "Invalid encoding bits for Op1*");
|
||||||
|
debug_assert_eq!(rex, BASE_REX, "Invalid registers for REX-less encoding");
|
||||||
sink.put1(bits as u8);
|
sink.put1(bits as u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit two-byte opcode: 0F XX
|
// Emit two-byte opcode: 0F XX
|
||||||
fn put_op2<CS: CodeSink + ?Sized>(bits: u16, sink: &mut CS) {
|
fn put_op2<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||||
debug_assert_eq!(bits & 0x0f00, 0x0400, "Invalid encoding bits for Op2*");
|
debug_assert_eq!(bits & 0x8f00, 0x0400, "Invalid encoding bits for Op2*");
|
||||||
|
debug_assert_eq!(rex, BASE_REX, "Invalid registers for REX-less encoding");
|
||||||
sink.put1(0x0f);
|
sink.put1(0x0f);
|
||||||
sink.put1(bits as u8);
|
sink.put1(bits as u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mandatory prefix bytes for Mp* opcodes.
|
|
||||||
const PREFIX: [u8; 3] = [0x66, 0xf3, 0xf2];
|
|
||||||
|
|
||||||
// Emit single-byte opcode with mandatory prefix.
|
// Emit single-byte opcode with mandatory prefix.
|
||||||
fn put_mp1<CS: CodeSink + ?Sized>(bits: u16, sink: &mut CS) {
|
fn put_mp1<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||||
debug_assert_eq!(bits & 0x0c00, 0, "Invalid encoding bits for Mp1*");
|
debug_assert_eq!(bits & 0x0c00, 0, "Invalid encoding bits for Mp1*");
|
||||||
let pp = (bits >> 8) & 3;
|
let pp = (bits >> 8) & 3;
|
||||||
sink.put1(PREFIX[(pp - 1) as usize]);
|
sink.put1(PREFIX[(pp - 1) as usize]);
|
||||||
|
debug_assert_eq!(rex, BASE_REX, "Invalid registers for REX-less encoding");
|
||||||
sink.put1(bits as u8);
|
sink.put1(bits as u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,290 +123,3 @@ fn modrm_disp32<CS: CodeSink + ?Sized>(rm: RegUnit, reg: RegUnit, sink: &mut CS)
|
|||||||
b |= rm;
|
b |= rm;
|
||||||
sink.put1(b);
|
sink.put1(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recipe_op1rr<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
in_reg1: RegUnit) {
|
|
||||||
put_op1(bits, sink);
|
|
||||||
modrm_rr(in_reg0, in_reg1, sink);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op1ur<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
out_reg0: RegUnit) {
|
|
||||||
put_op1(bits, sink);
|
|
||||||
modrm_rr(out_reg0, in_reg0, sink);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op1rc<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit) {
|
|
||||||
put_op1(bits, sink);
|
|
||||||
modrm_r_bits(in_reg0, bits, sink);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op1rib<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
imm: Imm64) {
|
|
||||||
put_op1(bits, sink);
|
|
||||||
modrm_r_bits(in_reg0, bits, sink);
|
|
||||||
let imm: i64 = imm.into();
|
|
||||||
sink.put1(imm as u8);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op1rid<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
imm: Imm64) {
|
|
||||||
put_op1(bits, sink);
|
|
||||||
modrm_r_bits(in_reg0, bits, sink);
|
|
||||||
let imm: i64 = imm.into();
|
|
||||||
sink.put4(imm as u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op1uid<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
imm: Imm64,
|
|
||||||
out_reg0: RegUnit) {
|
|
||||||
// The destination register is encoded in the low bits of the opcode. No ModR/M
|
|
||||||
put_op1(bits | (out_reg0 & 7), sink);
|
|
||||||
let imm: i64 = imm.into();
|
|
||||||
sink.put4(imm as u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store recipes.
|
|
||||||
|
|
||||||
fn recipe_op1st<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
in_reg1: RegUnit,
|
|
||||||
_flags: MemFlags,
|
|
||||||
_offset: Offset32) {
|
|
||||||
put_op1(bits, sink);
|
|
||||||
modrm_rm(in_reg1, in_reg0, sink);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is just a tighter register class constraint.
|
|
||||||
fn recipe_op1st_abcd<CS: CodeSink + ?Sized>(func: &Function,
|
|
||||||
inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
in_reg1: RegUnit,
|
|
||||||
flags: MemFlags,
|
|
||||||
offset: Offset32) {
|
|
||||||
recipe_op1st(func, inst, sink, bits, in_reg0, in_reg1, flags, offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_mp1st<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
in_reg1: RegUnit,
|
|
||||||
_flags: MemFlags,
|
|
||||||
_offset: Offset32) {
|
|
||||||
put_mp1(bits, sink);
|
|
||||||
modrm_rm(in_reg1, in_reg0, sink);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op1stdisp8<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
in_reg1: RegUnit,
|
|
||||||
_flags: MemFlags,
|
|
||||||
offset: Offset32) {
|
|
||||||
put_op1(bits, sink);
|
|
||||||
modrm_disp8(in_reg1, in_reg0, sink);
|
|
||||||
let offset: i32 = offset.into();
|
|
||||||
sink.put1(offset as u8);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op1stdisp8_abcd<CS: CodeSink + ?Sized>(func: &Function,
|
|
||||||
inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
in_reg1: RegUnit,
|
|
||||||
flags: MemFlags,
|
|
||||||
offset: Offset32) {
|
|
||||||
recipe_op1stdisp8(func, inst, sink, bits, in_reg0, in_reg1, flags, offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_mp1stdisp8<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
in_reg1: RegUnit,
|
|
||||||
_flags: MemFlags,
|
|
||||||
offset: Offset32) {
|
|
||||||
put_mp1(bits, sink);
|
|
||||||
modrm_disp8(in_reg1, in_reg0, sink);
|
|
||||||
let offset: i32 = offset.into();
|
|
||||||
sink.put1(offset as u8);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op1stdisp32<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
in_reg1: RegUnit,
|
|
||||||
_flags: MemFlags,
|
|
||||||
offset: Offset32) {
|
|
||||||
put_op1(bits, sink);
|
|
||||||
modrm_disp32(in_reg1, in_reg0, sink);
|
|
||||||
let offset: i32 = offset.into();
|
|
||||||
sink.put4(offset as u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op1stdisp32_abcd<CS: CodeSink + ?Sized>(func: &Function,
|
|
||||||
inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
in_reg1: RegUnit,
|
|
||||||
flags: MemFlags,
|
|
||||||
offset: Offset32) {
|
|
||||||
recipe_op1stdisp32(func, inst, sink, bits, in_reg0, in_reg1, flags, offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_mp1stdisp32<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
in_reg1: RegUnit,
|
|
||||||
_flags: MemFlags,
|
|
||||||
offset: Offset32) {
|
|
||||||
put_mp1(bits, sink);
|
|
||||||
modrm_disp32(in_reg1, in_reg0, sink);
|
|
||||||
let offset: i32 = offset.into();
|
|
||||||
sink.put4(offset as u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load recipes
|
|
||||||
|
|
||||||
fn recipe_op1ld<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
_flags: MemFlags,
|
|
||||||
_offset: Offset32,
|
|
||||||
out_reg0: RegUnit) {
|
|
||||||
put_op1(bits, sink);
|
|
||||||
modrm_rm(in_reg0, out_reg0, sink);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op1lddisp8<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
_flags: MemFlags,
|
|
||||||
offset: Offset32,
|
|
||||||
out_reg0: RegUnit) {
|
|
||||||
put_op1(bits, sink);
|
|
||||||
modrm_disp8(in_reg0, out_reg0, sink);
|
|
||||||
let offset: i32 = offset.into();
|
|
||||||
sink.put1(offset as u8);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op1lddisp32<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
_flags: MemFlags,
|
|
||||||
offset: Offset32,
|
|
||||||
out_reg0: RegUnit) {
|
|
||||||
put_op1(bits, sink);
|
|
||||||
modrm_disp32(in_reg0, out_reg0, sink);
|
|
||||||
let offset: i32 = offset.into();
|
|
||||||
sink.put4(offset as u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op2ld<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
_flags: MemFlags,
|
|
||||||
_offset: Offset32,
|
|
||||||
out_reg0: RegUnit) {
|
|
||||||
put_op2(bits, sink);
|
|
||||||
modrm_rm(in_reg0, out_reg0, sink);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op2lddisp8<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
_flags: MemFlags,
|
|
||||||
offset: Offset32,
|
|
||||||
out_reg0: RegUnit) {
|
|
||||||
put_op2(bits, sink);
|
|
||||||
modrm_disp8(in_reg0, out_reg0, sink);
|
|
||||||
let offset: i32 = offset.into();
|
|
||||||
sink.put1(offset as u8);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op2lddisp32<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
_flags: MemFlags,
|
|
||||||
offset: Offset32,
|
|
||||||
out_reg0: RegUnit) {
|
|
||||||
put_op2(bits, sink);
|
|
||||||
modrm_disp32(in_reg0, out_reg0, sink);
|
|
||||||
let offset: i32 = offset.into();
|
|
||||||
sink.put4(offset as u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op1call_id<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
func_ref: ir::FuncRef) {
|
|
||||||
put_op1(bits, sink);
|
|
||||||
sink.reloc_func(RelocKind::PCRel4.into(), func_ref);
|
|
||||||
sink.put4(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op1call_r<CS: CodeSink + ?Sized>(_func: &Function,
|
|
||||||
_inst: Inst,
|
|
||||||
sink: &mut CS,
|
|
||||||
bits: u16,
|
|
||||||
in_reg0: RegUnit,
|
|
||||||
_sig_ref: ir::SigRef) {
|
|
||||||
put_op1(bits, sink);
|
|
||||||
modrm_r_bits(in_reg0, bits, sink);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recipe_op1ret<CS: CodeSink + ?Sized>(_func: &Function, _inst: Inst, sink: &mut CS, bits: u16) {
|
|
||||||
put_op1(bits, sink);
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user