Adapt intel to be able to correctly choose compressed instruction encodings: create a register class to identify the lower 8 registers, omit unnecessary REX prefixes, and fix the tests

This commit is contained in:
Angus Holder
2017-09-22 00:49:21 +01:00
committed by Jakob Stoklund Olesen
parent 3b66c0be40
commit b003605132
5 changed files with 136 additions and 109 deletions

View File

@@ -15,7 +15,7 @@ runif() {
runif flake8 .
# Type checking.
runif mypy --py2 build.py
runif python3 -m mypy --py2 build.py
# Python unit tests.
runif python -m unittest discover

View File

@@ -91,6 +91,12 @@ def enc_flt(inst, recipe, *args, **kwargs):
I64.enc(inst, *recipe(*args, **kwargs))
def enc_i64(inst, recipe, *args, **kwargs):
# type: (MaybeBoundInst, r.TailRecipe, *int, **int) -> None
I64.enc(inst, *recipe.rex(*args, **kwargs))
I64.enc(inst, *recipe(*args, **kwargs))
for inst, opc in [
(base.iadd, 0x01),
(base.isub, 0x29),
@@ -175,9 +181,9 @@ 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)
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_i64(base.istore32.i64.any, r.st, 0x89)
enc_i64(base.istore32.i64.any, r.stDisp8, 0x89)
enc_i64(base.istore32.i64.any, r.stDisp32, 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)
@@ -187,21 +193,24 @@ enc_i32_i64_ld_st(base.istore16, False, r.stDisp32, 0x66, 0x89)
# 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_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_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_abcd(0x88))
I64.enc(base.istore8.i64.any, *r.stDisp32.rex(0x88))
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)
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))
enc_i64(base.uload32.i64, r.ld, 0x8b)
enc_i64(base.uload32.i64, r.ldDisp8, 0x8b)
enc_i64(base.uload32.i64, r.ldDisp32, 0x8b)
I64.enc(base.sload32.i64, *r.ld.rex(0x63, w=1))
I64.enc(base.sload32.i64, *r.ldDisp8.rex(0x63, w=1))
@@ -301,7 +310,7 @@ enc_i32_i64(base.icmp, r.icscc, 0x39)
# This assumes that b1 is represented as an 8-bit low register with the value 0
# or 1.
I32.enc(base.bint.i32.b1, *r.urm_abcd(0x0f, 0xb6))
I64.enc(base.bint.i64.b1, *r.urm.rex(0x0f, 0xb6, w=1))
I64.enc(base.bint.i64.b1, *r.urm.rex(0x0f, 0xb6)) # zext to i64 implicit.
I64.enc(base.bint.i64.b1, *r.urm_abcd(0x0f, 0xb6)) # zext to i64 implicit.
I64.enc(base.bint.i32.b1, *r.urm.rex(0x0f, 0xb6))
I64.enc(base.bint.i32.b1, *r.urm_abcd(0x0f, 0xb6))

View File

@@ -8,10 +8,10 @@ from base.formats import Unary, UnaryImm, Binary, BinaryImm, MultiAry
from base.formats import Trap, Call, IndirectCall, Store, Load
from base.formats import IntCompare
from base.formats import RegMove, Ternary, Jump, Branch, FuncAddr
from .registers import GPR, ABCD, FPR
from .registers import GPR, ABCD, FPR, GPR8, FPR8
try:
from typing import Tuple, Dict # noqa
from typing import Tuple, Dict, Sequence # noqa
from cdsl.instructions import InstructionFormat # noqa
from cdsl.isa import ConstraintSeq, BranchRange, PredNode, OperandConstraint # noqa
except ImportError:
@@ -95,6 +95,15 @@ def replace_put_op(emit, prefix):
return emit.replace('PUT_OP', 'put_' + prefix.lower())
def map_regs(
regs, # type: Sequence[OperandConstraint]
from_class, # type: OperandConstraint
to_class # type: OperandConstraint
):
# type: (...) -> Sequence[OperandConstraint]
return tuple(to_class if (reg is from_class) else reg for reg in regs)
class TailRecipe:
"""
Generate encoding recipes on demand.
@@ -150,7 +159,7 @@ class TailRecipe:
w = kwargs.get('w', 0)
name, bits = decode_ops(ops, rrr, w)
if name not in self.recipes:
self.recipes[name] = EncRecipe(
recipe = EncRecipe(
name + self.name,
self.format,
len(ops) + self.size,
@@ -160,6 +169,13 @@ class TailRecipe:
instp=self.instp,
isap=self.isap,
emit=replace_put_op(self.emit, name))
recipe.ins = map_regs(recipe.ins, GPR, GPR8)
recipe.ins = map_regs(recipe.ins, FPR, FPR8)
recipe.outs = map_regs(recipe.outs, GPR, GPR8)
recipe.outs = map_regs(recipe.outs, FPR, FPR8)
self.recipes[name] = recipe
return (self.recipes[name], bits)
def rex(self, *ops, **kwargs):

View File

@@ -39,7 +39,9 @@ FloatRegs = RegBank(
units=16, prefix='xmm')
GPR = RegClass(IntRegs)
GPR8 = GPR[0:8]
ABCD = GPR[0:4]
FPR = RegClass(FloatRegs)
FPR8 = FPR[0:8]
RegClass.extract_names(globals())