Add support for tied operand constraints.

The register constraint for an output operand can be specified as an
integer indicating the input operand number to tie. The tied operands
must use the same register.

Generate operand constraints using ConstraintKind::Tied(n) for both the
tied operands. The n index refers to the opposite array. The input
operand refers to the outs array and vice versa.
This commit is contained in:
Jakob Stoklund Olesen
2017-05-08 15:21:00 -07:00
parent fedc834ecd
commit b3b15f9c32
3 changed files with 53 additions and 22 deletions

View File

@@ -7,7 +7,7 @@ from .ast import Apply
# The typing module is only required by mypy, and we don't use these imports # The typing module is only required by mypy, and we don't use these imports
# outside type comments. # outside type comments.
try: try:
from typing import Tuple, Union, Any, Iterable, Sequence, List, Set, TYPE_CHECKING # noqa from typing import Tuple, Union, Any, Iterable, Sequence, List, Set, Dict, TYPE_CHECKING # noqa
if TYPE_CHECKING: if TYPE_CHECKING:
from .instructions import MaybeBoundInst, InstructionGroup, InstructionFormat # noqa from .instructions import MaybeBoundInst, InstructionGroup, InstructionFormat # noqa
from .predicates import PredNode # noqa from .predicates import PredNode # noqa
@@ -220,13 +220,27 @@ class EncRecipe(object):
if isinstance(c, int): if isinstance(c, int):
# An integer constraint is bound to a value operand. # An integer constraint is bound to a value operand.
# Check that it is in range. # Check that it is in range.
assert c >= 0 assert c >= 0 and c < len(self.ins)
if not self.format.has_value_list:
assert c < self.format.num_value_operands
else: else:
assert isinstance(c, RegClass) or isinstance(c, Register) assert isinstance(c, RegClass) or isinstance(c, Register)
return seq return seq
def ties(self):
# type: () -> Tuple[Dict[int, int], Dict[int, int]]
"""
Return two dictionaries representing the tied operands.
The first maps input number to tied output number, the second maps
output number to tied input number.
"""
i2o = dict() # type: Dict[int, int]
o2i = dict() # type: Dict[int, int]
for o, i in enumerate(self.outs):
if isinstance(i, int):
i2o[i] = o
o2i[o] = i
return (i2o, o2i)
class Encoding(object): class Encoding(object):
""" """

View File

@@ -60,9 +60,9 @@ from cdsl.registers import RegClass, Register
from cdsl.predicates import FieldPredicate from cdsl.predicates import FieldPredicate
try: try:
from typing import Sequence, Set, Tuple, List, Iterable, DefaultDict, TYPE_CHECKING # noqa from typing import Sequence, Set, Tuple, List, Dict, Iterable, DefaultDict, TYPE_CHECKING # noqa
if TYPE_CHECKING: if TYPE_CHECKING:
from cdsl.isa import TargetISA, OperandConstraint, Encoding, CPUMode # noqa from cdsl.isa import TargetISA, OperandConstraint, Encoding, CPUMode, EncRecipe # noqa
from cdsl.predicates import PredNode, PredLeaf # noqa from cdsl.predicates import PredNode, PredLeaf # noqa
from cdsl.types import ValueType # noqa from cdsl.types import ValueType # noqa
from cdsl.instructions import Instruction # noqa from cdsl.instructions import Instruction # noqa
@@ -470,13 +470,20 @@ def emit_recipe_constraints(isa, fmt):
.format(len(isa.all_recipes)), '];'): .format(len(isa.all_recipes)), '];'):
for r in isa.all_recipes: for r in isa.all_recipes:
fmt.comment(r.name) fmt.comment(r.name)
tied_i2o, tied_o2i = r.ties()
with fmt.indented('RecipeConstraints {', '},'): with fmt.indented('RecipeConstraints {', '},'):
emit_operand_constraints(r.ins, 'ins', fmt) emit_operand_constraints(r, r.ins, 'ins', tied_i2o, fmt)
emit_operand_constraints(r.outs, 'outs', fmt) emit_operand_constraints(r, r.outs, 'outs', tied_o2i, fmt)
def emit_operand_constraints(seq, field, fmt): def emit_operand_constraints(
# type: (Sequence[OperandConstraint], str, srcgen.Formatter) -> None recipe, # type: EncRecipe
seq, # type: Sequence[OperandConstraint]
field, # type: str
tied, # type: Dict[int, int]
fmt # type: srcgen.Formatter
):
# type: (...) -> None
""" """
Emit a struct field initializer for an array of operand constraints. Emit a struct field initializer for an array of operand constraints.
""" """
@@ -484,16 +491,25 @@ def emit_operand_constraints(seq, field, fmt):
fmt.line('{}: &[],'.format(field)) fmt.line('{}: &[],'.format(field))
return return
with fmt.indented('{}: &['.format(field), '],'): with fmt.indented('{}: &['.format(field), '],'):
for cons in seq: for n, cons in enumerate(seq):
with fmt.indented('OperandConstraint {', '},'): with fmt.indented('OperandConstraint {', '},'):
if isinstance(cons, RegClass): if isinstance(cons, RegClass):
fmt.line('kind: ConstraintKind::Reg,') if n in tied:
fmt.line('regclass: {},'.format(cons)) fmt.format('kind: ConstraintKind::Tied({}),', tied[n])
else:
fmt.line('kind: ConstraintKind::Reg,')
fmt.format('regclass: {},', cons)
elif isinstance(cons, Register): elif isinstance(cons, Register):
fmt.line( assert n not in tied, "Can't tie fixed register operand"
'kind: ConstraintKind::FixedReg({}),' fmt.format(
.format(cons.unit)) 'kind: ConstraintKind::FixedReg({}),', cons.unit)
fmt.line('regclass: {},'.format(cons.regclass)) fmt.format('regclass: {},', cons.regclass)
elif isinstance(cons, int):
# This is a tied output constraint. It should never happen
# for input constraints.
assert cons == tied[n], "Invalid tied constraint"
fmt.format('kind: ConstraintKind::Tied({}),', cons)
fmt.format('regclass: {},', recipe.ins[cons])
else: else:
raise AssertionError( raise AssertionError(
'Unsupported constraint {}'.format(cons)) 'Unsupported constraint {}'.format(cons))

View File

@@ -33,13 +33,14 @@ pub enum ConstraintKind {
/// register. /// register.
FixedReg(RegUnit), FixedReg(RegUnit),
/// This result value must use the same register as an input value operand. Input operands /// This result value must use the same register as an input value operand.
/// can't be tied.
/// ///
/// The associated number is the index of the input value operand this result is tied to. /// The associated number is the index of the input value operand this result is tied to. The
/// constraint's `regclass` field is the same as the tied operand's register class.
/// ///
/// The constraint's `regclass` field is the top-level register class containing the tied /// When an (in, out) operand pair is tied, this constraint kind appears in both the `ins` and
/// operand's register class. /// the `outs` arrays. The constraint for the in operand is `Tied(out)`, and the constraint for
/// the out operand is `Tied(in)`.
Tied(u8), Tied(u8),
/// This operand must be a value in a stack slot. /// This operand must be a value in a stack slot.