Split out operand descriptions.

- cdsl.operands has the Operand and OperandKind classes.
This commit is contained in:
Jakob Stoklund Olesen
2016-11-08 10:58:23 -08:00
parent 2fe61e83f6
commit bb28dc6686
10 changed files with 167 additions and 156 deletions

View File

@@ -127,13 +127,14 @@ There are some practical restrictions on the use of type variables, see
Immediate operands Immediate operands
------------------ ------------------
.. currentmodule:: cdsl.operands
Immediate instruction operands don't correspond to SSA values, but have values Immediate instruction operands don't correspond to SSA values, but have values
that are encoded directly in the instruction. Immediate operands don't that are encoded directly in the instruction. Immediate operands don't
have types from the :class:`cdsl.types.ValueType` type system; they often have have types from the :class:`cdsl.types.ValueType` type system; they often have
enumerated values of a specific type. The type of an immediate operand is enumerated values of a specific type. The type of an immediate operand is
indicated with an instance of :class:`ImmediateKind`. indicated with an instance of :class:`ImmediateKind`.
.. currentmodule:: cretonne
.. autoclass:: ImmediateKind .. autoclass:: ImmediateKind
.. automodule:: cretonne.immediates .. automodule:: cretonne.immediates
@@ -145,8 +146,7 @@ Entity references
Instruction operands can also refer to other entities in the same function. This Instruction operands can also refer to other entities in the same function. This
can be extended basic blocks, or entities declared in the function preamble. can be extended basic blocks, or entities declared in the function preamble.
.. currentmodule:: cretonne .. currentmodule:: cdsl.operands
.. autoclass:: EntityRefKind .. autoclass:: EntityRefKind
.. automodule:: cretonne.entities .. automodule:: cretonne.entities
@@ -183,7 +183,7 @@ the :func:`ScalarType.by` function.
Instruction representation Instruction representation
========================== ==========================
.. currentmodule:: cretonne .. module:: cdsl.operands
The Rust in-memory representation of instructions is derived from the The Rust in-memory representation of instructions is derived from the
instruction descriptions. Part of the representation is generated, and part is instruction descriptions. Part of the representation is generated, and part is
@@ -198,8 +198,10 @@ Since all SSA value operands are represented as a `Value` in Rust code, value
types don't affect the representation. Two special operand kinds are used to types don't affect the representation. Two special operand kinds are used to
represent SSA values: represent SSA values:
.. autodata:: value .. autodata:: VALUE
.. autodata:: variable_args .. autodata:: VARIABLE_ARGS
.. currentmodule:: cretonne
When an instruction description is created, it is automatically assigned a When an instruction description is created, it is automatically assigned a
predefined instruction format which is an instance of predefined instruction format which is an instance of

View File

@@ -4,3 +4,14 @@ Cretonne DSL classes.
This module defines the classes that are used to define Cretonne instructions This module defines the classes that are used to define Cretonne instructions
and other entitties. and other entitties.
""" """
from __future__ import absolute_import
import re
camel_re = re.compile('(^|_)([a-z])')
def camel_case(s):
# type: (str) -> str
"""Convert the string s to CamelCase"""
return camel_re.sub(lambda m: m.group(2).upper(), s)

View File

