From aa06e404569adfa6b8fb9aa8d08dff18e610d361 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Thu, 30 Mar 2017 11:33:28 -0700 Subject: [PATCH] Allow dot syntax notation for enumerated immediate operands. The meta language patterns sometimes need to refer to specific values of enumerated immediate operands. The dot syntax provides a namespaced, typed way of doing that: icmp(intcc.ult, a, x). Add an ast.Enumerator class for representing this kind of AST leaf node. Add value definitions for the intcc and floatcc immediate operand kinds. --- lib/cretonne/meta/base/immediates.py | 32 ++++++++++++++++++++++-- lib/cretonne/meta/base/legalize.py | 5 ++-- lib/cretonne/meta/cdsl/ast.py | 36 ++++++++++++++++++++++++++- lib/cretonne/meta/cdsl/operands.py | 37 +++++++++++++++++++++++++--- 4 files changed, 102 insertions(+), 8 deletions(-) diff --git a/lib/cretonne/meta/base/immediates.py b/lib/cretonne/meta/base/immediates.py index 05a542b6d9..ff2eb972a5 100644 --- a/lib/cretonne/meta/base/immediates.py +++ b/lib/cretonne/meta/base/immediates.py @@ -34,7 +34,19 @@ ieee64 = ImmediateKind('ieee64', 'A 64-bit immediate floating point number.') intcc = ImmediateKind( 'intcc', 'An integer comparison condition code.', - default_member='cond', rust_type='IntCC') + default_member='cond', rust_type='IntCC', + values={ + 'eq': 'Equal', + 'ne': 'NotEqual', + 'sge': 'SignedGreaterThanOrEqual', + 'sgt': 'SignedGreaterThan', + 'sle': 'SignedLessThanOrEqual', + 'slt': 'SignedLessThan', + 'uge': 'UnsignedGreaterThanOrEqual', + 'ugt': 'UnsignedGreaterThan', + 'ule': 'UnsignedLessThanOrEqual', + 'ult': 'UnsignedLessThan', + }) #: A condition code for comparing floating point values. #: @@ -43,4 +55,20 @@ intcc = ImmediateKind( floatcc = ImmediateKind( 'floatcc', 'A floating point comparison condition code.', - default_member='cond', rust_type='FloatCC') + default_member='cond', rust_type='FloatCC', + values={ + 'ord': 'Ordered', + 'uno': 'Unordered', + 'eq': 'Equal', + 'ne': 'NotEqual', + 'one': 'OrderedNotEqual', + 'ueq': 'UnorderedOrEqual', + 'lt': 'LessThan', + 'le': 'LessThanOrEqual', + 'gt': 'GreaterThan', + 'ge': 'GreaterThanOrEqual', + 'ult': 'UnorderedOrLessThan', + 'ule': 'UnorderedOrLessThanOrEqual', + 'ugt': 'UnorderedOrGreaterThan', + 'uge': 'UnorderedOrGreaterThanOrEqual', + }) diff --git a/lib/cretonne/meta/base/legalize.py b/lib/cretonne/meta/base/legalize.py index dc8185daf2..8211a0039f 100644 --- a/lib/cretonne/meta/base/legalize.py +++ b/lib/cretonne/meta/base/legalize.py @@ -7,6 +7,7 @@ patterns that describe how base instructions can be transformed to other base instructions that are legal. """ from __future__ import absolute_import +from .immediates import intcc from .instructions import iadd, iadd_cout, iadd_cin, iadd_carry, iadd_imm from .instructions import isub, isub_bin, isub_bout, isub_borrow from .instructions import band, bor, bxor, isplit, iconcat @@ -90,14 +91,14 @@ expand.legalize( (a, c) << iadd_cout(x, y), Rtl( a << iadd(x, y), - c << icmp('IntCC::UnsignedLessThan', a, x) + c << icmp(intcc.ult, a, x) )) expand.legalize( (a, b) << isub_bout(x, y), Rtl( a << isub(x, y), - b << icmp('IntCC::UnsignedGreaterThan', a, x) + b << icmp(intcc.ugt, a, x) )) expand.legalize( diff --git a/lib/cretonne/meta/cdsl/ast.py b/lib/cretonne/meta/cdsl/ast.py index 931cc1e3a2..e70e36388a 100644 --- a/lib/cretonne/meta/cdsl/ast.py +++ b/lib/cretonne/meta/cdsl/ast.py @@ -9,7 +9,9 @@ from . import instructions from .typevar import TypeVar try: - from typing import Union, Tuple, Sequence # noqa + from typing import Union, Tuple, Sequence, TYPE_CHECKING # noqa + if TYPE_CHECKING: + from .operands import ImmediateKind # noqa except ImportError: pass @@ -404,3 +406,35 @@ class Apply(Expr): args = defs[0].rust_type() + ', ' + args method = self.inst.snake_name() return '{}({})'.format(method, args) + + +class Enumerator(Expr): + """ + A value of an enumerated immediate operand. + + Some immediate operand kinds like `intcc` and `floatcc` have an enumerated + range of values corresponding to a Rust enum type. An `Enumerator` object + is an AST leaf node representing one of the values. + + :param kind: The enumerated `ImmediateKind` containing the value. + :param value: The textual IL representation of the value. + + `Enumerator` nodes are not usually created directly. They are created by + using the dot syntax on immediate kinds: `intcc.ult`. + """ + + def __init__(self, kind, value): + # type: (ImmediateKind, str) -> None + self.kind = kind + self.value = value + + def __str__(self): + # type: () -> str + """ + Get the Rust expression form of this enumerator. + """ + return self.kind.rust_enumerator(self.value) + + def __repr__(self): + # type: () -> str + return '{}.{}'.format(self.kind, self.value) diff --git a/lib/cretonne/meta/cdsl/operands.py b/lib/cretonne/meta/cdsl/operands.py index 49e3e588af..44bae5d500 100644 --- a/lib/cretonne/meta/cdsl/operands.py +++ b/lib/cretonne/meta/cdsl/operands.py @@ -5,8 +5,10 @@ from .types import ValueType from .typevar import TypeVar try: - from typing import Union + from typing import Union, Dict, TYPE_CHECKING # noqa OperandSpec = Union['OperandKind', ValueType, TypeVar] + if TYPE_CHECKING: + from .ast import Enumerator # noqa except ImportError: pass @@ -74,15 +76,44 @@ class ImmediateKind(OperandKind): `InstructionData` data structure. """ - def __init__(self, name, doc, default_member='imm', rust_type=None): - # type: (str, str, str, str) -> None + def __init__( + self, name, doc, + default_member='imm', + rust_type=None, + values=None): + # type: (str, str, str, str, Dict[str, str]) -> None super(ImmediateKind, self).__init__( name, doc, default_member, rust_type) + self.values = values def __repr__(self): # type: () -> str return 'ImmediateKind({})'.format(self.name) + def __getattr__(self, value): + # type: (str) -> Enumerator + """ + Enumerated immediate kinds allow the use of dot syntax to produce + `Enumerator` AST nodes: `icmp.i32(intcc.ult, a, b)`. + """ + from .ast import Enumerator # noqa + if not self.values: + raise AssertionError( + '{n} is not an enumerated operand kind: {n}.{a}'.format( + n=self.name, a=value)) + if value not in self.values: + raise AssertionError( + 'No such {n} enumerator: {n}.{a}'.format( + n=self.name, a=value)) + return Enumerator(self, value) + + def rust_enumerator(self, value): + # type: (str) -> str + """ + Get the qualified Rust name of the enumerator value `value`. + """ + return '{}::{}'.format(self.rust_type, self.values[value]) + # Instances of entity reference operand types are provided in the # `cretonne.entities` module.