Use a more compact encoding list representation.
Encodings has a 16-bit "recipe" field, but even Intel only has 57 recipes currently, so it is unlikely that we will ever need to full range. Use this to represent encoding lists more compactly. Change the encoding list to a format that: - Doesn't need a predicate entry before every encoding entry. - Doesn't need a terminator after the list for each instruction. - Supports multiple "stop codes" for configurable guidance of the legalizer. The encoding scheme has these limits: - 2*NR + NS <= 0x1000 - INSTP + ISAP <= 0x1000 Where: - NR is the number of recipes in an ISA, - NS is the number of stop codes (legalization actions). - INSTP is the number of instruction predicates. - ISAP is the number of discrete ISA predicates.
This commit is contained in:
@@ -39,13 +39,13 @@ types, so many of the level 2 tables will be cold.
|
|||||||
An encoding list is a non-empty sequence of list entries. Each entry has
|
An encoding list is a non-empty sequence of list entries. Each entry has
|
||||||
one of these forms:
|
one of these forms:
|
||||||
|
|
||||||
1. Instruction predicate, encoding recipe, and encoding bits. If the
|
1. Recipe + bits. Use this encoding if the recipe predicate is satisfied.
|
||||||
instruction predicate is true, use this recipe and bits.
|
2. Recipe + bits, final entry. Use this encoding if the recipe predicate is
|
||||||
2. ISA predicate and skip-count. If the ISA predicate is false, skip the next
|
satisfied. Otherwise, stop with the default legalization code.
|
||||||
*skip-count* entries in the list. If the skip count is zero, stop
|
3. Stop with legalization code.
|
||||||
completely.
|
4. Predicate + skip count. Test predicate and skip N entries if it is false.
|
||||||
3. Stop. End of list marker. If this is reached, the instruction does not have
|
4. Predicate + stop. Test predicate and stop with the default legalization code
|
||||||
a legal encoding.
|
if it is false.
|
||||||
|
|
||||||
The instruction predicate is also used to distinguish between polymorphic
|
The instruction predicate is also used to distinguish between polymorphic
|
||||||
instructions with different types for secondary type variables.
|
instructions with different types for secondary type variables.
|
||||||
@@ -56,9 +56,10 @@ from constant_hash import compute_quadratic
|
|||||||
from unique_table import UniqueSeqTable
|
from unique_table import UniqueSeqTable
|
||||||
from collections import OrderedDict, defaultdict
|
from collections import OrderedDict, defaultdict
|
||||||
import math
|
import math
|
||||||
import itertools
|
from itertools import groupby
|
||||||
from cdsl.registers import RegClass, Register, Stack
|
from cdsl.registers import RegClass, Register, Stack
|
||||||
from cdsl.predicates import FieldPredicate
|
from cdsl.predicates import FieldPredicate
|
||||||
|
from cdsl.settings import SettingGroup
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from typing import Sequence, Set, Tuple, List, Dict, Iterable, DefaultDict, TYPE_CHECKING # noqa
|
from typing import Sequence, Set, Tuple, List, Dict, Iterable, DefaultDict, TYPE_CHECKING # noqa
|
||||||
@@ -173,42 +174,228 @@ def emit_recipe_predicates(recipes, fmt):
|
|||||||
fmt.format('Some({}),', pname[p])
|
fmt.format('Some({}),', pname[p])
|
||||||
|
|
||||||
|
|
||||||
# Encoding lists are represented as u16 arrays.
|
# The u16 values in an encoding list entry are interpreted as follows:
|
||||||
CODE_BITS = 16
|
|
||||||
PRED_BITS = 12
|
|
||||||
PRED_MASK = (1 << PRED_BITS) - 1
|
|
||||||
|
|
||||||
# 0..CODE_ALWAYS means: Check instruction predicate and use the next two
|
|
||||||
# entries as a (recipe, encbits) pair if true. CODE_ALWAYS is the always-true
|
|
||||||
# predicate, smaller numbers refer to instruction predicates.
|
|
||||||
CODE_ALWAYS = PRED_MASK
|
|
||||||
|
|
||||||
# Codes above CODE_ALWAYS indicate an ISA predicate to be tested.
|
|
||||||
# `x & PRED_MASK` is the ISA predicate number to test.
|
|
||||||
# `(x >> PRED_BITS)*3` is the number of u16 table entries to skip if the ISA
|
|
||||||
# predicate is false. (The factor of three corresponds to the (inst-pred,
|
|
||||||
# recipe, encbits) triples.
|
|
||||||
#
|
#
|
||||||
# Finally, CODE_FAIL indicates the end of the list.
|
# NR = len(all_recipes)
|
||||||
CODE_FAIL = (1 << CODE_BITS) - 1
|
#
|
||||||
|
# entry < 2*NR
|
||||||
|
# Try Encoding(entry/2, next_entry) if the recipe predicate is satisfied.
|
||||||
|
# If bit 0 is set, stop with the default legalization code.
|
||||||
|
# If bit 0 is clear, keep going down the list.
|
||||||
|
# entry < PRED_START
|
||||||
|
# Stop with legalization code `entry - 2*NR`.
|
||||||
|
#
|
||||||
|
# Remaining entries are interpreted as (skip, pred) pairs, where:
|
||||||
|
#
|
||||||
|
# skip = (entry - PRED_START) >> PRED_BITS
|
||||||
|
# pred = (entry - PRED_START) & PRED_MASK
|
||||||
|
#
|
||||||
|
# If the predicate is satisfied, keep going. Otherwise skip over the next
|
||||||
|
# `skip` entries. If skip == 0, stop with the default legalization code.
|
||||||
|
#
|
||||||
|
# The `pred` predicate number is interpreted as an instruction predicate if it
|
||||||
|
# is in range, otherwise an ISA predicate.
|
||||||
|
|
||||||
|
|
||||||
def seq_doc(enc):
|
class Encoder:
|
||||||
# type: (Encoding) -> Tuple[Tuple[int, int, int], str]
|
|
||||||
"""
|
"""
|
||||||
Return a tuple containing u16 representations of the instruction predicate
|
Encoder for the list format above.
|
||||||
an recipe / encbits.
|
|
||||||
|
|
||||||
Also return a doc string.
|
Two parameters are needed:
|
||||||
|
|
||||||
|
:param NR: Number of recipes.
|
||||||
|
:param NI: Number of instruction predicates.
|
||||||
"""
|
"""
|
||||||
if enc.instp:
|
|
||||||
p = enc.instp.number
|
def __init__(self, isa):
|
||||||
doc = '--> {} when {}'.format(enc, enc.instp)
|
# type: (TargetISA) -> None
|
||||||
else:
|
self.isa = isa
|
||||||
p = CODE_ALWAYS
|
self.NR = len(isa.all_recipes)
|
||||||
|
self.NI = len(isa.all_instps)
|
||||||
|
# u16 encoding list words.
|
||||||
|
self.words = list() # type: List[int]
|
||||||
|
# Documentation comments: Index into `words` + comment.
|
||||||
|
self.docs = list() # type: List[Tuple[int, str]]
|
||||||
|
|
||||||
|
# Encoding lists are represented as u16 arrays.
|
||||||
|
CODE_BITS = 16
|
||||||
|
|
||||||
|
# Beginning of the predicate code words.
|
||||||
|
PRED_START = 0x1000
|
||||||
|
|
||||||
|
# Number of bits used to hold a predicate number (instruction + ISA
|
||||||
|
# predicates.
|
||||||
|
PRED_BITS = 12
|
||||||
|
|
||||||
|
# Mask for extracting the predicate number.
|
||||||
|
PRED_MASK = (1 << PRED_BITS) - 1
|
||||||
|
|
||||||
|
def max_skip(self):
|
||||||
|
# type: () -> int
|
||||||
|
"""The maximum number of entries that a predicate can skip."""
|
||||||
|
return (1 << (self.CODE_BITS - self.PRED_BITS)) - 1
|
||||||
|
|
||||||
|
def recipe(self, enc, final):
|
||||||
|
# type: (Encoding, bool) -> None
|
||||||
|
"""Add a recipe+bits entry to the list."""
|
||||||
|
offset = len(self.words)
|
||||||
|
code = 2 * enc.recipe.number
|
||||||
doc = '--> {}'.format(enc)
|
doc = '--> {}'.format(enc)
|
||||||
assert p <= CODE_ALWAYS
|
if final:
|
||||||
return ((p, enc.recipe.number, enc.encbits), doc)
|
code += 1
|
||||||
|
doc += ' and stop'
|
||||||
|
|
||||||
|
assert(code < self.PRED_START)
|
||||||
|
self.words.extend((code, enc.encbits))
|
||||||
|
self.docs.append((offset, doc))
|
||||||
|
|
||||||
|
def _pred(self, pred, skip, n):
|
||||||
|
# type: (PredNode, int, int) -> None
|
||||||
|
"""Add a predicate entry."""
|
||||||
|
assert n <= self.PRED_MASK
|
||||||
|
code = n | (skip << self.PRED_BITS)
|
||||||
|
code += self.PRED_START
|
||||||
|
assert code < (1 << self.CODE_BITS)
|
||||||
|
|
||||||
|
if skip == 0:
|
||||||
|
doc = 'stop'
|
||||||
|
else:
|
||||||
|
doc = 'skip ' + str(skip)
|
||||||
|
doc = '{} unless {}'.format(doc, pred)
|
||||||
|
|
||||||
|
self.docs.append((len(self.words), doc))
|
||||||
|
self.words.append(code)
|
||||||
|
|
||||||
|
def instp(self, pred, skip):
|
||||||
|
# type: (PredNode, int) -> None
|
||||||
|
"""Add an instruction predicate entry."""
|
||||||
|
self._pred(pred, skip, pred.number)
|
||||||
|
|
||||||
|
def isap(self, pred, skip):
|
||||||
|
# type: (PredNode, int) -> None
|
||||||
|
"""Add an ISA predicate entry."""
|
||||||
|
n = self.isa.settings.predicate_number[pred]
|
||||||
|
# ISA predicates follow the instruction predicates.
|
||||||
|
self._pred(pred, skip, self.NI + n)
|
||||||
|
|
||||||
|
|
||||||
|
class EncNode(object):
|
||||||
|
"""
|
||||||
|
An abstract node in the encoder tree for an instruction.
|
||||||
|
|
||||||
|
This tree is used to simplify the predicates guarding recipe+bits entries.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def size(self):
|
||||||
|
# type: () -> int
|
||||||
|
"""Get the number of list entries needed to encode this tree."""
|
||||||
|
raise NotImplementedError('EncNode.size() is abstract')
|
||||||
|
|
||||||
|
def encode(self, encoder, final):
|
||||||
|
# type: (Encoder, bool) -> None
|
||||||
|
"""Encode this tree."""
|
||||||
|
raise NotImplementedError('EncNode.encode() is abstract')
|
||||||
|
|
||||||
|
def optimize(self):
|
||||||
|
# type: () -> EncNode
|
||||||
|
"""Transform this encoder tree into something simpler."""
|
||||||
|
return self
|
||||||
|
|
||||||
|
def predicate(self):
|
||||||
|
# type: () -> PredNode
|
||||||
|
"""Get the predicate guarding this tree, or `None` for always"""
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class EncPred(EncNode):
|
||||||
|
"""
|
||||||
|
An encoder tree node which asserts a predicate on its child nodes.
|
||||||
|
|
||||||
|
A `None` predicate is always satisfied.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, pred, children):
|
||||||
|
# type: (PredNode, List[EncNode]) -> None
|
||||||
|
self.pred = pred
|
||||||
|
self.children = children
|
||||||
|
|
||||||
|
def size(self):
|
||||||
|
# type: () -> int
|
||||||
|
s = 1 if self.pred else 0
|
||||||
|
s += sum(c.size() for c in self.children)
|
||||||
|
return s
|
||||||
|
|
||||||
|
def encode(self, encoder, final):
|
||||||
|
# type: (Encoder, bool) -> None
|
||||||
|
if self.pred:
|
||||||
|
skip = 0 if final else self.size() - 1
|
||||||
|
ctx = self.pred.predicate_context()
|
||||||
|
if isinstance(ctx, SettingGroup):
|
||||||
|
encoder.isap(self.pred, skip)
|
||||||
|
else:
|
||||||
|
encoder.instp(self.pred, skip)
|
||||||
|
|
||||||
|
final_idx = len(self.children) - 1 if final else -1
|
||||||
|
for idx, node in enumerate(self.children):
|
||||||
|
node.encode(encoder, idx == final_idx)
|
||||||
|
|
||||||
|
def predicate(self):
|
||||||
|
# type: () -> PredNode
|
||||||
|
return self.pred
|
||||||
|
|
||||||
|
def optimize(self):
|
||||||
|
# type: () -> EncNode
|
||||||
|
"""
|
||||||
|
Optimize a predicate node in the tree by combining child nodes that
|
||||||
|
have identical predicates.
|
||||||
|
"""
|
||||||
|
cnodes = list() # type: List[EncNode]
|
||||||
|
for pred, niter in groupby(
|
||||||
|
map(lambda c: c.optimize(), self.children),
|
||||||
|
key=lambda c: c.predicate()):
|
||||||
|
nodes = list(niter)
|
||||||
|
if pred is None or len(nodes) <= 1:
|
||||||
|
cnodes.extend(nodes)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# We have multiple children with identical predicates.
|
||||||
|
# Group them all into `n0`.
|
||||||
|
n0 = nodes[0]
|
||||||
|
assert isinstance(n0, EncPred)
|
||||||
|
for n in nodes[1:]:
|
||||||
|
assert isinstance(n, EncPred)
|
||||||
|
n0.children.extend(n.children)
|
||||||
|
|
||||||
|
cnodes.append(n0)
|
||||||
|
|
||||||
|
# Finally strip a redundant grouping node.
|
||||||
|
if self.pred is None and len(cnodes) == 1:
|
||||||
|
return cnodes[0]
|
||||||
|
else:
|
||||||
|
self.children = cnodes
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
class EncLeaf(EncNode):
|
||||||
|
"""
|
||||||
|
A leaf in the encoder tree.
|
||||||
|
|
||||||
|
This represents a single `Encoding`, without its predicates (they are
|
||||||
|
represented in the tree by parent nodes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, encoding):
|
||||||
|
# type: (Encoding) -> None
|
||||||
|
self.encoding = encoding
|
||||||
|
|
||||||
|
def size(self):
|
||||||
|
# type: () -> int
|
||||||
|
# recipe + bits.
|
||||||
|
return 2
|
||||||
|
|
||||||
|
def encode(self, encoder, final):
|
||||||
|
# type: (Encoder, bool) -> None
|
||||||
|
encoder.recipe(self.encoding, final)
|
||||||
|
|
||||||
|
|
||||||
class EncList(object):
|
class EncList(object):
|
||||||
@@ -239,25 +426,23 @@ class EncList(object):
|
|||||||
name += ' ({})'.format(self.encodings[0].cpumode)
|
name += ' ({})'.format(self.encodings[0].cpumode)
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def by_isap(self):
|
def encoder_tree(self):
|
||||||
# type: () -> Iterable[Tuple[PredNode, Tuple[Encoding, ...]]]
|
# type: () -> EncNode
|
||||||
"""
|
"""
|
||||||
Group the encodings by ISA predicate without reordering them.
|
Generate an optimized encoder tree for this list. The tree represents
|
||||||
|
all of the encodings with parent nodes for the predicates that need
|
||||||
|
checking.
|
||||||
|
"""
|
||||||
|
forest = list() # type: List[EncNode]
|
||||||
|
for enc in self.encodings:
|
||||||
|
n = EncLeaf(enc) # type: EncNode
|
||||||
|
if enc.instp:
|
||||||
|
n = EncPred(enc.instp, [n])
|
||||||
|
if enc.isap:
|
||||||
|
n = EncPred(enc.isap, [n])
|
||||||
|
forest.append(n)
|
||||||
|
|
||||||
Yield a sequence of `(isap, (encs...))` tuples where `isap` is the ISA
|
return EncPred(None, forest).optimize()
|
||||||
predicate or `None`, and `(encs...)` is a tuple of encodings that all
|
|
||||||
have the same ISA predicate.
|
|
||||||
"""
|
|
||||||
maxlen = CODE_FAIL >> PRED_BITS
|
|
||||||
for isap, groupi in itertools.groupby(
|
|
||||||
self.encodings, lambda enc: enc.isap):
|
|
||||||
group = tuple(groupi)
|
|
||||||
# This probably never happens, but we can't express more than
|
|
||||||
# maxlen encodings per isap.
|
|
||||||
while len(group) > maxlen:
|
|
||||||
yield (isap, group[0:maxlen])
|
|
||||||
group = group[maxlen:]
|
|
||||||
yield (isap, group)
|
|
||||||
|
|
||||||
def encode(self, seq_table, doc_table, isa):
|
def encode(self, seq_table, doc_table, isa):
|
||||||
# type: (UniqueSeqTable, DefaultDict[int, List[str]], TargetISA) -> None # noqa
|
# type: (UniqueSeqTable, DefaultDict[int, List[str]], TargetISA) -> None # noqa
|
||||||
@@ -269,34 +454,20 @@ class EncList(object):
|
|||||||
|
|
||||||
Adds comment lines to `doc_table` keyed by seq_table offsets.
|
Adds comment lines to `doc_table` keyed by seq_table offsets.
|
||||||
"""
|
"""
|
||||||
words = list() # type: List[int]
|
# Use an encoder object to hold the parameters.
|
||||||
docs = list() # type: List[Tuple[int, str]]
|
encoder = Encoder(isa)
|
||||||
|
tree = self.encoder_tree()
|
||||||
|
tree.encode(encoder, True)
|
||||||
|
|
||||||
# Group our encodings by isap.
|
self.offset = seq_table.add(encoder.words)
|
||||||
for isap, group in self.by_isap():
|
|
||||||
if isap:
|
|
||||||
# We have an ISA predicate covering `glen` encodings.
|
|
||||||
pnum = isa.settings.predicate_number[isap]
|
|
||||||
glen = len(group)
|
|
||||||
doc = 'skip {}x3 unless {}'.format(glen, isap)
|
|
||||||
docs.append((len(words), doc))
|
|
||||||
words.append((glen << PRED_BITS) | pnum)
|
|
||||||
|
|
||||||
for enc in group:
|
|
||||||
seq, doc = seq_doc(enc)
|
|
||||||
docs.append((len(words), doc))
|
|
||||||
words.extend(seq)
|
|
||||||
|
|
||||||
# Terminate the list.
|
|
||||||
words.append(CODE_FAIL)
|
|
||||||
|
|
||||||
self.offset = seq_table.add(words)
|
|
||||||
|
|
||||||
# Add doc comments.
|
# Add doc comments.
|
||||||
doc_table[self.offset].append(
|
doc_table[self.offset].append(
|
||||||
'{:06x}: {}'.format(self.offset, self.name()))
|
'{:06x}: {}'.format(self.offset, self.name()))
|
||||||
for pos, doc in docs:
|
for pos, doc in encoder.docs:
|
||||||
doc_table[self.offset + pos].append(doc)
|
doc_table[self.offset + pos].append(doc)
|
||||||
|
doc_table[self.offset + len(encoder.words)].insert(
|
||||||
|
0, 'end of: {}'.format(self.name()))
|
||||||
|
|
||||||
|
|
||||||
class Level2Table(object):
|
class Level2Table(object):
|
||||||
|
|||||||
@@ -143,22 +143,19 @@ pub fn lookup_enclist<OffT1, OffT2>(ctrl_typevar: Type,
|
|||||||
/// Encoding lists are represented as sequences of u16 words.
|
/// Encoding lists are represented as sequences of u16 words.
|
||||||
pub type EncListEntry = u16;
|
pub type EncListEntry = u16;
|
||||||
|
|
||||||
/// Number of bits used to represent a predicate. c.f. `meta.gen_encoding.py`.
|
/// Number of bits used to represent a predicate. c.f. `meta/gen_encoding.py`.
|
||||||
const PRED_BITS: u8 = 12;
|
const PRED_BITS: u8 = 12;
|
||||||
const PRED_MASK: EncListEntry = (1 << PRED_BITS) - 1;
|
const PRED_MASK: usize = (1 << PRED_BITS) - 1;
|
||||||
|
/// First code word representing a predicate check. c.f. `meta/gen_encoding.py`.
|
||||||
/// The match-always instruction predicate. c.f. `meta.gen_encoding.py`.
|
const PRED_START: usize = 0x1000;
|
||||||
const CODE_ALWAYS: EncListEntry = PRED_MASK;
|
|
||||||
|
|
||||||
/// The encoding list terminator.
|
|
||||||
const CODE_FAIL: EncListEntry = 0xffff;
|
|
||||||
|
|
||||||
/// An iterator over legal encodings for the instruction.
|
/// An iterator over legal encodings for the instruction.
|
||||||
pub struct Encodings<'a> {
|
pub struct Encodings<'a> {
|
||||||
|
// Current offset into `enclist`, or out of bounds after we've reached the end.
|
||||||
offset: usize,
|
offset: usize,
|
||||||
enclist: &'static [EncListEntry],
|
|
||||||
inst: &'a InstructionData,
|
inst: &'a InstructionData,
|
||||||
isa_predicates: PredicateView<'a>,
|
isa_predicates: PredicateView<'a>,
|
||||||
|
enclist: &'static [EncListEntry],
|
||||||
recipe_predicates: &'static [RecipePredicate],
|
recipe_predicates: &'static [RecipePredicate],
|
||||||
inst_predicates: &'static [InstPredicate],
|
inst_predicates: &'static [InstPredicate],
|
||||||
}
|
}
|
||||||
@@ -166,16 +163,6 @@ pub struct Encodings<'a> {
|
|||||||
impl<'a> Encodings<'a> {
|
impl<'a> Encodings<'a> {
|
||||||
/// Creates a new instance of `Encodings`.
|
/// Creates a new instance of `Encodings`.
|
||||||
///
|
///
|
||||||
/// # Parameters
|
|
||||||
///
|
|
||||||
/// - `offset` an offset into encoding list returned by `lookup_enclist` function.
|
|
||||||
/// - `enclist` a list of encoding entries.
|
|
||||||
/// - `recipe_predicates` is a slice of recipe predicate functions.
|
|
||||||
/// - `inst` the current instruction.
|
|
||||||
/// - `instp` an instruction predicate number to be evaluated on the current instruction.
|
|
||||||
/// - `isa_predicate_bytes` an ISA flags as a slice of bytes to evaluate an ISA predicate number
|
|
||||||
/// on the current instruction.
|
|
||||||
///
|
|
||||||
/// This iterator provides search for encodings that applies to the given instruction. The
|
/// This iterator provides search for encodings that applies to the given instruction. The
|
||||||
/// encoding lists are laid out such that first call to `next` returns valid entry in the list
|
/// encoding lists are laid out such that first call to `next` returns valid entry in the list
|
||||||
/// or `None`.
|
/// or `None`.
|
||||||
@@ -196,42 +183,63 @@ impl<'a> Encodings<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the predicate for `recipe` is satisfied.
|
/// Check if the `rpred` recipe predicate s satisfied.
|
||||||
fn check_recipe(&self, recipe: u16) -> bool {
|
fn check_recipe(&self, rpred: RecipePredicate) -> bool {
|
||||||
match self.recipe_predicates[recipe as usize] {
|
match rpred {
|
||||||
Some(p) => p(self.isa_predicates, self.inst),
|
Some(p) => p(self.isa_predicates, self.inst),
|
||||||
None => true,
|
None => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check an instruction or isa predicate.
|
||||||
|
fn check_pred(&self, pred: usize) -> bool {
|
||||||
|
if let Some(&p) = self.inst_predicates.get(pred) {
|
||||||
|
p(self.inst)
|
||||||
|
} else {
|
||||||
|
let pred = pred - self.inst_predicates.len();
|
||||||
|
self.isa_predicates.test(pred)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for Encodings<'a> {
|
impl<'a> Iterator for Encodings<'a> {
|
||||||
type Item = Encoding;
|
type Item = Encoding;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Encoding> {
|
fn next(&mut self) -> Option<Encoding> {
|
||||||
while self.enclist[self.offset] != CODE_FAIL {
|
while let Some(entryref) = self.enclist.get(self.offset) {
|
||||||
let pred = self.enclist[self.offset];
|
let entry = *entryref as usize;
|
||||||
if pred <= CODE_ALWAYS {
|
|
||||||
// This is an instruction predicate followed by recipe and encbits entries.
|
// Check for "recipe+bits".
|
||||||
self.offset += 3;
|
let recipe = entry >> 1;
|
||||||
let satisfied = match self.inst_predicates.get(pred as usize) {
|
if let Some(&rpred) = self.recipe_predicates.get(recipe) {
|
||||||
Some(p) => p(self.inst),
|
let bits = self.offset + 1;
|
||||||
None => true,
|
if entry & 1 == 0 {
|
||||||
};
|
self.offset += 2; // Next entry.
|
||||||
if satisfied {
|
|
||||||
let recipe = self.enclist[self.offset - 2];
|
|
||||||
if self.check_recipe(recipe) {
|
|
||||||
let encoding = Encoding::new(recipe, self.enclist[self.offset - 1]);
|
|
||||||
return Some(encoding);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// This is an ISA predicate entry.
|
self.offset = !0; // Stop.
|
||||||
self.offset += 1;
|
|
||||||
if !self.isa_predicates.test((pred & PRED_MASK) as usize) {
|
|
||||||
// ISA predicate failed, skip the next N entries.
|
|
||||||
self.offset += 3 * (pred >> PRED_BITS) as usize;
|
|
||||||
}
|
}
|
||||||
|
if self.check_recipe(rpred) {
|
||||||
|
return Some(Encoding::new(recipe as u16, self.enclist[bits]));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for "stop with legalize".
|
||||||
|
if entry < PRED_START {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, this must be a predicate entry.
|
||||||
|
let pred_entry = entry - PRED_START;
|
||||||
|
let skip = pred_entry >> PRED_BITS;
|
||||||
|
let pred = pred_entry & PRED_MASK;
|
||||||
|
|
||||||
|
if self.check_pred(pred) {
|
||||||
|
self.offset += 1;
|
||||||
|
} else if skip == 0 {
|
||||||
|
self.offset = !0 // This means stop.
|
||||||
|
} else {
|
||||||
|
self.offset += 1 + skip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
|||||||
Reference in New Issue
Block a user