@@ -0,0 +1,104 @@
"""Classes for describing instruction operands."""
from __future__ import absolute_import
from . import camel_case
# Kinds of operands.
#
# Each instruction has an opcode and a number of operands. The opcode
# determines the instruction format, and the format determines the number of
# operands and the kind of each operand.
class OperandKind(object):
"""
An instance of the `OperandKind` class corresponds to a kind of operand.
Each operand kind has a corresponding type in the Rust representation of an
instruction.
"""
def __init__(self, name, doc, default_member=None, rust_type=None):
# type: (str, str, str, str) -> None
self.name = name
self.__doc__ = doc
self.default_member = default_member
# The camel-cased name of an operand kind is also the Rust type used to
# represent it.
self.rust_type = rust_type or camel_case(name)
def __str__(self):
# type: () -> str
return self.name
def __repr__(self):
# type: () -> str
return 'OperandKind({})'.format(self.name)
def operand_kind(self):
# type: () -> OperandKind
"""
An `OperandKind` instance can be used directly as the type of an
`Operand` when defining an instruction.
"""
return self
def free_typevar(self):
# Return the free typevariable controlling the type of this operand.
return None
#: An SSA value operand. This is a value defined by another instruction.
VALUE = OperandKind(
'value', """
An SSA value defined by another instruction.
This kind of operand can represent any SSA value type, but the
instruction format may restrict the valid value types for a given
operand.
""")
#: A variable-sized list of value operands. Use for Ebb and function call
#: arguments.
VARIABLE_ARGS = OperandKind(
'variable_args', """
A variable size list of `value` operands.
Use this to represent arguemtns passed to a function call, arguments
passed to an extended basic block, or a variable number of results
returned from an instruction.
""",
default_member='varargs')
# Instances of immediate operand types are provided in the
# `cretonne.immediates` module.
class ImmediateKind(OperandKind):
"""
The kind of an immediate instruction operand.
:param default_member: The default member name of this kind the
`InstructionData` data structure.
"""
def __init__(self, name, doc, default_member='imm', rust_type=None):
# type: (str, str, str, str) -> None
super(ImmediateKind, self).__init__(
name, doc, default_member, rust_type)
def __repr__(self):
# type: () -> str
return 'ImmediateKind({})'.format(self.name)
# Instances of entity reference operand types are provided in the
# `cretonne.entities` module.
class EntityRefKind(OperandKind):
"""
The kind of an entity reference instruction operand.
"""
def __init__(self, name, doc, default_member=None, rust_type=None):
# type: (str, str, str, str) -> None
super(EntityRefKind, self).__init__(
name, doc, default_member or name, rust_type)
def __repr__(self):
# type: () -> str
return 'EntityRefKind({})'.format(self.name)

View File

@@ -5,10 +5,11 @@ This module provides classes and functions used to describe Cretonne
instructions. instructions.
""" """
from __future__ import absolute_import from __future__ import absolute_import
import re
import importlib import importlib
from cdsl import camel_case
from cdsl.predicates import And from cdsl.predicates import And
import cdsl.types import cdsl.types
from cdsl.operands import VALUE, VARIABLE_ARGS, OperandKind
# 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.
@@ -25,116 +26,6 @@ if TYPE_CHECKING:
from .typevar import TypeVar # noqa from .typevar import TypeVar # noqa
camel_re = re.compile('(^|_)([a-z])')
def camel_case(s):
# type: (str) -> str
"""Convert the string s to CamelCase"""
return camel_re.sub(lambda m: m.group(2).upper(), s)
# Kinds of operands.
#
# Each instruction has an opcode and a number of operands. The opcode
# determines the instruction format, and the format determines the number of
# operands and the kind of each operand.
class OperandKind(object):
"""
An instance of the `OperandKind` class corresponds to a kind of operand.
Each operand kind has a corresponding type in the Rust representation of an
instruction.
"""
def __init__(self, name, doc, default_member=None, rust_type=None):
# type: (str, str, str, str) -> None
self.name = name
self.__doc__ = doc
self.default_member = default_member
# The camel-cased name of an operand kind is also the Rust type used to
# represent it.
self.rust_type = rust_type or camel_case(name)
def __str__(self):
# type: () -> str
return self.name
def __repr__(self):
# type: () -> str
return 'OperandKind({})'.format(self.name)
def operand_kind(self):
# type: () -> OperandKind
"""
An `OperandKind` instance can be used directly as the type of an
`Operand` when defining an instruction.
"""
return self
def free_typevar(self):
# Return the free typevariable controlling the type of this operand.
return None
#: An SSA value operand. This is a value defined by another instruction.
value = OperandKind(
'value', """
An SSA value defined by another instruction.
This kind of operand can represent any SSA value type, but the
instruction format may restrict the valid value types for a given
operand.
""")
#: A variable-sized list of value operands. Use for Ebb and function call
#: arguments.
variable_args = OperandKind(
'variable_args', """
A variable size list of `value` operands.
Use this to represent arguemtns passed to a function call, arguments
passed to an extended basic block, or a variable number of results
returned from an instruction.
""",
default_member='varargs')
# Instances of immediate operand types are provided in the
# `cretonne.immediates` module.
class ImmediateKind(OperandKind):
"""
The kind of an immediate instruction operand.
:param default_member: The default member name of this kind the
`InstructionData` data structure.
"""
def __init__(self, name, doc, default_member='imm', rust_type=None):
# type: (str, str, str, str) -> None
super(ImmediateKind, self).__init__(
name, doc, default_member, rust_type)
def __repr__(self):
# type: () -> str
return 'ImmediateKind({})'.format(self.name)
# Instances of entity reference operand types are provided in the
# `cretonne.entities` module.
class EntityRefKind(OperandKind):
"""
The kind of an entity reference instruction operand.
"""
def __init__(self, name, doc, default_member=None, rust_type=None):
# type: (str, str, str, str) -> None
super(EntityRefKind, self).__init__(
name, doc, default_member or name, rust_type)
def __repr__(self):
# type: () -> str
return 'EntityRefKind({})'.format(self.name)
# Defining instructions. # Defining instructions.
@@ -215,7 +106,7 @@ class Operand(object):
self.__doc__ = doc self.__doc__ = doc
self.typ = typ self.typ = typ
if isinstance(typ, cdsl.types.ValueType): if isinstance(typ, cdsl.types.ValueType):
self.kind = value self.kind = VALUE
else: else:
self.kind = typ.operand_kind() self.kind = typ.operand_kind()
@@ -235,7 +126,7 @@ class Operand(object):
""" """
Is this an SSA value operand? Is this an SSA value operand?
""" """
return self.kind is value return self.kind is cdsl.operands.VALUE
class InstructionFormat(object): class InstructionFormat(object):
@@ -285,12 +176,12 @@ class InstructionFormat(object):
# Which of self.kinds are `value`? # Which of self.kinds are `value`?
self.value_operands = tuple( self.value_operands = tuple(
i for i, k in enumerate(self.kinds) if k is value) i for i, k in enumerate(self.kinds) if k is VALUE)
# The typevar_operand argument must point to a 'value' operand. # The typevar_operand argument must point to a 'value' operand.
self.typevar_operand = kwargs.get('typevar_operand', None) # type: int self.typevar_operand = kwargs.get('typevar_operand', None) # type: int
if self.typevar_operand is not None: if self.typevar_operand is not None:
assert self.kinds[self.typevar_operand] is value, \ assert self.kinds[self.typevar_operand] is VALUE, \
"typevar_operand must indicate a 'value' operand" "typevar_operand must indicate a 'value' operand"
elif len(self.value_operands) > 0: elif len(self.value_operands) > 0:
# Default to the first 'value' operand, if there is one. # Default to the first 'value' operand, if there is one.
@@ -361,7 +252,7 @@ class InstructionFormat(object):
tuples of :py:`Operand` objects. tuples of :py:`Operand` objects.
""" """
if len(outs) == 1: if len(outs) == 1:
multiple_results = outs[0].kind == variable_args multiple_results = outs[0].kind == VARIABLE_ARGS
else: else:
multiple_results = len(outs) > 1 multiple_results = len(outs) > 1
sig = (multiple_results, tuple(op.kind for op in ins)) sig = (multiple_results, tuple(op.kind for op in ins))

