Start adding Intel 64-bit encodings.

Add a TailRecipe.rex() method which creates an encoding recipe with a
REX prefix.

Define I64 encodings with REX.W for i64 operations and with/without REX
for i32 ops. Only test the with-REX encodings for now. We don't yet have
an instruction shrinking pass that can select the non-REX encodings.
This commit is contained in:
Jakob Stoklund Olesen
2017-07-10 16:16:22 -07:00
parent fb227cb389
commit a4a8c83aab
4 changed files with 365 additions and 18 deletions

View File

@@ -2,30 +2,65 @@
Intel Encodings.
"""
from __future__ import absolute_import
from cdsl.predicates import IsUnsignedInt
from base import instructions as base
from .defs import I32
from base.formats import UnaryImm
from .defs import I32, I64
from . import recipes as r
I32.enc(base.iadd.i32, *r.rr(0x01))
I32.enc(base.isub.i32, *r.rr(0x29))
for inst, opc in [
(base.iadd, 0x01),
(base.isub, 0x29),
(base.band, 0x21),
(base.bor, 0x09),
(base.bxor, 0x31)]:
I32.enc(inst.i32, *r.rr(opc))
I32.enc(base.band.i32, *r.rr(0x21))
I32.enc(base.bor.i32, *r.rr(0x09))
I32.enc(base.bxor.i32, *r.rr(0x31))
I64.enc(inst.i64, *r.rr.rex(opc, w=1))
I64.enc(inst.i32, *r.rr.rex(opc))
# 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, *r.rr(opc))
I32.enc(base.copy.i32, *r.ur(0x89))
# Immediate instructions with sign-extended 8-bit and 32-bit immediate.
for inst, rrr in [
(base.iadd_imm.i32, 0),
(base.band_imm.i32, 4),
(base.bor_imm.i32, 1),
(base.bxor_imm.i32, 6)]:
I32.enc(inst, *r.rib(0x83, rrr=rrr))
I32.enc(inst, *r.rid(0x81, rrr=rrr))
I64.enc(base.copy.i64, *r.ur.rex(0x89, w=1))
I64.enc(base.copy.i32, *r.ur.rex(0x89))
I64.enc(base.copy.i32, *r.ur(0x89))
# Immediate constant.
I32.enc(base.iconst.i32, *r.uid(0xb8))
# Immediate instructions with sign-extended 8-bit and 32-bit immediate.
for inst, rrr in [
(base.iadd_imm, 0),
(base.band_imm, 4),
(base.bor_imm, 1),
(base.bxor_imm, 6)]:
I32.enc(inst.i32, *r.rib(0x83, rrr=rrr))
I32.enc(inst.i32, *r.rid(0x81, rrr=rrr))
I64.enc(inst.i64, *r.rib.rex(0x83, rrr=rrr, w=1))
I64.enc(inst.i64, *r.rid.rex(0x81, rrr=rrr, w=1))
I64.enc(inst.i32, *r.rib.rex(0x83, rrr=rrr))
I64.enc(inst.i32, *r.rid.rex(0x81, rrr=rrr))
I64.enc(inst.i32, *r.rib(0x83, rrr=rrr))
I64.enc(inst.i32, *r.rid(0x81, rrr=rrr))
# TODO: band_imm.i64 with an unsigned 32-bit immediate can be encoded as
# band_imm.i32. Can even use the single-byte immediate for 0xffff_ffXX masks.
# Immediate constants.
I32.enc(base.iconst.i32, *r.puid(0xb8))
I64.enc(base.iconst.i32, *r.puid.rex(0xb8))
I64.enc(base.iconst.i32, *r.puid(0xb8))
# The 32-bit immediate movl also zero-extends to 64 bits.
I64.enc(base.iconst.i64, *r.puid.rex(0xb8),
instp=IsUnsignedInt(UnaryImm.imm, 32))
I64.enc(base.iconst.i64, *r.puid(0xb8),
instp=IsUnsignedInt(UnaryImm.imm, 32))
# Sign-extended 32-bit immediate.
I64.enc(base.iconst.i64, *r.uid.rex(0xc7, rrr=0, w=1))
# Finally, the 0xb8 opcode takes an 8-byte immediate with a REX.W prefix.
I64.enc(base.iconst.i64, *r.puiq.rex(0xb8, w=1))
# 32-bit shifts and rotates.
# Note that the dynamic shift amount is only masked by 5 or 6 bits; the 8-bit
@@ -73,3 +108,4 @@ I32.enc(base.sload8.i32.i32, *r.ldDisp32(0x0f, 0xbe))
I32.enc(base.call, *r.call_id(0xe8))
I32.enc(base.call_indirect.i32, *r.call_r(0xff, rrr=2))
I32.enc(base.x_return, *r.ret(0xc3))
I64.enc(base.x_return, *r.ret(0xc3))