moved crates in lib/ to src/, renamed crates, modified some files' text (#660)
moved crates in lib/ to src/, renamed crates, modified some files' text (#660)
This commit is contained in:
251
cranelift/codegen/meta-python/cdsl/operands.py
Normal file
251
cranelift/codegen/meta-python/cdsl/operands.py
Normal file
@@ -0,0 +1,251 @@
|
||||
"""Classes for describing instruction operands."""
|
||||
from __future__ import absolute_import
|
||||
from . import camel_case
|
||||
from .types import ValueType
|
||||
from .typevar import TypeVar
|
||||
|
||||
try:
|
||||
from typing import Union, Dict, TYPE_CHECKING, Iterable # noqa
|
||||
OperandSpec = Union['OperandKind', ValueType, TypeVar]
|
||||
if TYPE_CHECKING:
|
||||
from .ast import Enumerator, ConstantInt, ConstantBits, Literal # noqa
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
# 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 ('ir::' + camel_case(name))
|
||||
|
||||
def __str__(self):
|
||||
# type: () -> str
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
# type: () -> str
|
||||
return 'OperandKind({})'.format(self.name)
|
||||
|
||||
|
||||
#: 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 arguments passed to a function call, arguments
|
||||
passed to an extended basic block, or a variable number of results
|
||||
returned from an instruction.
|
||||
""",
|
||||
rust_type='&[Value]')
|
||||
|
||||
|
||||
# Instances of immediate operand types are provided in the
|
||||
# `cranelift.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,
|
||||
values=None):
|
||||
# type: (str, str, str, str, Dict[str, str]) -> None
|
||||
if rust_type is None:
|
||||
rust_type = 'ir::immediates::' + camel_case(name)
|
||||
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 __call__(self, value):
|
||||
# type: (int) -> ConstantInt
|
||||
"""
|
||||
Create an AST node representing a constant integer:
|
||||
|
||||
iconst(imm64(0))
|
||||
"""
|
||||
from .ast import ConstantInt # noqa
|
||||
if self.values:
|
||||
raise AssertionError(
|
||||
"{}({}): Can't make a constant numeric value for an enum"
|
||||
.format(self.name, value))
|
||||
return ConstantInt(self, value)
|
||||
|
||||
def bits(self, bits):
|
||||
# type: (int) -> ConstantBits
|
||||
"""
|
||||
Create an AST literal node for the given bitwise representation of this
|
||||
immediate operand kind.
|
||||
"""
|
||||
from .ast import ConstantBits # noqa
|
||||
return ConstantBits(self, bits)
|
||||
|
||||
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])
|
||||
|
||||
def is_enumerable(self):
|
||||
# type: () -> bool
|
||||
return self.values is not None
|
||||
|
||||
def possible_values(self):
|
||||
# type: () -> Iterable[Literal]
|
||||
from cdsl.ast import Enumerator # noqa
|
||||
assert self.is_enumerable()
|
||||
for v in self.values.keys():
|
||||
yield Enumerator(self, v)
|
||||
|
||||
|
||||
# Instances of entity reference operand types are provided in the
|
||||
# `cranelift.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)
|
||||
|
||||
|
||||
class Operand(object):
|
||||
"""
|
||||
An instruction operand can be an *immediate*, an *SSA value*, or an *entity
|
||||
reference*. The type of the operand is one of:
|
||||
|
||||
1. A :py:class:`ValueType` instance indicates an SSA value operand with a
|
||||
concrete type.
|
||||
|
||||
2. A :py:class:`TypeVar` instance indicates an SSA value operand, and the
|
||||
instruction is polymorphic over the possible concrete types that the
|
||||
type variable can assume.
|
||||
|
||||
3. An :py:class:`ImmediateKind` instance indicates an immediate operand
|
||||
whose value is encoded in the instruction itself rather than being
|
||||
passed as an SSA value.
|
||||
|
||||
4. An :py:class:`EntityRefKind` instance indicates an operand that
|
||||
references another entity in the function, typically something declared
|
||||
in the function preamble.
|
||||
|
||||
"""
|
||||
def __init__(self, name, typ, doc=''):
|
||||
# type: (str, OperandSpec, str) -> None
|
||||
self.name = name
|
||||
self.__doc__ = doc
|
||||
|
||||
# Decode the operand spec and set self.kind.
|
||||
# Only VALUE operands have a typevar member.
|
||||
if isinstance(typ, ValueType):
|
||||
self.kind = VALUE
|
||||
self.typevar = TypeVar.singleton(typ)
|
||||
elif isinstance(typ, TypeVar):
|
||||
self.kind = VALUE
|
||||
self.typevar = typ
|
||||
else:
|
||||
assert isinstance(typ, OperandKind)
|
||||
self.kind = typ
|
||||
|
||||
def get_doc(self):
|
||||
# type: () -> str
|
||||
if self.__doc__:
|
||||
return self.__doc__
|
||||
if self.kind is VALUE:
|
||||
return self.typevar.__doc__
|
||||
return self.kind.__doc__
|
||||
|
||||
def __str__(self):
|
||||
# type: () -> str
|
||||
return "`{}`".format(self.name)
|
||||
|
||||
def is_value(self):
|
||||
# type: () -> bool
|
||||
"""
|
||||
Is this an SSA value operand?
|
||||
"""
|
||||
return self.kind is VALUE
|
||||
|
||||
def is_varargs(self):
|
||||
# type: () -> bool
|
||||
"""
|
||||
Is this a VARIABLE_ARGS operand?
|
||||
"""
|
||||
return self.kind is VARIABLE_ARGS
|
||||
|
||||
def is_immediate(self):
|
||||
# type: () -> bool
|
||||
"""
|
||||
Is this an immediate operand?
|
||||
|
||||
Note that this includes both `ImmediateKind` operands *and* entity
|
||||
references. It is any operand that doesn't represent a value
|
||||
dependency.
|
||||
"""
|
||||
return self.kind is not VALUE and self.kind is not VARIABLE_ARGS
|
||||
|
||||
def is_cpu_flags(self):
|
||||
# type: () -> bool
|
||||
"""
|
||||
Is this a CPU flags operand?
|
||||
"""
|
||||
return self.kind is VALUE and self.typevar.name in ['iflags', 'fflags']
|
||||
Reference in New Issue
Block a user