Encodings for load/store instructions.

We don't support the full set of Intel addressing modes yet. So far we
have:

- Register indirect, no displacement.
- Register indirect, 8-bit signed displacement.
- Register indirect, 32-bit signed displacement.

The SIB addressing modes will need new Cretonne instruction formats to
represent.
This commit is contained in:
Jakob Stoklund Olesen
2017-05-12 14:26:44 -07:00
parent f4929825ca
commit bd8230411a
5 changed files with 470 additions and 27 deletions

View File

@@ -92,5 +92,110 @@ ebb0:
; asm: xorl $1000000, %esi
[-,%rsi] v47 = bxor_imm v2, 1000000 ; bin: 81 f6 000f4240
; Load/Store instructions.
; Register indirect addressing with no displacement.
; asm: movl %ecx, (%esi)
store v1, v2 ; bin: 89 0e
; asm: movl %esi, (%ecx)
store v2, v1 ; bin: 89 31
; asm: movw %cx, (%esi)
istore16 v1, v2 ; bin: 66 89 0e
; asm: movw %si, (%ecx)
istore16 v2, v1 ; bin: 66 89 31
; asm: movb %cl, (%esi)
istore8 v1, v2 ; bin: 88 0e
; Can't store %sil in 32-bit mode (needs REX prefix).
; asm: movl (%ecx), %edi
[-,%rdi] v100 = load.i32 v1 ; bin: 8b 39
; asm: movl (%esi), %edx
[-,%rdx] v101 = load.i32 v2 ; bin: 8b 16
; asm: movzwl (%ecx), %edi
[-,%rdi] v102 = uload16.i32 v1 ; bin: 0f b7 39
; asm: movzwl (%esi), %edx
[-,%rdx] v103 = uload16.i32 v2 ; bin: 0f b7 16
; asm: movswl (%ecx), %edi
[-,%rdi] v104 = sload16.i32 v1 ; bin: 0f bf 39
; asm: movswl (%esi), %edx
[-,%rdx] v105 = sload16.i32 v2 ; bin: 0f bf 16
; asm: movzbl (%ecx), %edi
[-,%rdi] v106 = uload8.i32 v1 ; bin: 0f b6 39
; asm: movzbl (%esi), %edx
[-,%rdx] v107 = uload8.i32 v2 ; bin: 0f b6 16
; asm: movsbl (%ecx), %edi
[-,%rdi] v108 = sload8.i32 v1 ; bin: 0f be 39
; asm: movsbl (%esi), %edx
[-,%rdx] v109 = sload8.i32 v2 ; bin: 0f be 16
; Register-indirect with 8-bit signed displacement.
; asm: movl %ecx, 100(%esi)
store v1, v2+100 ; bin: 89 4e 64
; asm: movl %esi, -100(%ecx)
store v2, v1-100 ; bin: 89 71 9c
; asm: movw %cx, 100(%esi)
istore16 v1, v2+100 ; bin: 66 89 4e 64
; asm: movw %si, -100(%ecx)
istore16 v2, v1-100 ; bin: 66 89 71 9c
; asm: movb %cl, 100(%esi)
istore8 v1, v2+100 ; bin: 88 4e 64
; asm: movl 50(%ecx), %edi
[-,%rdi] v110 = load.i32 v1+50 ; bin: 8b 79 32
; asm: movl -50(%esi), %edx
[-,%rdx] v111 = load.i32 v2-50 ; bin: 8b 56 ce
; asm: movzwl 50(%ecx), %edi
[-,%rdi] v112 = uload16.i32 v1+50 ; bin: 0f b7 79 32
; asm: movzwl -50(%esi), %edx
[-,%rdx] v113 = uload16.i32 v2-50 ; bin: 0f b7 56 ce
; asm: movswl 50(%ecx), %edi
[-,%rdi] v114 = sload16.i32 v1+50 ; bin: 0f bf 79 32
; asm: movswl -50(%esi), %edx
[-,%rdx] v115 = sload16.i32 v2-50 ; bin: 0f bf 56 ce
; asm: movzbl 50(%ecx), %edi
[-,%rdi] v116 = uload8.i32 v1+50 ; bin: 0f b6 79 32
; asm: movzbl -50(%esi), %edx
[-,%rdx] v117 = uload8.i32 v2-50 ; bin: 0f b6 56 ce
; asm: movsbl 50(%ecx), %edi
[-,%rdi] v118 = sload8.i32 v1+50 ; bin: 0f be 79 32
; asm: movsbl -50(%esi), %edx
[-,%rdx] v119 = sload8.i32 v2-50 ; bin: 0f be 56 ce
; Register-indirect with 32-bit signed displacement.
; asm: movl %ecx, 10000(%esi)
store v1, v2+10000 ; bin: 89 8e 00002710
; asm: movl %esi, -10000(%ecx)
store v2, v1-10000 ; bin: 89 b1 ffffd8f0
; asm: movw %cx, 10000(%esi)
istore16 v1, v2+10000 ; bin: 66 89 8e 00002710
; asm: movw %si, -10000(%ecx)
istore16 v2, v1-10000 ; bin: 66 89 b1 ffffd8f0
; asm: movb %cl, 10000(%esi)
istore8 v1, v2+10000 ; bin: 88 8e 00002710
; asm: movl 50000(%ecx), %edi
[-,%rdi] v120 = load.i32 v1+50000 ; bin: 8b b9 0000c350
; asm: movl -50000(%esi), %edx
[-,%rdx] v121 = load.i32 v2-50000 ; bin: 8b 96 ffff3cb0
; asm: movzwl 50000(%ecx), %edi
[-,%rdi] v122 = uload16.i32 v1+50000 ; bin: 0f b7 b9 0000c350
; asm: movzwl -50000(%esi), %edx
[-,%rdx] v123 = uload16.i32 v2-50000 ; bin: 0f b7 96 ffff3cb0
; asm: movswl 50000(%ecx), %edi
[-,%rdi] v124 = sload16.i32 v1+50000 ; bin: 0f bf b9 0000c350
; asm: movswl -50000(%esi), %edx
[-,%rdx] v125 = sload16.i32 v2-50000 ; bin: 0f bf 96 ffff3cb0
; asm: movzbl 50000(%ecx), %edi
[-,%rdi] v126 = uload8.i32 v1+50000 ; bin: 0f b6 b9 0000c350
; asm: movzbl -50000(%esi), %edx
[-,%rdx] v127 = uload8.i32 v2-50000 ; bin: 0f b6 96 ffff3cb0
; asm: movsbl 50000(%ecx), %edi
[-,%rdi] v128 = sload8.i32 v1+50000 ; bin: 0f be b9 0000c350
; asm: movsbl -50000(%esi), %edx
[-,%rdx] v129 = sload8.i32 v2-50000 ; bin: 0f be 96 ffff3cb0
return
}

