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:
@@ -92,5 +92,110 @@ ebb0:
|
|||||||
; asm: xorl $1000000, %esi
|
; asm: xorl $1000000, %esi
|
||||||
[-,%rsi] v47 = bxor_imm v2, 1000000 ; bin: 81 f6 000f4240
|
[-,%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
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ Intel Encodings.
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from base import instructions as base
|
from base import instructions as base
|
||||||
from .defs import I32
|
from .defs import I32
|
||||||
from .recipes import Op1rr, Op1rc, Op1rib, Op1rid
|
from . import recipes as rcp
|
||||||
from .recipes import OP
|
from .recipes import OP, OP0F, MP66
|
||||||
|
|
||||||
I32.enc(base.iadd.i32, Op1rr, OP(0x01))
|
I32.enc(base.iadd.i32, rcp.Op1rr, OP(0x01))
|
||||||
I32.enc(base.isub.i32, Op1rr, OP(0x29))
|
I32.enc(base.isub.i32, rcp.Op1rr, OP(0x29))
|
||||||
|
|
||||||
I32.enc(base.band.i32, Op1rr, OP(0x21))
|
I32.enc(base.band.i32, rcp.Op1rr, OP(0x21))
|
||||||
I32.enc(base.bor.i32, Op1rr, OP(0x09))
|
I32.enc(base.bor.i32, rcp.Op1rr, OP(0x09))
|
||||||
I32.enc(base.bxor.i32, Op1rr, OP(0x31))
|
I32.enc(base.bxor.i32, rcp.Op1rr, OP(0x31))
|
||||||
|
|
||||||
# Immediate instructions with sign-extended 8-bit and 32-bit immediate.
|
# Immediate instructions with sign-extended 8-bit and 32-bit immediate.
|
||||||
for inst, r in [
|
for inst, r in [
|
||||||
@@ -20,12 +20,45 @@ for inst, r in [
|
|||||||
(base.band_imm.i32, 4),
|
(base.band_imm.i32, 4),
|
||||||
(base.bor_imm.i32, 1),
|
(base.bor_imm.i32, 1),
|
||||||
(base.bxor_imm.i32, 6)]:
|
(base.bxor_imm.i32, 6)]:
|
||||||
I32.enc(inst, Op1rib, OP(0x83, rrr=r))
|
I32.enc(inst, rcp.Op1rib, OP(0x83, rrr=r))
|
||||||
I32.enc(inst, Op1rid, OP(0x81, rrr=r))
|
I32.enc(inst, rcp.Op1rid, OP(0x81, rrr=r))
|
||||||
|
|
||||||
# 32-bit shifts and rotates.
|
# 32-bit shifts and rotates.
|
||||||
# Note that the dynamic shift amount is only masked by 5 or 6 bits; the 8-bit
|
# 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.
|
# and 16-bit shifts would need explicit masking.
|
||||||
I32.enc(base.ishl.i32.i32, Op1rc, OP(0xd3, rrr=4))
|
I32.enc(base.ishl.i32.i32, rcp.Op1rc, OP(0xd3, rrr=4))
|
||||||
I32.enc(base.ushr.i32.i32, Op1rc, OP(0xd3, rrr=5))
|
I32.enc(base.ushr.i32.i32, rcp.Op1rc, OP(0xd3, rrr=5))
|
||||||
I32.enc(base.sshr.i32.i32, Op1rc, OP(0xd3, rrr=7))
|
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))
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ Intel Encoding recipes.
|
|||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from cdsl.isa import EncRecipe
|
from cdsl.isa import EncRecipe
|
||||||
from cdsl.predicates import IsSignedInt
|
from cdsl.predicates import IsSignedInt, IsEqual
|
||||||
from base.formats import Binary, BinaryImm
|
from base.formats import Binary, BinaryImm, Store, Load
|
||||||
from .registers import GPR
|
from .registers import GPR, ABCD
|
||||||
|
|
||||||
# Opcode representation.
|
# Opcode representation.
|
||||||
#
|
#
|
||||||
@@ -15,21 +15,21 @@ from .registers import GPR
|
|||||||
# name prefix:
|
# name prefix:
|
||||||
#
|
#
|
||||||
# <op> Op1* OP(op)
|
# <op> Op1* OP(op)
|
||||||
# 0F <op> Op2* OP(op)
|
# 0F <op> Op2* OP0F(op)
|
||||||
# 0F 38 <op> Op3* OP38(op)
|
# 0F 38 <op> Op3* OP38(op)
|
||||||
# 0F 3A <op> Op3* OP3A(op)
|
# 0F 3A <op> Op3* OP3A(op)
|
||||||
# 66 <op> Mp1* MP66(op)
|
# 66 <op> Mp1* MP66(op)
|
||||||
# 66 0F <op> Mp2* MP66(op)
|
# 66 0F <op> Mp2* MP660F(op)
|
||||||
# 66 0F 38 <op> Mp3* MP6638(op)
|
# 66 0F 38 <op> Mp3* MP660F38(op)
|
||||||
# 66 0F 3A <op> Mp3* MP663A(op)
|
# 66 0F 3A <op> Mp3* MP660F3A(op)
|
||||||
# F2 <op> Mp1* MPF2(op)
|
# F2 <op> Mp1* MPF2(op)
|
||||||
# F2 0F <op> Mp2* MPF2(op)
|
# F2 0F <op> Mp2* MPF20F(op)
|
||||||
# F2 0F 38 <op> Mp3* MPF238(op)
|
# F2 0F 38 <op> Mp3* MPF20F38(op)
|
||||||
# F2 0F 3A <op> Mp3* MPF23A(op)
|
# F2 0F 3A <op> Mp3* MPF20F3A(op)
|
||||||
# F3 <op> Mp1* MPF3(op)
|
# F3 <op> Mp1* MPF3(op)
|
||||||
# F3 0F <op> Mp2* MPF3(op)
|
# F3 0F <op> Mp2* MP0FF3(op)
|
||||||
# F3 0F 38 <op> Mp3* MPF338(op)
|
# F3 0F 38 <op> Mp3* MPF30F38(op)
|
||||||
# F3 0F 3A <op> Mp3* MPF33A(op)
|
# F3 0F 3A <op> Mp3* MPF30F3A(op)
|
||||||
#
|
#
|
||||||
# VEX/XOP and EVEX prefixes are not yet supported.
|
# 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)
|
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
|
# XX /r
|
||||||
Op1rr = EncRecipe('Op1rr', Binary, size=2, ins=(GPR, GPR), outs=0)
|
Op1rr = EncRecipe('Op1rr', Binary, size=2, ins=(GPR, GPR), outs=0)
|
||||||
|
|
||||||
@@ -78,3 +88,78 @@ Op1rib = EncRecipe(
|
|||||||
Op1rid = EncRecipe(
|
Op1rid = EncRecipe(
|
||||||
'Op1rid', BinaryImm, size=6, ins=GPR, outs=0,
|
'Op1rid', BinaryImm, size=6, ins=GPR, outs=0,
|
||||||
instp=IsSignedInt(BinaryImm.imm, 32))
|
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))
|
||||||
|
|||||||
@@ -8,11 +8,30 @@ include!(concat!(env!("OUT_DIR"), "/binemit-intel.rs"));
|
|||||||
|
|
||||||
pub static RELOC_NAMES: [&'static str; 1] = ["Call"];
|
pub static RELOC_NAMES: [&'static str; 1] = ["Call"];
|
||||||
|
|
||||||
|
// Emit single-byte opcode.
|
||||||
fn put_op1<CS: CodeSink + ?Sized>(bits: u16, sink: &mut CS) {
|
fn put_op1<CS: CodeSink + ?Sized>(bits: u16, sink: &mut CS) {
|
||||||
debug_assert!(bits & 0x0f00 == 0, "Invalid encoding bits for Op1*");
|
debug_assert!(bits & 0x0f00 == 0, "Invalid encoding bits for Op1*");
|
||||||
sink.put1(bits as u8);
|
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.
|
/// Emit a ModR/M byte for reg-reg operands.
|
||||||
fn modrm_rr<CS: CodeSink + ?Sized>(rm: RegUnit, reg: RegUnit, sink: &mut CS) {
|
fn modrm_rr<CS: CodeSink + ?Sized>(rm: RegUnit, reg: RegUnit, sink: &mut CS) {
|
||||||
let reg = reg as u8 & 7;
|
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);
|
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) {
|
fn recipe_op1rr<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
|
||||||
if let InstructionData::Binary { args, .. } = func.dfg[inst] {
|
if let InstructionData::Binary { args, .. } = func.dfg[inst] {
|
||||||
put_op1(func.encodings[inst].bits(), sink);
|
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]);
|
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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
|
|
||||||
/// Check that `x` is the same as `y`.
|
/// Check that `x` is the same as `y`.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn is_equal<T: Eq + Copy>(x: T, y: T) -> bool {
|
pub fn is_equal<T: Eq + Copy, O: Into<T> + Copy>(x: T, y: O) -> bool {
|
||||||
x == y
|
x == y.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check that `x` can be represented as a `wd`-bit signed integer with `sc` low zero bits.
|
/// Check that `x` can be represented as a `wd`-bit signed integer with `sc` low zero bits.
|
||||||
|
|||||||
Reference in New Issue
Block a user