View File

@@ -5,7 +5,8 @@ This module defines the basic Cretonne instruction set that all targets
support. support.
""" """
from __future__ import absolute_import from __future__ import absolute_import
from . import Operand, Instruction, InstructionGroup, variable_args from cdsl.operands import VARIABLE_ARGS
from . import Operand, Instruction, InstructionGroup
from .typevar import TypeVar from .typevar import TypeVar
from base.types import i8, f32, f64, b1 from base.types import i8, f32, f64, b1
from .immediates import imm64, uimm8, ieee32, ieee64, immvector, intcc, floatcc from .immediates import imm64, uimm8, ieee32, ieee64, immvector, intcc, floatcc
@@ -31,7 +32,7 @@ Any = TypeVar(
# #
c = Operand('c', Testable, doc='Controlling value to test') c = Operand('c', Testable, doc='Controlling value to test')
EBB = Operand('EBB', entities.ebb, doc='Destination extended basic block') EBB = Operand('EBB', entities.ebb, doc='Destination extended basic block')
args = Operand('args', variable_args, doc='EBB arguments') args = Operand('args', VARIABLE_ARGS, doc='EBB arguments')
jump = Instruction( jump = Instruction(
'jump', r""" 'jump', r"""
@@ -98,7 +99,7 @@ trapnz = Instruction(
""", """,
ins=c) ins=c)
rvals = Operand('rvals', variable_args, doc='return values') rvals = Operand('rvals', VARIABLE_ARGS, doc='return values')
x_return = Instruction( x_return = Instruction(
'return', r""" 'return', r"""
@@ -114,7 +115,7 @@ FN = Operand(
'FN', 'FN',
entities.func_ref, entities.func_ref,
doc='function to call, declared by :inst:`function`') doc='function to call, declared by :inst:`function`')
args = Operand('args', variable_args, doc='call arguments') args = Operand('args', VARIABLE_ARGS, doc='call arguments')
call = Instruction( call = Instruction(
'call', r""" 'call', r"""

View File

@@ -4,7 +4,7 @@ operand types. There are corresponding definitions in the `cretonne.entities`
Rust module. Rust module.
""" """
from __future__ import absolute_import from __future__ import absolute_import
from . import EntityRefKind from cdsl.operands import EntityRefKind
#: A reference to an extended basic block in the same function. #: A reference to an extended basic block in the same function.

View File

@@ -6,51 +6,52 @@ Rust representation of cretonne IL, so all instruction formats must be defined
in this module. in this module.
""" """
from __future__ import absolute_import from __future__ import absolute_import
from . import InstructionFormat, value, variable_args from cdsl.operands import VALUE, VARIABLE_ARGS
from . import InstructionFormat
from .immediates import imm64, uimm8, ieee32, ieee64, immvector, intcc, floatcc from .immediates import imm64, uimm8, ieee32, ieee64, immvector, intcc, floatcc
from .entities import ebb, sig_ref, func_ref, jump_table from .entities import ebb, sig_ref, func_ref, jump_table
Nullary = InstructionFormat() Nullary = InstructionFormat()
Unary = InstructionFormat(value) Unary = InstructionFormat(VALUE)
UnaryImm = InstructionFormat(imm64) UnaryImm = InstructionFormat(imm64)
UnaryIeee32 = InstructionFormat(ieee32) UnaryIeee32 = InstructionFormat(ieee32)
UnaryIeee64 = InstructionFormat(ieee64) UnaryIeee64 = InstructionFormat(ieee64)
UnaryImmVector = InstructionFormat(immvector, boxed_storage=True) UnaryImmVector = InstructionFormat(immvector, boxed_storage=True)
UnarySplit = InstructionFormat(value, multiple_results=True) UnarySplit = InstructionFormat(VALUE, multiple_results=True)
Binary = InstructionFormat(value, value) Binary = InstructionFormat(VALUE, VALUE)
BinaryImm = InstructionFormat(value, imm64) BinaryImm = InstructionFormat(VALUE, imm64)
BinaryImmRev = InstructionFormat(imm64, value) BinaryImmRev = InstructionFormat(imm64, VALUE)
# Generate result + overflow flag. # Generate result + overflow flag.
BinaryOverflow = InstructionFormat(value, value, multiple_results=True) BinaryOverflow = InstructionFormat(VALUE, VALUE, multiple_results=True)
# The select instructions are controlled by the second value operand. # The select instructions are controlled by the second VALUE operand.
# The first value operand is the controlling flag which has a derived type. # The first VALUE operand is the controlling flag which has a derived type.
# The fma instruction has the same constraint on all inputs. # The fma instruction has the same constraint on all inputs.
Ternary = InstructionFormat(value, value, value, typevar_operand=1) Ternary = InstructionFormat(VALUE, VALUE, VALUE, typevar_operand=1)
# Carry in *and* carry out for `iadd_carry` and friends. # Carry in *and* carry out for `iadd_carry` and friends.
TernaryOverflow = InstructionFormat( TernaryOverflow = InstructionFormat(
value, value, value, multiple_results=True, boxed_storage=True) VALUE, VALUE, VALUE, multiple_results=True, boxed_storage=True)
InsertLane = InstructionFormat(value, ('lane', uimm8), value) InsertLane = InstructionFormat(VALUE, ('lane', uimm8), VALUE)
ExtractLane = InstructionFormat(value, ('lane', uimm8)) ExtractLane = InstructionFormat(VALUE, ('lane', uimm8))
IntCompare = InstructionFormat(intcc, value, value) IntCompare = InstructionFormat(intcc, VALUE, VALUE)
FloatCompare = InstructionFormat(floatcc, value, value) FloatCompare = InstructionFormat(floatcc, VALUE, VALUE)
Jump = InstructionFormat(ebb, variable_args, boxed_storage=True) Jump = InstructionFormat(ebb, VARIABLE_ARGS, boxed_storage=True)
Branch = InstructionFormat(value, ebb, variable_args, boxed_storage=True) Branch = InstructionFormat(VALUE, ebb, VARIABLE_ARGS, boxed_storage=True)
BranchTable = InstructionFormat(value, jump_table) BranchTable = InstructionFormat(VALUE, jump_table)
Call = InstructionFormat( Call = InstructionFormat(
func_ref, variable_args, multiple_results=True, boxed_storage=True) func_ref, VARIABLE_ARGS, multiple_results=True, boxed_storage=True)
IndirectCall = InstructionFormat( IndirectCall = InstructionFormat(
sig_ref, value, variable_args, sig_ref, VALUE, VARIABLE_ARGS,
multiple_results=True, boxed_storage=True) multiple_results=True, boxed_storage=True)
Return = InstructionFormat(variable_args, boxed_storage=True) Return = InstructionFormat(VARIABLE_ARGS, boxed_storage=True)
# Finally extract the names of global variables in this module. # Finally extract the names of global variables in this module.

View File

@@ -3,7 +3,7 @@ The `cretonne.immediates` module predefines all the Cretonne immediate operand
types. types.
""" """
from __future__ import absolute_import from __future__ import absolute_import
from . import ImmediateKind from cdsl.operands import ImmediateKind
#: A 64-bit immediate integer operand. #: A 64-bit immediate integer operand.
#: #:

View File

@@ -6,7 +6,7 @@ polymorphic by using type variables.
""" """
from __future__ import absolute_import from __future__ import absolute_import
import math import math
import cretonne import cdsl.operands
try: try:
from typing import Tuple, Union # noqa from typing import Tuple, Union # noqa
@@ -315,11 +315,11 @@ class TypeVar(object):
return TypeVar(None, None, base=self, derived_func='DoubleWidth') return TypeVar(None, None, base=self, derived_func='DoubleWidth')
def operand_kind(self): def operand_kind(self):
# type: () -> cretonne.OperandKind # type: () -> cdsl.operands.OperandKind
# When a `TypeVar` object is used to describe the type of an `Operand` # When a `TypeVar` object is used to describe the type of an `Operand`
# in an instruction definition, the kind of that operand is an SSA # in an instruction definition, the kind of that operand is an SSA
# value. # value.
return cretonne.value # type: ignore return cdsl.operands.VALUE
def free_typevar(self): def free_typevar(self):
# type: () -> TypeVar # type: () -> TypeVar

View File

@@ -6,6 +6,7 @@ import srcgen
import constant_hash import constant_hash
from unique_table import UniqueTable, UniqueSeqTable from unique_table import UniqueTable, UniqueSeqTable
import cdsl.types import cdsl.types
import cdsl.operands
import cretonne import cretonne
@@ -56,7 +57,7 @@ def gen_arguments_method(fmt, is_mut):
with fmt.indented('match *self {', '}'): with fmt.indented('match *self {', '}'):
for f in cretonne.InstructionFormat.all_formats: for f in cretonne.InstructionFormat.all_formats:
n = 'InstructionData::' + f.name n = 'InstructionData::' + f.name
has_varargs = cretonne.variable_args in f.kinds has_varargs = cdsl.operands.VARIABLE_ARGS in f.kinds
# Formats with both fixed and variable arguments delegate to # Formats with both fixed and variable arguments delegate to
# the data struct. We need to work around borrow checker quirks # the data struct. We need to work around borrow checker quirks
# when extracting two mutable references. # when extracting two mutable references.
@@ -84,7 +85,7 @@ def gen_arguments_method(fmt, is_mut):
capture = 'ref {}args, '.format(mut) capture = 'ref {}args, '.format(mut)
arg = 'args' arg = 'args'
# Varargs. # Varargs.
if cretonne.variable_args in f.kinds: if cdsl.operands.VARIABLE_ARGS in f.kinds:
varg = '&{}data.varargs'.format(mut) varg = '&{}data.varargs'.format(mut)
capture = 'ref {}data, '.format(mut) capture = 'ref {}data, '.format(mut)
else: else:
@@ -311,7 +312,7 @@ def get_constraint(op, ctrl_typevar, type_sets):
- `Free(idx)` where `idx` is an index into `type_sets`. - `Free(idx)` where `idx` is an index into `type_sets`.
- `Same`, `Lane`, `AsBool` for controlling typevar-derived constraints. - `Same`, `Lane`, `AsBool` for controlling typevar-derived constraints.
""" """
assert op.kind is cretonne.value assert op.kind is cdsl.operands.VALUE
t = op.typ t = op.typ
# A concrete value type. # A concrete value type.
@@ -504,7 +505,7 @@ def gen_inst_builder(inst, fmt):
tmpl_types = list() tmpl_types = list()
into_args = list() into_args = list()
for op in inst.ins: for op in inst.ins:
if isinstance(op.kind, cretonne.ImmediateKind): if isinstance(op.kind, cdsl.operands.ImmediateKind):
t = 'T{}{}'.format(1 + len(tmpl_types), op.kind.name) t = 'T{}{}'.format(1 + len(tmpl_types), op.kind.name)
tmpl_types.append('{}: Into<{}>'.format(t, op.kind.rust_type)) tmpl_types.append('{}: Into<{}>'.format(t, op.kind.rust_type))
into_args.append(op.name) into_args.append(op.name)