From b3b15f9c321acd111f345d4522ee80203fa3260a Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Mon, 8 May 2017 15:21:00 -0700 Subject: [PATCH] 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. --- lib/cretonne/meta/cdsl/isa.py | 22 ++++++++++++--- lib/cretonne/meta/gen_encoding.py | 42 ++++++++++++++++++++--------- lib/cretonne/src/isa/constraints.rs | 11 ++++---- 3 files changed, 53 insertions(+), 22 deletions(-) diff --git a/lib/cretonne/meta/cdsl/isa.py b/lib/cretonne/meta/cdsl/isa.py index a44a1e6333..f1125f59da 100644 --- a/lib/cretonne/meta/cdsl/isa.py +++ b/lib/cretonne/meta/cdsl/isa.py @@ -7,7 +7,7 @@ from .ast import Apply # The typing module is only required by mypy, and we don't use these imports # outside type comments. 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: from .instructions import MaybeBoundInst, InstructionGroup, InstructionFormat # noqa from .predicates import PredNode # noqa @@ -220,13 +220,27 @@ class EncRecipe(object): if isinstance(c, int): # An integer constraint is bound to a value operand. # Check that it is in range. - assert c >= 0 - if not self.format.has_value_list: - assert c < self.format.num_value_operands + assert c >= 0 and c < len(self.ins) else: assert isinstance(c, RegClass) or isinstance(c, Register) 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): """ diff --git a/lib/cretonne/meta/gen_encoding.py b/lib/cretonne/meta/gen_encoding.py index bbe1df7591..f19377b8bd 100644 --- a/lib/cretonne/meta/gen_encoding.py +++ b/lib/cretonne/meta/gen_encoding.py @@ -60,9 +60,9 @@ from cdsl.registers import RegClass, Register from cdsl.predicates import FieldPredicate 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: - 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.types import ValueType # noqa from cdsl.instructions import Instruction # noqa @@ -470,13 +470,20 @@ def emit_recipe_constraints(isa, fmt): .format(len(isa.all_recipes)), '];'): for r in isa.all_recipes: fmt.comment(r.name) + tied_i2o, tied_o2i = r.ties() with fmt.indented('RecipeConstraints {', '},'): - emit_operand_constraints(r.ins, 'ins', fmt) - emit_operand_constraints(r.outs, 'outs', fmt) + emit_operand_constraints(r, r.ins, 'ins', tied_i2o, fmt) + emit_operand_constraints(r, r.outs, 'outs', tied_o2i, fmt) -def emit_operand_constraints(seq, field, fmt): - # type: (Sequence[OperandConstraint], str, srcgen.Formatter) -> None +def emit_operand_constraints( + 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. """ @@ -484,16 +491,25 @@ def emit_operand_constraints(seq, field, fmt): fmt.line('{}: &[],'.format(field)) return with fmt.indented('{}: &['.format(field), '],'): - for cons in seq: + for n, cons in enumerate(seq): with fmt.indented('OperandConstraint {', '},'): if isinstance(cons, RegClass): - fmt.line('kind: ConstraintKind::Reg,') - fmt.line('regclass: {},'.format(cons)) + if n in tied: + fmt.format('kind: ConstraintKind::Tied({}),', tied[n]) + else: + fmt.line('kind: ConstraintKind::Reg,') + fmt.format('regclass: {},', cons) elif isinstance(cons, Register): - fmt.line( - 'kind: ConstraintKind::FixedReg({}),' - .format(cons.unit)) - fmt.line('regclass: {},'.format(cons.regclass)) + assert n not in tied, "Can't tie fixed register operand" + fmt.format( + 'kind: ConstraintKind::FixedReg({}),', cons.unit) + 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: raise AssertionError( 'Unsupported constraint {}'.format(cons)) diff --git a/lib/cretonne/src/isa/constraints.rs b/lib/cretonne/src/isa/constraints.rs index 23cd923f93..fa30fd24fe 100644 --- a/lib/cretonne/src/isa/constraints.rs +++ b/lib/cretonne/src/isa/constraints.rs @@ -33,13 +33,14 @@ pub enum ConstraintKind { /// register. FixedReg(RegUnit), - /// This result value must use the same register as an input value operand. Input operands - /// can't be tied. + /// This result value must use the same register as an input value operand. /// - /// 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 - /// operand's register class. + /// When an (in, out) operand pair is tied, this constraint kind appears in both the `ins` and + /// the `outs` arrays. The constraint for the in operand is `Tied(out)`, and the constraint for + /// the out operand is `Tied(in)`. Tied(u8), /// This operand must be a value in a stack slot.