Add encoding size information to EncInfo.

Two new pieces of information are available for all encoding recipes:

- The size in bytes of an encoded instruction, and
- The range of a branch encoded with the recipe, if any.

In the meta language, EncRecipe takes two new constructor arguments. The
size is required for all encodings and branch_range is required for all
recipes used to encode branches.
This commit is contained in:
Jakob Stoklund Olesen
2017-04-05 11:04:17 -07:00
parent f47c62ba8c
commit 598c81c12e
10 changed files with 169 additions and 14 deletions

View File

@@ -19,6 +19,7 @@ try:
# Instruction specification for encodings. Allows for predicated
# instructions.
InstSpec = Union[MaybeBoundInst, Apply]
BranchRange = Sequence[int]
except ImportError:
pass
@@ -164,17 +165,38 @@ class EncRecipe(object):
- An integer indicating that this result is tied to a value operand, so
they must use the same register.
The `branch_range` argument must be provided for recipes that can encode
branch instructions. It is an `(origin, bits)` tuple describing the exact
range that can be encoded in a branch instruction.
:param name: Short mnemonic name for this recipe.
:param format: All encoded instructions must have this
:py:class:`InstructionFormat`.
:param size: Number of bytes in the binary encoded instruction.
:param: ins Tuple of register constraints for value operands.
:param: outs Tuple of register constraints for results.
:param: branch_range `(origin, bits)` range for branches.
:param: instp Instruction predicate.
:param: isap ISA predicate.
"""
def __init__(self, name, format, ins, outs, instp=None, isap=None):
# type: (str, InstructionFormat, ConstraintSeq, ConstraintSeq, PredNode, PredNode) -> None # noqa
def __init__(
self,
name, # type: str
format, # type: InstructionFormat
size, # type: int
ins, # type: ConstraintSeq
outs, # type: ConstraintSeq
branch_range=None, # type: BranchRange
instp=None, # type: PredNode
isap=None # type: PredNode
):
# type: (...) -> None
self.name = name
self.format = format
assert size >= 0
self.size = size
self.branch_range = branch_range
self.instp = instp
self.isap = isap
if instp:
@@ -249,6 +271,12 @@ class Encoding(object):
assert self.inst.format == recipe.format, (
"Format {} must match recipe: {}".format(
self.inst.format, recipe.format))
if self.inst.is_branch:
assert recipe.branch_range, (
'Recipe {} for {} must have a branch_range'
.format(recipe, self.inst.name))
self.recipe = recipe
self.encbits = encbits
# Combine recipe predicates with the manually specified ones.

View File

@@ -498,6 +498,27 @@ def emit_operand_constraints(seq, field, fmt):
'Unsupported constraint {}'.format(cons))
def emit_recipe_sizing(isa, fmt):
# type: (TargetISA, srcgen.Formatter) -> None
"""
Emit a table of encoding recipe code size information.
"""
with fmt.indented(
'static RECIPE_SIZING: [RecipeSizing; {}] = ['
.format(len(isa.all_recipes)), '];'):
for r in isa.all_recipes:
fmt.comment(r.name)
with fmt.indented('RecipeSizing {', '},'):
fmt.format('bytes: {},', r.size)
if r.branch_range:
fmt.format(
'branch_range: '
'Some(BranchRange {{ origin: {}, bits: {} }}),',
*r.branch_range)
else:
fmt.line('branch_range: None,')
def gen_isa(isa, fmt):
# type: (TargetISA, srcgen.Formatter) -> None
# First assign numbers to relevant instruction predicates and generate the
@@ -535,10 +556,12 @@ def gen_isa(isa, fmt):
emit_recipe_names(isa, fmt)
emit_recipe_constraints(isa, fmt)
emit_recipe_sizing(isa, fmt)
# Finally, tie it all together in an `EncInfo`.
with fmt.indented('pub static INFO: EncInfo = EncInfo {', '};'):
fmt.line('constraints: &RECIPE_CONSTRAINTS,')
fmt.line('sizing: &RECIPE_SIZING,')
fmt.line('names: &RECIPE_NAMES,')

View File

@@ -85,37 +85,43 @@ def LUI():
# R-type 32-bit instructions: These are mostly binary arithmetic instructions.
# The encbits are `opcode[6:2] | (funct3 << 5) | (funct7 << 8)
R = EncRecipe('R', Binary, ins=(GPR, GPR), outs=GPR)
R = EncRecipe('R', Binary, size=4, ins=(GPR, GPR), outs=GPR)
# R-type with an immediate shift amount instead of rs2.
Rshamt = EncRecipe('Rshamt', BinaryImm, ins=GPR, outs=GPR)
Rshamt = EncRecipe('Rshamt', BinaryImm, size=4, ins=GPR, outs=GPR)
# R-type encoding of an integer comparison.
Ricmp = EncRecipe('Ricmp', IntCompare, ins=(GPR, GPR), outs=GPR)
Ricmp = EncRecipe('Ricmp', IntCompare, size=4, ins=(GPR, GPR), outs=GPR)
I = EncRecipe(
'I', BinaryImm, ins=GPR, outs=GPR,
'I', BinaryImm, size=4, ins=GPR, outs=GPR,
instp=IsSignedInt(BinaryImm.imm, 12))
# I-type encoding of an integer comparison.
Iicmp = EncRecipe(
'Iicmp', IntCompareImm, ins=GPR, outs=GPR,
'Iicmp', IntCompareImm, size=4, ins=GPR, outs=GPR,
instp=IsSignedInt(IntCompareImm.imm, 12))
# I-type encoding for `jalr` as a return instruction. We won't use the
# immediate offset.
# The variable return values are not encoded.
Iret = EncRecipe('Iret', MultiAry, ins=GPR, outs=())
Iret = EncRecipe('Iret', MultiAry, size=4, ins=GPR, outs=())
# U-type instructions have a 20-bit immediate that targets bits 12-31.
U = EncRecipe(
'U', UnaryImm, ins=(), outs=GPR,
'U', UnaryImm, size=4, ins=(), outs=GPR,
instp=IsSignedInt(UnaryImm.imm, 32, 12))
# SB-type branch instructions.
# TODO: These instructions have a +/- 4 KB branch range. How to encode that
# constraint?
SB = EncRecipe('SB', BranchIcmp, ins=(GPR, GPR), outs=())
SB = EncRecipe(
'SB', BranchIcmp, size=4,
ins=(GPR, GPR), outs=(),
branch_range=(0, 13))
# SB-type branch instruction with rs2 fixed to zero.
SBzero = EncRecipe('SBzero', Branch, ins=(GPR), outs=())
SBzero = EncRecipe(
'SBzero', Branch, size=4,
ins=(GPR), outs=(),
branch_range=(0, 13))