Added Intel x86-64 encodings for 64bit loads and store instructions (#127)
* Added Intel x86-64 encodings for 64bit loads and store instructions * Using GPR registers instead of ABCD for istore8 with REX prefix Fixed testing of 64bit intel encoding * Emit REX and REX-less encodings for optional REX prefix Value renumbering in binary64.cton
This commit is contained in:
committed by
Jakob Stoklund Olesen
parent
54534e2147
commit
07e1f682d0
@@ -271,7 +271,7 @@ istore16 = Instruction(
|
||||
'istore16', r"""
|
||||
Store the low 16 bits of ``x`` to memory at ``p + Offset``.
|
||||
|
||||
This is equivalent to ``ireduce.i16`` followed by ``store.i8``.
|
||||
This is equivalent to ``ireduce.i16`` followed by ``store.i16``.
|
||||
""",
|
||||
ins=(Flags, x, p, Offset), can_store=True)
|
||||
|
||||
@@ -301,7 +301,7 @@ istore32 = Instruction(
|
||||
'istore32', r"""
|
||||
Store the low 32 bits of ``x`` to memory at ``p + Offset``.
|
||||
|
||||
This is equivalent to ``ireduce.i32`` followed by ``store.i8``.
|
||||
This is equivalent to ``ireduce.i32`` followed by ``store.i32``.
|
||||
""",
|
||||
ins=(Flags, x, p, Offset), can_store=True)
|
||||
|
||||
|
||||
@@ -55,6 +55,28 @@ def enc_i32_i64(inst, recipe, *args, **kwargs):
|
||||
I64.enc(inst.i64, *recipe.rex(*args, w=1, **kwargs))
|
||||
|
||||
|
||||
def enc_i32_i64_ld_st(inst, w_bit, recipe, *args, **kwargs):
|
||||
# type: (MaybeBoundInst, bool, r.TailRecipe, *int, **int) -> None
|
||||
"""
|
||||
Add encodings for `inst.i32` to I32.
|
||||
Add encodings for `inst.i32` to I64 with and without REX.
|
||||
Add encodings for `inst.i64` to I64 with a REX prefix, using the `w_bit`
|
||||
argument to determine wheter or not to set the REX.W bit.
|
||||
"""
|
||||
I32.enc(inst.i32.any, *recipe(*args, **kwargs))
|
||||
|
||||
# REX-less encoding must come after REX encoding so we don't use it by
|
||||
# default. Otherwise reg-alloc would never use r8 and up.
|
||||
I64.enc(inst.i32.any, *recipe.rex(*args, **kwargs))
|
||||
I64.enc(inst.i32.any, *recipe(*args, **kwargs))
|
||||
|
||||
if w_bit:
|
||||
I64.enc(inst.i64.any, *recipe.rex(*args, w=1, **kwargs))
|
||||
else:
|
||||
I64.enc(inst.i64.any, *recipe.rex(*args, **kwargs))
|
||||
I64.enc(inst.i64.any, *recipe(*args, **kwargs))
|
||||
|
||||
|
||||
def enc_flt(inst, recipe, *args, **kwargs):
|
||||
# type: (MaybeBoundInst, r.TailRecipe, *int, **int) -> None
|
||||
"""
|
||||
@@ -142,38 +164,60 @@ I64.enc(base.ctz.i64, *r.urm.rex(0xf3, 0x0f, 0xbc, w=1),
|
||||
I64.enc(base.ctz.i32, *r.urm.rex(0xf3, 0x0f, 0xbc), isap=cfg.use_bmi1)
|
||||
I64.enc(base.ctz.i32, *r.urm(0xf3, 0x0f, 0xbc), isap=cfg.use_bmi1)
|
||||
|
||||
#
|
||||
# Loads and stores.
|
||||
I32.enc(base.store.i32.any, *r.st(0x89))
|
||||
I32.enc(base.store.i32.any, *r.stDisp8(0x89))
|
||||
I32.enc(base.store.i32.any, *r.stDisp32(0x89))
|
||||
#
|
||||
enc_i32_i64_ld_st(base.store, True, r.st, 0x89)
|
||||
enc_i32_i64_ld_st(base.store, True, r.stDisp8, 0x89)
|
||||
enc_i32_i64_ld_st(base.store, True, r.stDisp32, 0x89)
|
||||
|
||||
I32.enc(base.istore16.i32.any, *r.st(0x66, 0x89))
|
||||
I32.enc(base.istore16.i32.any, *r.stDisp8(0x66, 0x89))
|
||||
I32.enc(base.istore16.i32.any, *r.stDisp32(0x66, 0x89))
|
||||
I64.enc(base.istore32.i64.any, *r.st.rex(0x89))
|
||||
I64.enc(base.istore32.i64.any, *r.stDisp8.rex(0x89))
|
||||
I64.enc(base.istore32.i64.any, *r.stDisp32.rex(0x89))
|
||||
|
||||
enc_i32_i64_ld_st(base.istore16, False, r.st, 0x66, 0x89)
|
||||
enc_i32_i64_ld_st(base.istore16, False, r.stDisp8, 0x66, 0x89)
|
||||
enc_i32_i64_ld_st(base.istore16, False, r.stDisp32, 0x66, 0x89)
|
||||
|
||||
# Byte stores are more complicated because the registers they can address
|
||||
# depends of the presence of a REX prefix
|
||||
I32.enc(base.istore8.i32.any, *r.st_abcd(0x88))
|
||||
I64.enc(base.istore8.i32.any, *r.st_abcd(0x88))
|
||||
I64.enc(base.istore8.i64.any, *r.st.rex(0x88))
|
||||
I32.enc(base.istore8.i32.any, *r.stDisp8_abcd(0x88))
|
||||
I64.enc(base.istore8.i32.any, *r.stDisp8_abcd(0x88))
|
||||
I64.enc(base.istore8.i64.any, *r.stDisp8.rex(0x88))
|
||||
I32.enc(base.istore8.i32.any, *r.stDisp32_abcd(0x88))
|
||||
I64.enc(base.istore8.i32.any, *r.stDisp32_abcd(0x88))
|
||||
I64.enc(base.istore8.i64.any, *r.stDisp32.rex(0x88))
|
||||
|
||||
I32.enc(base.load.i32.any, *r.ld(0x8b))
|
||||
I32.enc(base.load.i32.any, *r.ldDisp8(0x8b))
|
||||
I32.enc(base.load.i32.any, *r.ldDisp32(0x8b))
|
||||
enc_i32_i64_ld_st(base.load, True, r.ld, 0x8b)
|
||||
enc_i32_i64_ld_st(base.load, True, r.ldDisp8, 0x8b)
|
||||
enc_i32_i64_ld_st(base.load, True, r.ldDisp32, 0x8b)
|
||||
|
||||
I32.enc(base.uload16.i32.any, *r.ld(0x0f, 0xb7))
|
||||
I32.enc(base.uload16.i32.any, *r.ldDisp8(0x0f, 0xb7))
|
||||
I32.enc(base.uload16.i32.any, *r.ldDisp32(0x0f, 0xb7))
|
||||
I64.enc(base.uload32.i64, *r.ld.rex(0x8b))
|
||||
I64.enc(base.uload32.i64, *r.ldDisp8.rex(0x8b))
|
||||
I64.enc(base.uload32.i64, *r.ldDisp32.rex(0x8b))
|
||||
|
||||
I32.enc(base.sload16.i32.any, *r.ld(0x0f, 0xbf))
|
||||
I32.enc(base.sload16.i32.any, *r.ldDisp8(0x0f, 0xbf))
|
||||
I32.enc(base.sload16.i32.any, *r.ldDisp32(0x0f, 0xbf))
|
||||
I64.enc(base.sload32.i64, *r.ld.rex(0x63, w=1))
|
||||
I64.enc(base.sload32.i64, *r.ldDisp8.rex(0x63, w=1))
|
||||
I64.enc(base.sload32.i64, *r.ldDisp32.rex(0x63, w=1))
|
||||
|
||||
I32.enc(base.uload8.i32.any, *r.ld(0x0f, 0xb6))
|
||||
I32.enc(base.uload8.i32.any, *r.ldDisp8(0x0f, 0xb6))
|
||||
I32.enc(base.uload8.i32.any, *r.ldDisp32(0x0f, 0xb6))
|
||||
enc_i32_i64_ld_st(base.uload16, True, r.ld, 0x0f, 0xb7)
|
||||
enc_i32_i64_ld_st(base.uload16, True, r.ldDisp8, 0x0f, 0xb7)
|
||||
enc_i32_i64_ld_st(base.uload16, True, r.ldDisp32, 0x0f, 0xb7)
|
||||
|
||||
I32.enc(base.sload8.i32.any, *r.ld(0x0f, 0xbe))
|
||||
I32.enc(base.sload8.i32.any, *r.ldDisp8(0x0f, 0xbe))
|
||||
I32.enc(base.sload8.i32.any, *r.ldDisp32(0x0f, 0xbe))
|
||||
enc_i32_i64_ld_st(base.sload16, True, r.ld, 0x0f, 0xbf)
|
||||
enc_i32_i64_ld_st(base.sload16, True, r.ldDisp8, 0x0f, 0xbf)
|
||||
enc_i32_i64_ld_st(base.sload16, True, r.ldDisp32, 0x0f, 0xbf)
|
||||
|
||||
enc_i32_i64_ld_st(base.uload8, True, r.ld, 0x0f, 0xb6)
|
||||
enc_i32_i64_ld_st(base.uload8, True, r.ldDisp8, 0x0f, 0xb6)
|
||||
enc_i32_i64_ld_st(base.uload8, True, r.ldDisp32, 0x0f, 0xb6)
|
||||
|
||||
enc_i32_i64_ld_st(base.sload8, True, r.ld, 0x0f, 0xbe)
|
||||
enc_i32_i64_ld_st(base.sload8, True, r.ldDisp8, 0x0f, 0xbe)
|
||||
enc_i32_i64_ld_st(base.sload8, True, r.ldDisp32, 0x0f, 0xbe)
|
||||
|
||||
#
|
||||
# Call/return
|
||||
|
||||
@@ -114,6 +114,15 @@ fn put_rexmp2<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||
sink.put1(bits as u8);
|
||||
}
|
||||
|
||||
// Emit single-byte opcode with mandatory prefix and REX.
|
||||
fn put_rexmp1<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||
debug_assert_eq!(bits & 0x0c00, 0, "Invalid encoding bits for Mp1*");
|
||||
let pp = (bits >> 8) & 3;
|
||||
sink.put1(PREFIX[(pp - 1) as usize]);
|
||||
rex_prefix(bits, rex, sink);
|
||||
sink.put1(bits as u8);
|
||||
}
|
||||
|
||||
/// Emit a ModR/M byte for reg-reg operands.
|
||||
fn modrm_rr<CS: CodeSink + ?Sized>(rm: RegUnit, reg: RegUnit, sink: &mut CS) {
|
||||
let reg = reg as u8 & 7;
|
||||
|
||||
Reference in New Issue
Block a user