View File

@@ -4,15 +4,15 @@ Intel Encodings.
from __future__ import absolute_import
from base import instructions as base
from .defs import I32
from .recipes import Op1rr, Op1rc, Op1rib, Op1rid
from .recipes import OP
from . import recipes as rcp
from .recipes import OP, OP0F, MP66
I32.enc(base.iadd.i32, Op1rr, OP(0x01))
I32.enc(base.isub.i32, Op1rr, OP(0x29))
I32.enc(base.iadd.i32, rcp.Op1rr, OP(0x01))
I32.enc(base.isub.i32, rcp.Op1rr, OP(0x29))
I32.enc(base.band.i32, Op1rr, OP(0x21))
I32.enc(base.bor.i32, Op1rr, OP(0x09))
I32.enc(base.bxor.i32, Op1rr, OP(0x31))
I32.enc(base.band.i32, rcp.Op1rr, OP(0x21))
I32.enc(base.bor.i32, rcp.Op1rr, OP(0x09))
I32.enc(base.bxor.i32, rcp.Op1rr, OP(0x31))
# Immediate instructions with sign-extended 8-bit and 32-bit immediate.
for inst, r in [
@@ -20,12 +20,45 @@ for inst, r in [
(base.band_imm.i32, 4),
(base.bor_imm.i32, 1),
(base.bxor_imm.i32, 6)]:
I32.enc(inst, Op1rib, OP(0x83, rrr=r))
I32.enc(inst, Op1rid, OP(0x81, rrr=r))
I32.enc(inst, rcp.Op1rib, OP(0x83, rrr=r))
I32.enc(inst, rcp.Op1rid, OP(0x81, rrr=r))
# 32-bit shifts and rotates.
# Note that the dynamic shift amount is only masked by 5 or 6 bits; the 8-bit
# and 16-bit shifts would need explicit masking.
I32.enc(base.ishl.i32.i32, Op1rc, OP(0xd3, rrr=4))
I32.enc(base.ushr.i32.i32, Op1rc, OP(0xd3, rrr=5))
I32.enc(base.sshr.i32.i32, Op1rc, OP(0xd3, rrr=7))
I32.enc(base.ishl.i32.i32, rcp.Op1rc, OP(0xd3, rrr=4))
I32.enc(base.ushr.i32.i32, rcp.Op1rc, OP(0xd3, rrr=5))
I32.enc(base.sshr.i32.i32, rcp.Op1rc, OP(0xd3, rrr=7))
# Loads and stores.
I32.enc(base.store.i32.i32, rcp.Op1st, OP(0x89))
I32.enc(base.store.i32.i32, rcp.Op1stDisp8, OP(0x89))
I32.enc(base.store.i32.i32, rcp.Op1stDisp32, OP(0x89))
I32.enc(base.istore16.i32.i32, rcp.Mp1st, MP66(0x89))
I32.enc(base.istore16.i32.i32, rcp.Mp1stDisp8, MP66(0x89))
I32.enc(base.istore16.i32.i32, rcp.Mp1stDisp32, MP66(0x89))
I32.enc(base.istore8.i32.i32, rcp.Op1st_abcd, OP(0x88))
I32.enc(base.istore8.i32.i32, rcp.Op1stDisp8_abcd, OP(0x88))
I32.enc(base.istore8.i32.i32, rcp.Op1stDisp32_abcd, OP(0x88))
I32.enc(base.load.i32.i32, rcp.Op1ld, OP(0x8b))
I32.enc(base.load.i32.i32, rcp.Op1ldDisp8, OP(0x8b))
I32.enc(base.load.i32.i32, rcp.Op1ldDisp32, OP(0x8b))
I32.enc(base.uload16.i32.i32, rcp.Op2ld, OP0F(0xb7))
I32.enc(base.uload16.i32.i32, rcp.Op2ldDisp8, OP0F(0xb7))
I32.enc(base.uload16.i32.i32, rcp.Op2ldDisp32, OP0F(0xb7))
I32.enc(base.sload16.i32.i32, rcp.Op2ld, OP0F(0xbf))
I32.enc(base.sload16.i32.i32, rcp.Op2ldDisp8, OP0F(0xbf))
I32.enc(base.sload16.i32.i32, rcp.Op2ldDisp32, OP0F(0xbf))
I32.enc(base.uload8.i32.i32, rcp.Op2ld, OP0F(0xb6))
I32.enc(base.uload8.i32.i32, rcp.Op2ldDisp8, OP0F(0xb6))
I32.enc(base.uload8.i32.i32, rcp.Op2ldDisp32, OP0F(0xb6))
I32.enc(base.sload8.i32.i32, rcp.Op2ld, OP0F(0xbe))
I32.enc(base.sload8.i32.i32, rcp.Op2ldDisp8, OP0F(0xbe))
I32.enc(base.sload8.i32.i32, rcp.Op2ldDisp32, OP0F(0xbe))

View File

@@ -3,9 +3,9 @@ Intel Encoding recipes.
"""
from __future__ import absolute_import
from cdsl.isa import EncRecipe
from cdsl.predicates import IsSignedInt
from base.formats import Binary, BinaryImm
from .registers import GPR
from cdsl.predicates import IsSignedInt, IsEqual
from base.formats import Binary, BinaryImm, Store, Load
from .registers import GPR, ABCD
# Opcode representation.
#
@@ -15,21 +15,21 @@ from .registers import GPR
# name prefix:
#
# <op> Op1* OP(op)
# 0F <op> Op2* OP(op)
# 0F <op> Op2* OP0F(op)
# 0F 38 <op> Op3* OP38(op)
# 0F 3A <op> Op3* OP3A(op)
# 66 <op> Mp1* MP66(op)
# 66 0F <op> Mp2* MP66(op)
# 66 0F 38 <op> Mp3* MP6638(op)
# 66 0F 3A <op> Mp3* MP663A(op)
# 66 0F <op> Mp2* MP660F(op)
# 66 0F 38 <op> Mp3* MP660F38(op)
# 66 0F 3A <op> Mp3* MP660F3A(op)
# F2 <op> Mp1* MPF2(op)
# F2 0F <op> Mp2* MPF2(op)
# F2 0F 38 <op> Mp3* MPF238(op)
# F2 0F 3A <op> Mp3* MPF23A(op)
# F2 0F <op> Mp2* MPF20F(op)
# F2 0F 38 <op> Mp3* MPF20F38(op)
# F2 0F 3A <op> Mp3* MPF20F3A(op)
# F3 <op> Mp1* MPF3(op)
# F3 0F <op> Mp2* MPF3(op)
# F3 0F 38 <op> Mp3* MPF338(op)
# F3 0F 3A <op> Mp3* MPF33A(op)
# F3 0F <op> Mp2* MP0FF3(op)
# F3 0F 38 <op> Mp3* MPF30F38(op)
# F3 0F 3A <op> Mp3* MPF30F3A(op)
#
# VEX/XOP and EVEX prefixes are not yet supported.
#
@@ -63,6 +63,16 @@ def OP(op, pp=0, mm=0, rrr=0, w=0):
return op | (pp << 8) | (mm << 10) | (rrr << 12) | (w << 15)
def OP0F(op, rrr=0, w=0):
# type: (int, int, int) -> int
return OP(op, pp=0, mm=1, rrr=rrr, w=w)
def MP66(op, rrr=0, w=0):
# type: (int, int, int) -> int
return OP(op, pp=1, mm=0, rrr=rrr, w=w)
# XX /r
Op1rr = EncRecipe('Op1rr', Binary, size=2, ins=(GPR, GPR), outs=0)
@@ -78,3 +88,78 @@ Op1rib = EncRecipe(
Op1rid = EncRecipe(
'Op1rid', BinaryImm, size=6, ins=GPR, outs=0,
instp=IsSignedInt(BinaryImm.imm, 32))
#
# Store recipes.
#
# XX /r register-indirect store with no offset.
Op1st = EncRecipe(
'Op1st', Store, size=2, ins=(GPR, GPR), outs=(),
instp=IsEqual(Store.offset, 0))
# XX /r register-indirect store with no offset.
# Only ABCD allowed for stored value. This is for byte stores.
Op1st_abcd = EncRecipe(
'Op1st_abcd', Store, size=2, ins=(ABCD, GPR), outs=(),
instp=IsEqual(Store.offset, 0))
# XX /r register-indirect store with 8-bit offset.
Op1stDisp8 = EncRecipe(
'Op1stDisp8', Store, size=3, ins=(GPR, GPR), outs=(),
instp=IsSignedInt(Store.offset, 8))
Op1stDisp8_abcd = EncRecipe(
'Op1stDisp8_abcd', Store, size=3, ins=(ABCD, GPR), outs=(),
instp=IsSignedInt(Store.offset, 8))
# XX /r register-indirect store with 32-bit offset.
Op1stDisp32 = EncRecipe('Op1stDisp32', Store, size=6, ins=(GPR, GPR), outs=())
Op1stDisp32_abcd = EncRecipe(
'Op1stDisp32_abcd', Store, size=6, ins=(ABCD, GPR), outs=())
# PP WW /r register-indirect store with no offset.
Mp1st = EncRecipe(
'Mp1st', Store, size=3, ins=(GPR, GPR), outs=(),
instp=IsEqual(Store.offset, 0))
# PP XX /r register-indirect store with 8-bit offset.
Mp1stDisp8 = EncRecipe(
'Mp1stDisp8', Store, size=4, ins=(GPR, GPR), outs=(),
instp=IsSignedInt(Store.offset, 8))
# PP XX /r register-indirect store with 32-bit offset.
Mp1stDisp32 = EncRecipe('Mp1stDisp32', Store, size=7, ins=(GPR, GPR), outs=())
#
# Load recipes
#
# XX /r load with no offset.
Op1ld = EncRecipe(
'Op1ld', Load, size=2, ins=(GPR), outs=(GPR),
instp=IsEqual(Load.offset, 0))
# XX /r load with 8-bit offset.
Op1ldDisp8 = EncRecipe(
'Op1ldDisp8', Load, size=3, ins=(GPR), outs=(GPR),
instp=IsSignedInt(Load.offset, 8))
# XX /r load with 32-bit offset.
Op1ldDisp32 = EncRecipe(
'Op1ldDisp32', Load, size=6, ins=(GPR), outs=(GPR),
instp=IsSignedInt(Load.offset, 32))
# 0F XX /r load with no offset.
Op2ld = EncRecipe(
'Op2ld', Load, size=3, ins=(GPR), outs=(GPR),
instp=IsEqual(Load.offset, 0))
# XX /r load with 8-bit offset.
Op2ldDisp8 = EncRecipe(
'Op2ldDisp8', Load, size=4, ins=(GPR), outs=(GPR),
instp=IsSignedInt(Load.offset, 8))
# XX /r load with 32-bit offset.
Op2ldDisp32 = EncRecipe(
'Op2ldDisp32', Load, size=7, ins=(GPR), outs=(GPR),
instp=IsSignedInt(Load.offset, 32))

View File

@@ -8,11 +8,30 @@ include!(concat!(env!("OUT_DIR"), "/binemit-intel.rs"));
pub static RELOC_NAMES: [&'static str; 1] = ["Call"];
// Emit single-byte opcode.
fn put_op1<CS: CodeSink + ?Sized>(bits: u16, sink: &mut CS) {
debug_assert!(bits & 0x0f00 == 0, "Invalid encoding bits for Op1*");
sink.put1(bits as u8);
}
// Emit two-byte opcode: 0F XX
fn put_op2<CS: CodeSink + ?Sized>(bits: u16, sink: &mut CS) {
debug_assert!(bits & 0x0f00 == 0x0400, "Invalid encoding bits for Op2*");
sink.put1(0x0f);
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.
fn put_mp1<CS: CodeSink + ?Sized>(bits: u16, sink: &mut CS) {
debug_assert!(bits & 0x0c00 == 0, "Invalid encoding bits for Mp1*");
let pp = (bits >> 8) & 3;
sink.put1(PREFIX[(pp - 1) as usize]);
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;
@@ -33,6 +52,42 @@ fn modrm_r_bits<CS: CodeSink + ?Sized>(rm: RegUnit, bits: u16, sink: &mut CS) {
sink.put1(b);
}
/// Emit a mode 00 ModR/M byte. This is a register-indirect addressing mode with no offset.
/// Registers %rsp and %rbp are invalid for `rm`, %rsp indicates a SIB byte, and %rbp indicates an
/// absolute immediate 32-bit address.
fn modrm_rm<CS: CodeSink + ?Sized>(rm: RegUnit, reg: RegUnit, sink: &mut CS) {
let reg = reg as u8 & 7;
let rm = rm as u8 & 7;
let mut b = 0b00000000;
b |= reg << 3;
b |= rm;
sink.put1(b);
}
/// Emit a mode 01 ModR/M byte. This is a register-indirect addressing mode with 8-bit
/// displacement.
/// Register %rsp is invalid for `rm`. It indicates the presence of a SIB byte.
fn modrm_disp8<CS: CodeSink + ?Sized>(rm: RegUnit, reg: RegUnit, sink: &mut CS) {
let reg = reg as u8 & 7;
let rm = rm as u8 & 7;
let mut b = 0b01000000;
b |= reg << 3;
b |= rm;
sink.put1(b);
}
/// Emit a mode 10 ModR/M byte. This is a register-indirect addressing mode with 32-bit
/// displacement.
/// Register %rsp is invalid for `rm`. It indicates the presence of a SIB byte.
fn modrm_disp32<CS: CodeSink + ?Sized>(rm: RegUnit, reg: RegUnit, sink: &mut CS) {
let reg = reg as u8 & 7;
let rm = rm as u8 & 7;
let mut b = 0b10000000;
b |= reg << 3;
b |= rm;
sink.put1(b);
}
fn recipe_op1rr<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
if let InstructionData::Binary { args, .. } = func.dfg[inst] {
put_op1(func.encodings[inst].bits(), sink);
@@ -77,3 +132,168 @@ fn recipe_op1rid<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut
panic!("Expected BinaryImm format: {:?}", func.dfg[inst]);
}
}
// Store recipes.
fn recipe_op1st<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
if let InstructionData::Store { args, .. } = func.dfg[inst] {
put_op1(func.encodings[inst].bits(), sink);
modrm_rm(func.locations[args[1]].unwrap_reg(),
func.locations[args[0]].unwrap_reg(),
sink);
} else {
panic!("Expected Store format: {:?}", func.dfg[inst]);
}
}
// This is just a tighter register class constraint.
fn recipe_op1st_abcd<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
recipe_op1st(func, inst, sink)
}
fn recipe_mp1st<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
if let InstructionData::Store { args, .. } = func.dfg[inst] {
put_mp1(func.encodings[inst].bits(), sink);
modrm_rm(func.locations[args[1]].unwrap_reg(),
func.locations[args[0]].unwrap_reg(),
sink);
} else {
panic!("Expected Store format: {:?}", func.dfg[inst]);
}
}
fn recipe_op1stdisp8<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
if let InstructionData::Store { args, offset, .. } = func.dfg[inst] {
put_op1(func.encodings[inst].bits(), sink);
modrm_disp8(func.locations[args[1]].unwrap_reg(),
func.locations[args[0]].unwrap_reg(),
sink);
let offset: i32 = offset.into();
sink.put1(offset as u8);
} else {
panic!("Expected Store format: {:?}", func.dfg[inst]);
}
}
fn recipe_op1stdisp8_abcd<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
recipe_op1stdisp8(func, inst, sink)
}
fn recipe_mp1stdisp8<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
if let InstructionData::Store { args, offset, .. } = func.dfg[inst] {
put_mp1(func.encodings[inst].bits(), sink);
modrm_disp8(func.locations[args[1]].unwrap_reg(),
func.locations[args[0]].unwrap_reg(),
sink);
let offset: i32 = offset.into();
sink.put1(offset as u8);
} else {
panic!("Expected Store format: {:?}", func.dfg[inst]);
}
}
fn recipe_op1stdisp32<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
if let InstructionData::Store { args, offset, .. } = func.dfg[inst] {
put_op1(func.encodings[inst].bits(), sink);
modrm_disp32(func.locations[args[1]].unwrap_reg(),
func.locations[args[0]].unwrap_reg(),
sink);
let offset: i32 = offset.into();
sink.put4(offset as u32);
} else {
panic!("Expected Store format: {:?}", func.dfg[inst]);
}
}
fn recipe_op1stdisp32_abcd<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
recipe_op1stdisp32(func, inst, sink)
}
fn recipe_mp1stdisp32<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
if let InstructionData::Store { args, offset, .. } = func.dfg[inst] {
put_mp1(func.encodings[inst].bits(), sink);
modrm_disp32(func.locations[args[1]].unwrap_reg(),
func.locations[args[0]].unwrap_reg(),
sink);
let offset: i32 = offset.into();
sink.put4(offset as u32);
} else {
panic!("Expected Store format: {:?}", func.dfg[inst]);
}
}
// Load recipes
fn recipe_op1ld<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
if let InstructionData::Load { arg, .. } = func.dfg[inst] {
put_op1(func.encodings[inst].bits(), sink);
modrm_rm(func.locations[arg].unwrap_reg(),
func.locations[func.dfg.first_result(inst)].unwrap_reg(),
sink);
} else {
panic!("Expected Load format: {:?}", func.dfg[inst]);
}
}
fn recipe_op1lddisp8<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
if let InstructionData::Load { arg, offset, .. } = func.dfg[inst] {
put_op1(func.encodings[inst].bits(), sink);
modrm_disp8(func.locations[arg].unwrap_reg(),
func.locations[func.dfg.first_result(inst)].unwrap_reg(),
sink);
let offset: i32 = offset.into();
sink.put1(offset as u8);
} else {
panic!("Expected Load format: {:?}", func.dfg[inst]);
}
}
fn recipe_op1lddisp32<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
if let InstructionData::Load { arg, offset, .. } = func.dfg[inst] {
put_op1(func.encodings[inst].bits(), sink);
modrm_disp32(func.locations[arg].unwrap_reg(),
func.locations[func.dfg.first_result(inst)].unwrap_reg(),
sink);
let offset: i32 = offset.into();
sink.put4(offset as u32);
} else {
panic!("Expected Load format: {:?}", func.dfg[inst]);
}
}
fn recipe_op2ld<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
if let InstructionData::Load { arg, .. } = func.dfg[inst] {
put_op2(func.encodings[inst].bits(), sink);
modrm_rm(func.locations[arg].unwrap_reg(),
func.locations[func.dfg.first_result(inst)].unwrap_reg(),
sink);
} else {
panic!("Expected Load format: {:?}", func.dfg[inst]);
}
}
fn recipe_op2lddisp8<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
if let InstructionData::Load { arg, offset, .. } = func.dfg[inst] {
put_op2(func.encodings[inst].bits(), sink);
modrm_disp8(func.locations[arg].unwrap_reg(),
func.locations[func.dfg.first_result(inst)].unwrap_reg(),
sink);
let offset: i32 = offset.into();
sink.put1(offset as u8);
} else {
panic!("Expected Load format: {:?}", func.dfg[inst]);
}
}
fn recipe_op2lddisp32<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
if let InstructionData::Load { arg, offset, .. } = func.dfg[inst] {
put_op2(func.encodings[inst].bits(), sink);
modrm_disp32(func.locations[arg].unwrap_reg(),
func.locations[func.dfg.first_result(inst)].unwrap_reg(),
sink);
let offset: i32 = offset.into();
sink.put4(offset as u32);
} else {
panic!("Expected Load format: {:?}", func.dfg[inst]);
}
}

View File

@@ -11,8 +11,8 @@
/// Check that `x` is the same as `y`.
#[allow(dead_code)]
pub fn is_equal<T: Eq + Copy>(x: T, y: T) -> bool {
x == y
pub fn is_equal<T: Eq + Copy, O: Into<T> + Copy>(x: T, y: O) -> bool {
x == y.into()
}
/// Check that `x` can be represented as a `wd`-bit signed integer with `sc` low zero bits.