diff --git a/docs/metaref.rst b/docs/metaref.rst index cfb39b00ad..4699a80a43 100644 --- a/docs/metaref.rst +++ b/docs/metaref.rst @@ -127,13 +127,14 @@ There are some practical restrictions on the use of type variables, see Immediate operands ------------------ +.. currentmodule:: cdsl.operands + Immediate instruction operands don't correspond to SSA values, but have values that are encoded directly in the instruction. Immediate operands don't 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 indicated with an instance of :class:`ImmediateKind`. -.. currentmodule:: cretonne .. autoclass:: ImmediateKind .. automodule:: cretonne.immediates @@ -145,8 +146,7 @@ Entity references 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. -.. currentmodule:: cretonne - +.. currentmodule:: cdsl.operands .. autoclass:: EntityRefKind .. automodule:: cretonne.entities @@ -183,7 +183,7 @@ the :func:`ScalarType.by` function. Instruction representation ========================== -.. currentmodule:: cretonne +.. module:: cdsl.operands The Rust in-memory representation of instructions is derived from the 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 represent SSA values: -.. autodata:: value -.. autodata:: variable_args +.. autodata:: VALUE +.. autodata:: VARIABLE_ARGS + +.. currentmodule:: cretonne When an instruction description is created, it is automatically assigned a predefined instruction format which is an instance of diff --git a/lib/cretonne/meta/cdsl/__init__.py b/lib/cretonne/meta/cdsl/__init__.py index 417f800950..247b970675 100644 --- a/lib/cretonne/meta/cdsl/__init__.py +++ b/lib/cretonne/meta/cdsl/__init__.py @@ -4,3 +4,14 @@ Cretonne DSL classes. This module defines the classes that are used to define Cretonne instructions 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) diff --git a/lib/cretonne/meta/cdsl/operands.py b/lib/cretonne/meta/cdsl/operands.py new file mode 100644 index 0000000000..33157d9e23 --- /dev/null +++ b/lib/cretonne/meta/cdsl/operands.py @@ -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) diff --git a/lib/cretonne/meta/cretonne/__init__.py b/lib/cretonne/meta/cretonne/__init__.py index d2d4386de5..d6b9835443 100644 --- a/lib/cretonne/meta/cretonne/__init__.py +++ b/lib/cretonne/meta/cretonne/__init__.py @@ -5,10 +5,11 @@ This module provides classes and functions used to describe Cretonne instructions. """ from __future__ import absolute_import -import re import importlib +from cdsl import camel_case from cdsl.predicates import And 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 # outside type comments. @@ -25,116 +26,6 @@ if TYPE_CHECKING: 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. @@ -215,7 +106,7 @@ class Operand(object): self.__doc__ = doc self.typ = typ if isinstance(typ, cdsl.types.ValueType): - self.kind = value + self.kind = VALUE else: self.kind = typ.operand_kind() @@ -235,7 +126,7 @@ class Operand(object): """ Is this an SSA value operand? """ - return self.kind is value + return self.kind is cdsl.operands.VALUE class InstructionFormat(object): @@ -285,12 +176,12 @@ class InstructionFormat(object): # Which of self.kinds are `value`? 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. self.typevar_operand = kwargs.get('typevar_operand', None) # type: int 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" elif len(self.value_operands) > 0: # Default to the first 'value' operand, if there is one. @@ -361,7 +252,7 @@ class InstructionFormat(object): tuples of :py:`Operand` objects. """ if len(outs) == 1: - multiple_results = outs[0].kind == variable_args + multiple_results = outs[0].kind == VARIABLE_ARGS else: multiple_results = len(outs) > 1 sig = (multiple_results, tuple(op.kind for op in ins)) diff --git a/lib/cretonne/meta/cretonne/base.py b/lib/cretonne/meta/cretonne/base.py index d991228872..e2ceadaff4 100644 --- a/lib/cretonne/meta/cretonne/base.py +++ b/lib/cretonne/meta/cretonne/base.py @@ -5,7 +5,8 @@ This module defines the basic Cretonne instruction set that all targets support. """ 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 base.types import i8, f32, f64, b1 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') 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', r""" @@ -98,7 +99,7 @@ trapnz = Instruction( """, ins=c) -rvals = Operand('rvals', variable_args, doc='return values') +rvals = Operand('rvals', VARIABLE_ARGS, doc='return values') x_return = Instruction( 'return', r""" @@ -114,7 +115,7 @@ FN = Operand( 'FN', entities.func_ref, 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', r""" diff --git a/lib/cretonne/meta/cretonne/entities.py b/lib/cretonne/meta/cretonne/entities.py index afeeea7e98..327d45e8bc 100644 --- a/lib/cretonne/meta/cretonne/entities.py +++ b/lib/cretonne/meta/cretonne/entities.py @@ -4,7 +4,7 @@ operand types. There are corresponding definitions in the `cretonne.entities` Rust module. """ from __future__ import absolute_import -from . import EntityRefKind +from cdsl.operands import EntityRefKind #: A reference to an extended basic block in the same function. diff --git a/lib/cretonne/meta/cretonne/formats.py b/lib/cretonne/meta/cretonne/formats.py index cb8aed3f98..a4d012020d 100644 --- a/lib/cretonne/meta/cretonne/formats.py +++ b/lib/cretonne/meta/cretonne/formats.py @@ -6,51 +6,52 @@ Rust representation of cretonne IL, so all instruction formats must be defined in this module. """ 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 .entities import ebb, sig_ref, func_ref, jump_table Nullary = InstructionFormat() -Unary = InstructionFormat(value) +Unary = InstructionFormat(VALUE) UnaryImm = InstructionFormat(imm64) UnaryIeee32 = InstructionFormat(ieee32) UnaryIeee64 = InstructionFormat(ieee64) UnaryImmVector = InstructionFormat(immvector, boxed_storage=True) -UnarySplit = InstructionFormat(value, multiple_results=True) +UnarySplit = InstructionFormat(VALUE, multiple_results=True) -Binary = InstructionFormat(value, value) -BinaryImm = InstructionFormat(value, imm64) -BinaryImmRev = InstructionFormat(imm64, value) +Binary = InstructionFormat(VALUE, VALUE) +BinaryImm = InstructionFormat(VALUE, imm64) +BinaryImmRev = InstructionFormat(imm64, VALUE) # 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 first value operand is the controlling flag which has a derived type. +# The select instructions are controlled by the second VALUE operand. +# The first VALUE operand is the controlling flag which has a derived type. # 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. 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) -ExtractLane = InstructionFormat(value, ('lane', uimm8)) +InsertLane = InstructionFormat(VALUE, ('lane', uimm8), VALUE) +ExtractLane = InstructionFormat(VALUE, ('lane', uimm8)) -IntCompare = InstructionFormat(intcc, value, value) -FloatCompare = InstructionFormat(floatcc, value, value) +IntCompare = InstructionFormat(intcc, VALUE, VALUE) +FloatCompare = InstructionFormat(floatcc, VALUE, VALUE) -Jump = InstructionFormat(ebb, variable_args, boxed_storage=True) -Branch = InstructionFormat(value, ebb, variable_args, boxed_storage=True) -BranchTable = InstructionFormat(value, jump_table) +Jump = InstructionFormat(ebb, VARIABLE_ARGS, boxed_storage=True) +Branch = InstructionFormat(VALUE, ebb, VARIABLE_ARGS, boxed_storage=True) +BranchTable = InstructionFormat(VALUE, jump_table) Call = InstructionFormat( - func_ref, variable_args, multiple_results=True, boxed_storage=True) + func_ref, VARIABLE_ARGS, multiple_results=True, boxed_storage=True) IndirectCall = InstructionFormat( - sig_ref, value, variable_args, + sig_ref, VALUE, VARIABLE_ARGS, 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. diff --git a/lib/cretonne/meta/cretonne/immediates.py b/lib/cretonne/meta/cretonne/immediates.py index 34b81dc79d..565dd26850 100644 --- a/lib/cretonne/meta/cretonne/immediates.py +++ b/lib/cretonne/meta/cretonne/immediates.py @@ -3,7 +3,7 @@ The `cretonne.immediates` module predefines all the Cretonne immediate operand types. """ from __future__ import absolute_import -from . import ImmediateKind +from cdsl.operands import ImmediateKind #: A 64-bit immediate integer operand. #: diff --git a/lib/cretonne/meta/cretonne/typevar.py b/lib/cretonne/meta/cretonne/typevar.py index a6d8d9637f..7f58ce73c1 100644 --- a/lib/cretonne/meta/cretonne/typevar.py +++ b/lib/cretonne/meta/cretonne/typevar.py @@ -6,7 +6,7 @@ polymorphic by using type variables. """ from __future__ import absolute_import import math -import cretonne +import cdsl.operands try: from typing import Tuple, Union # noqa @@ -315,11 +315,11 @@ class TypeVar(object): return TypeVar(None, None, base=self, derived_func='DoubleWidth') def operand_kind(self): - # type: () -> cretonne.OperandKind + # type: () -> cdsl.operands.OperandKind # 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 # value. - return cretonne.value # type: ignore + return cdsl.operands.VALUE def free_typevar(self): # type: () -> TypeVar diff --git a/lib/cretonne/meta/gen_instr.py b/lib/cretonne/meta/gen_instr.py index d7afcf1887..aae46b5652 100644 --- a/lib/cretonne/meta/gen_instr.py +++ b/lib/cretonne/meta/gen_instr.py @@ -6,6 +6,7 @@ import srcgen import constant_hash from unique_table import UniqueTable, UniqueSeqTable import cdsl.types +import cdsl.operands import cretonne @@ -56,7 +57,7 @@ def gen_arguments_method(fmt, is_mut): with fmt.indented('match *self {', '}'): for f in cretonne.InstructionFormat.all_formats: 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 # the data struct. We need to work around borrow checker quirks # when extracting two mutable references. @@ -84,7 +85,7 @@ def gen_arguments_method(fmt, is_mut): capture = 'ref {}args, '.format(mut) arg = 'args' # Varargs. - if cretonne.variable_args in f.kinds: + if cdsl.operands.VARIABLE_ARGS in f.kinds: varg = '&{}data.varargs'.format(mut) capture = 'ref {}data, '.format(mut) else: @@ -311,7 +312,7 @@ def get_constraint(op, ctrl_typevar, type_sets): - `Free(idx)` where `idx` is an index into `type_sets`. - `Same`, `Lane`, `AsBool` for controlling typevar-derived constraints. """ - assert op.kind is cretonne.value + assert op.kind is cdsl.operands.VALUE t = op.typ # A concrete value type. @@ -504,7 +505,7 @@ def gen_inst_builder(inst, fmt): tmpl_types = list() into_args = list() 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) tmpl_types.append('{}: Into<{}>'.format(t, op.kind.rust_type)) into_args.append(op.name)