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.
This commit is contained in:
Jakob Stoklund Olesen
2017-03-30 11:33:28 -07:00
parent cb33f93fcd
commit aa06e40456
4 changed files with 102 additions and 8 deletions

View File

@@ -34,7 +34,19 @@ ieee64 = ImmediateKind('ieee64', 'A 64-bit immediate floating point number.')
intcc = ImmediateKind( intcc = ImmediateKind(
'intcc', 'intcc',
'An integer comparison condition code.', '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. #: A condition code for comparing floating point values.
#: #:
@@ -43,4 +55,20 @@ intcc = ImmediateKind(
floatcc = ImmediateKind( floatcc = ImmediateKind(
'floatcc', 'floatcc',
'A floating point comparison condition code.', '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',
})

View File

@@ -7,6 +7,7 @@ patterns that describe how base instructions can be transformed to other base
instructions that are legal. instructions that are legal.
""" """
from __future__ import absolute_import from __future__ import absolute_import
from .immediates import intcc
from .instructions import iadd, iadd_cout, iadd_cin, iadd_carry, iadd_imm 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 isub, isub_bin, isub_bout, isub_borrow
from .instructions import band, bor, bxor, isplit, iconcat from .instructions import band, bor, bxor, isplit, iconcat
@@ -90,14 +91,14 @@ expand.legalize(
(a, c) << iadd_cout(x, y), (a, c) << iadd_cout(x, y),
Rtl( Rtl(
a << iadd(x, y), a << iadd(x, y),
c << icmp('IntCC::UnsignedLessThan', a, x) c << icmp(intcc.ult, a, x)
)) ))
expand.legalize( expand.legalize(
(a, b) << isub_bout(x, y), (a, b) << isub_bout(x, y),
Rtl( Rtl(
a << isub(x, y), a << isub(x, y),
b << icmp('IntCC::UnsignedGreaterThan', a, x) b << icmp(intcc.ugt, a, x)
)) ))
expand.legalize( expand.legalize(

View File

@@ -9,7 +9,9 @@ from . import instructions
from .typevar import TypeVar from .typevar import TypeVar
try: 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: except ImportError:
pass pass
@@ -404,3 +406,35 @@ class Apply(Expr):
args = defs[0].rust_type() + ', ' + args args = defs[0].rust_type() + ', ' + args
method = self.inst.snake_name() method = self.inst.snake_name()
return '{}({})'.format(method, args) 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)

View File

@@ -5,8 +5,10 @@ from .types import ValueType
from .typevar import TypeVar from .typevar import TypeVar
try: try:
from typing import Union from typing import Union, Dict, TYPE_CHECKING # noqa
OperandSpec = Union['OperandKind', ValueType, TypeVar] OperandSpec = Union['OperandKind', ValueType, TypeVar]
if TYPE_CHECKING:
from .ast import Enumerator # noqa
except ImportError: except ImportError:
pass pass
@@ -74,15 +76,44 @@ class ImmediateKind(OperandKind):
`InstructionData` data structure. `InstructionData` data structure.
""" """
def __init__(self, name, doc, default_member='imm', rust_type=None): def __init__(
# type: (str, str, str, str) -> None self, name, doc,
default_member='imm',
rust_type=None,
values=None):
# type: (str, str, str, str, Dict[str, str]) -> None
super(ImmediateKind, self).__init__( super(ImmediateKind, self).__init__(
name, doc, default_member, rust_type) name, doc, default_member, rust_type)
self.values = values
def __repr__(self): def __repr__(self):
# type: () -> str # type: () -> str
return 'ImmediateKind({})'.format(self.name) 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 # Instances of entity reference operand types are provided in the
# `cretonne.entities` module. # `cretonne.entities` module.