Split out instruction definitions.
- cdsl.instructions defines the Instruction class. - base.instructions defines the base instruction set.
This commit is contained in:
@@ -269,7 +269,7 @@ class InstDocumenter(sphinx.ext.autodoc.Documenter):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def resolve_name(self, modname, parents, path, base):
|
def resolve_name(self, modname, parents, path, base):
|
||||||
return 'cretonne.base', [base]
|
return 'base.instructions', [base]
|
||||||
|
|
||||||
def format_signature(self):
|
def format_signature(self):
|
||||||
inst = self.object
|
inst = self.object
|
||||||
|
|||||||
@@ -849,7 +849,7 @@ Base instruction group
|
|||||||
All of the shared instructions are part of the :instgroup:`base` instruction
|
All of the shared instructions are part of the :instgroup:`base` instruction
|
||||||
group.
|
group.
|
||||||
|
|
||||||
.. autoinstgroup:: cretonne.base.instructions
|
.. autoinstgroup:: base.instructions.GROUP
|
||||||
|
|
||||||
Target ISAs may define further instructions in their own instruction groups.
|
Target ISAs may define further instructions in their own instruction groups.
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ a module looks like this::
|
|||||||
Instruction descriptions
|
Instruction descriptions
|
||||||
========================
|
========================
|
||||||
|
|
||||||
.. currentmodule:: cretonne
|
.. module:: cdsl.instructions
|
||||||
|
|
||||||
New instructions are defined as instances of the :class:`Instruction`
|
New instructions are defined as instances of the :class:`Instruction`
|
||||||
class. As instruction instances are created, they are added to the currently
|
class. As instruction instances are created, they are added to the currently
|
||||||
@@ -81,12 +81,14 @@ open :class:`InstructionGroup`.
|
|||||||
:members:
|
:members:
|
||||||
|
|
||||||
The basic Cretonne instruction set described in :doc:`langref` is defined by the
|
The basic Cretonne instruction set described in :doc:`langref` is defined by the
|
||||||
Python module :mod:`cretonne.base`. This module has a global variable
|
Python module :mod:`base.instructions`. This module has a global variable
|
||||||
:data:`cretonne.base.instructions` which is an :class:`InstructionGroup`
|
:data:`base.instructions.GROUP` which is an :class:`InstructionGroup` instance
|
||||||
instance containing all the base instructions.
|
containing all the base instructions.
|
||||||
|
|
||||||
.. autoclass:: Instruction
|
.. autoclass:: Instruction
|
||||||
|
|
||||||
|
.. currentmodule:: cdsl.operands
|
||||||
|
|
||||||
An instruction is defined with a set of distinct input and output operands which
|
An instruction is defined with a set of distinct input and output operands which
|
||||||
must be instances of the :class:`Operand` class.
|
must be instances of the :class:`Operand` class.
|
||||||
|
|
||||||
@@ -201,7 +203,7 @@ represent SSA values:
|
|||||||
.. autodata:: VALUE
|
.. autodata:: VALUE
|
||||||
.. autodata:: VARIABLE_ARGS
|
.. autodata:: VARIABLE_ARGS
|
||||||
|
|
||||||
.. currentmodule:: cretonne
|
.. module:: cdsl.formats
|
||||||
|
|
||||||
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
|
||||||
@@ -253,6 +255,8 @@ controlling type variable, or it can vary independently of the other operands.
|
|||||||
Encodings
|
Encodings
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
.. currentmodule:: cretonne
|
||||||
|
|
||||||
Encodings describe how Cretonne instructions are mapped to binary machine code
|
Encodings describe how Cretonne instructions are mapped to binary machine code
|
||||||
for the target architecture. After the legalization pass, all remaining
|
for the target architecture. After the legalization pass, all remaining
|
||||||
instructions are expected to map 1-1 to native instruction encodings. Cretonne
|
instructions are expected to map 1-1 to native instruction encodings. Cretonne
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ This module defines the basic Cretonne instruction set that all targets
|
|||||||
support.
|
support.
|
||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from cdsl.operands import VARIABLE_ARGS
|
from cdsl.operands import Operand, VARIABLE_ARGS
|
||||||
from cdsl.typevar import TypeVar
|
from cdsl.typevar import TypeVar
|
||||||
from . import Operand, Instruction, InstructionGroup
|
from cdsl.instructions import Instruction, InstructionGroup
|
||||||
from base.types import i8, f32, f64, b1
|
from base.types import i8, f32, f64, b1
|
||||||
from base.immediates import imm64, uimm8, ieee32, ieee64, immvector
|
from base.immediates import imm64, uimm8, ieee32, ieee64, immvector
|
||||||
from base.immediates import intcc, floatcc
|
from base.immediates import intcc, floatcc
|
||||||
from base import entities
|
from base import entities
|
||||||
import base.formats # noqa
|
import base.formats # noqa
|
||||||
|
|
||||||
instructions = InstructionGroup("base", "Shared base instruction set")
|
GROUP = InstructionGroup("base", "Shared base instruction set")
|
||||||
|
|
||||||
Int = TypeVar('Int', 'A scalar or vector integer type', ints=True, simd=True)
|
Int = TypeVar('Int', 'A scalar or vector integer type', ints=True, simd=True)
|
||||||
iB = TypeVar('iB', 'A scalar integer type', ints=True)
|
iB = TypeVar('iB', 'A scalar integer type', ints=True)
|
||||||
@@ -1213,4 +1213,4 @@ iconcat_lohi = Instruction(
|
|||||||
""",
|
""",
|
||||||
ins=(lo, hi), outs=a)
|
ins=(lo, hi), outs=a)
|
||||||
|
|
||||||
instructions.close()
|
GROUP.close()
|
||||||
316
lib/cretonne/meta/cdsl/instructions.py
Normal file
316
lib/cretonne/meta/cdsl/instructions.py
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
"""Classes for defining instructions."""
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from . import camel_case
|
||||||
|
from .types import ValueType
|
||||||
|
from .operands import Operand
|
||||||
|
from .formats import InstructionFormat
|
||||||
|
|
||||||
|
try:
|
||||||
|
from typing import Union, Sequence
|
||||||
|
# List of operands for ins/outs:
|
||||||
|
OpList = Union[Sequence[Operand], Operand]
|
||||||
|
MaybeBoundInst = Union['Instruction', 'BoundInstruction']
|
||||||
|
from typing import Tuple, Any # noqa
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InstructionGroup(object):
|
||||||
|
"""
|
||||||
|
Every instruction must belong to exactly one instruction group. A given
|
||||||
|
target architecture can support instructions from multiple groups, and it
|
||||||
|
does not necessarily support all instructions in a group.
|
||||||
|
|
||||||
|
New instructions are automatically added to the currently open instruction
|
||||||
|
group.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# The currently open instruction group.
|
||||||
|
_current = None # type: InstructionGroup
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
# type: () -> None
|
||||||
|
"""
|
||||||
|
Open this instruction group such that future new instructions are
|
||||||
|
added to this group.
|
||||||
|
"""
|
||||||
|
assert InstructionGroup._current is None, (
|
||||||
|
"Can't open {} since {} is already open"
|
||||||
|
.format(self, InstructionGroup._current))
|
||||||
|
InstructionGroup._current = self
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
# type: () -> None
|
||||||
|
"""
|
||||||
|
Close this instruction group. This function should be called before
|
||||||
|
opening another instruction group.
|
||||||
|
"""
|
||||||
|
assert InstructionGroup._current is self, (
|
||||||
|
"Can't close {}, the open instuction group is {}"
|
||||||
|
.format(self, InstructionGroup._current))
|
||||||
|
InstructionGroup._current = None
|
||||||
|
|
||||||
|
def __init__(self, name, doc):
|
||||||
|
# type: (str, str) -> None
|
||||||
|
self.name = name
|
||||||
|
self.__doc__ = doc
|
||||||
|
self.instructions = [] # type: List[Instruction]
|
||||||
|
self.open()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def append(inst):
|
||||||
|
# type: (Instruction) -> None
|
||||||
|
assert InstructionGroup._current, \
|
||||||
|
"Open an instruction group before defining instructions."
|
||||||
|
InstructionGroup._current.instructions.append(inst)
|
||||||
|
|
||||||
|
|
||||||
|
class Instruction(object):
|
||||||
|
"""
|
||||||
|
The operands to the instruction are specified as two tuples: ``ins`` and
|
||||||
|
``outs``. Since the Python singleton tuple syntax is a bit awkward, it is
|
||||||
|
allowed to specify a singleton as just the operand itself, i.e., `ins=x`
|
||||||
|
and `ins=(x,)` are both allowed and mean the same thing.
|
||||||
|
|
||||||
|
:param name: Instruction mnemonic, also becomes opcode name.
|
||||||
|
:param doc: Documentation string.
|
||||||
|
:param ins: Tuple of input operands. This can be a mix of SSA value
|
||||||
|
operands and other operand kinds.
|
||||||
|
:param outs: Tuple of output operands. The output operands must be SSA
|
||||||
|
values or `variable_args`.
|
||||||
|
:param is_terminator: This is a terminator instruction.
|
||||||
|
:param is_branch: This is a branch instruction.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name, doc, ins=(), outs=(), **kwargs):
|
||||||
|
# type: (str, str, OpList, OpList, **Any) -> None # noqa
|
||||||
|
self.name = name
|
||||||
|
self.camel_name = camel_case(name)
|
||||||
|
self.__doc__ = doc
|
||||||
|
self.ins = self._to_operand_tuple(ins)
|
||||||
|
self.outs = self._to_operand_tuple(outs)
|
||||||
|
self.format = InstructionFormat.lookup(self.ins, self.outs)
|
||||||
|
# Indexes into outs for value results. Others are `variable_args`.
|
||||||
|
self.value_results = tuple(
|
||||||
|
i for i, o in enumerate(self.outs) if o.is_value())
|
||||||
|
self._verify_polymorphic()
|
||||||
|
InstructionGroup.append(self)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
prefix = ', '.join(o.name for o in self.outs)
|
||||||
|
if prefix:
|
||||||
|
prefix = prefix + ' = '
|
||||||
|
suffix = ', '.join(o.name for o in self.ins)
|
||||||
|
return '{}{} {}'.format(prefix, self.name, suffix)
|
||||||
|
|
||||||
|
def snake_name(self):
|
||||||
|
# type: () -> str
|
||||||
|
"""
|
||||||
|
Get the snake_case name of this instruction.
|
||||||
|
|
||||||
|
Keywords in Rust and Python are altered by appending a '_'
|
||||||
|
"""
|
||||||
|
if self.name == 'return':
|
||||||
|
return 'return_'
|
||||||
|
else:
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def blurb(self):
|
||||||
|
"""Get the first line of the doc comment"""
|
||||||
|
for line in self.__doc__.split('\n'):
|
||||||
|
line = line.strip()
|
||||||
|
if line:
|
||||||
|
return line
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def _verify_polymorphic(self):
|
||||||
|
"""
|
||||||
|
Check if this instruction is polymorphic, and verify its use of type
|
||||||
|
variables.
|
||||||
|
"""
|
||||||
|
poly_ins = [
|
||||||
|
i for i in self.format.value_operands
|
||||||
|
if self.ins[i].typ.free_typevar()]
|
||||||
|
poly_outs = [
|
||||||
|
i for i, o in enumerate(self.outs)
|
||||||
|
if o.typ.free_typevar()]
|
||||||
|
self.is_polymorphic = len(poly_ins) > 0 or len(poly_outs) > 0
|
||||||
|
if not self.is_polymorphic:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Prefer to use the typevar_operand to infer the controlling typevar.
|
||||||
|
self.use_typevar_operand = False
|
||||||
|
typevar_error = None
|
||||||
|
if self.format.typevar_operand is not None:
|
||||||
|
try:
|
||||||
|
tv = self.ins[self.format.typevar_operand].typ
|
||||||
|
if tv is tv.free_typevar():
|
||||||
|
self.other_typevars = self._verify_ctrl_typevar(tv)
|
||||||
|
self.ctrl_typevar = tv
|
||||||
|
self.use_typevar_operand = True
|
||||||
|
except RuntimeError as e:
|
||||||
|
typevar_error = e
|
||||||
|
|
||||||
|
if not self.use_typevar_operand:
|
||||||
|
# The typevar_operand argument doesn't work. Can we infer from the
|
||||||
|
# first result instead?
|
||||||
|
if len(self.outs) == 0:
|
||||||
|
if typevar_error:
|
||||||
|
raise typevar_error
|
||||||
|
else:
|
||||||
|
raise RuntimeError(
|
||||||
|
"typevar_operand must be a free type variable")
|
||||||
|
tv = self.outs[0].typ
|
||||||
|
if tv is not tv.free_typevar():
|
||||||
|
raise RuntimeError("first result must be a free type variable")
|
||||||
|
self.other_typevars = self._verify_ctrl_typevar(tv)
|
||||||
|
self.ctrl_typevar = tv
|
||||||
|
|
||||||
|
def _verify_ctrl_typevar(self, ctrl_typevar):
|
||||||
|
"""
|
||||||
|
Verify that the use of TypeVars is consistent with `ctrl_typevar` as
|
||||||
|
the controlling type variable.
|
||||||
|
|
||||||
|
All polymorhic inputs must either be derived from `ctrl_typevar` or be
|
||||||
|
independent free type variables only used once.
|
||||||
|
|
||||||
|
All polymorphic results must be derived from `ctrl_typevar`.
|
||||||
|
|
||||||
|
Return list of other type variables used, or raise an error.
|
||||||
|
"""
|
||||||
|
other_tvs = []
|
||||||
|
# Check value inputs.
|
||||||
|
for opidx in self.format.value_operands:
|
||||||
|
typ = self.ins[opidx].typ
|
||||||
|
tv = typ.free_typevar()
|
||||||
|
# Non-polymorphic or derived form ctrl_typevar is OK.
|
||||||
|
if tv is None or tv is ctrl_typevar:
|
||||||
|
continue
|
||||||
|
# No other derived typevars allowed.
|
||||||
|
if typ is not tv:
|
||||||
|
raise RuntimeError(
|
||||||
|
"{}: type variable {} must be derived from {}"
|
||||||
|
.format(self.ins[opidx], typ.name, ctrl_typevar))
|
||||||
|
# Other free type variables can only be used once each.
|
||||||
|
if tv in other_tvs:
|
||||||
|
raise RuntimeError(
|
||||||
|
"type variable {} can't be used more than once"
|
||||||
|
.format(tv.name))
|
||||||
|
other_tvs.append(tv)
|
||||||
|
|
||||||
|
# Check outputs.
|
||||||
|
for result in self.outs:
|
||||||
|
typ = result.typ
|
||||||
|
tv = typ.free_typevar()
|
||||||
|
# Non-polymorphic or derived from ctrl_typevar is OK.
|
||||||
|
if tv is None or tv is ctrl_typevar:
|
||||||
|
continue
|
||||||
|
raise RuntimeError(
|
||||||
|
"type variable in output not derived from ctrl_typevar")
|
||||||
|
|
||||||
|
return other_tvs
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _to_operand_tuple(x):
|
||||||
|
# type: (Union[Sequence[Operand], Operand]) -> Tuple[Operand, ...]
|
||||||
|
# Allow a single Operand instance instead of the awkward singleton
|
||||||
|
# tuple syntax.
|
||||||
|
if isinstance(x, Operand):
|
||||||
|
x = (x,)
|
||||||
|
else:
|
||||||
|
x = tuple(x)
|
||||||
|
for op in x:
|
||||||
|
assert isinstance(op, Operand)
|
||||||
|
return x
|
||||||
|
|
||||||
|
def bind(self, *args):
|
||||||
|
# type: (*ValueType) -> BoundInstruction
|
||||||
|
"""
|
||||||
|
Bind a polymorphic instruction to a concrete list of type variable
|
||||||
|
values.
|
||||||
|
"""
|
||||||
|
assert self.is_polymorphic
|
||||||
|
return BoundInstruction(self, args)
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
# type: (str) -> BoundInstruction
|
||||||
|
"""
|
||||||
|
Bind a polymorphic instruction to a single type variable with dot
|
||||||
|
syntax:
|
||||||
|
|
||||||
|
>>> iadd.i32
|
||||||
|
"""
|
||||||
|
return self.bind(ValueType.by_name(name))
|
||||||
|
|
||||||
|
def fully_bound(self):
|
||||||
|
# type: () -> Tuple[Instruction, Tuple[ValueType, ...]]
|
||||||
|
"""
|
||||||
|
Verify that all typevars have been bound, and return a
|
||||||
|
`(inst, typevars)` pair.
|
||||||
|
|
||||||
|
This version in `Instruction` itself allows non-polymorphic
|
||||||
|
instructions to duck-type as `BoundInstruction`\s.
|
||||||
|
"""
|
||||||
|
assert not self.is_polymorphic, self
|
||||||
|
return (self, ())
|
||||||
|
|
||||||
|
def __call__(self, *args):
|
||||||
|
"""
|
||||||
|
Create an `ast.Apply` AST node representing the application of this
|
||||||
|
instruction to the arguments.
|
||||||
|
"""
|
||||||
|
from cretonne.ast import Apply
|
||||||
|
return Apply(self, args)
|
||||||
|
|
||||||
|
|
||||||
|
class BoundInstruction(object):
|
||||||
|
"""
|
||||||
|
A polymorphic `Instruction` bound to concrete type variables.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, inst, typevars):
|
||||||
|
# type: (Instruction, Tuple[ValueType, ...]) -> None
|
||||||
|
self.inst = inst
|
||||||
|
self.typevars = typevars
|
||||||
|
assert len(typevars) <= 1 + len(inst.other_typevars)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '.'.join([self.inst.name, ] + list(map(str, self.typevars)))
|
||||||
|
|
||||||
|
def bind(self, *args):
|
||||||
|
# type: (*ValueType) -> BoundInstruction
|
||||||
|
"""
|
||||||
|
Bind additional typevars.
|
||||||
|
"""
|
||||||
|
return BoundInstruction(self.inst, self.typevars + args)
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
# type: (str) -> BoundInstruction
|
||||||
|
"""
|
||||||
|
Bind an additional typevar dot syntax:
|
||||||
|
|
||||||
|
>>> uext.i32.i8
|
||||||
|
"""
|
||||||
|
return self.bind(ValueType.by_name(name))
|
||||||
|
|
||||||
|
def fully_bound(self):
|
||||||
|
# type: () -> Tuple[Instruction, Tuple[ValueType, ...]]
|
||||||
|
"""
|
||||||
|
Verify that all typevars have been bound, and return a
|
||||||
|
`(inst, typevars)` pair.
|
||||||
|
"""
|
||||||
|
if len(self.typevars) < 1 + len(self.inst.other_typevars):
|
||||||
|
unb = ', '.join(
|
||||||
|
str(tv) for tv in
|
||||||
|
self.inst.other_typevars[len(self.typevars) - 1:])
|
||||||
|
raise AssertionError("Unbound typevar {} in {}".format(unb, self))
|
||||||
|
assert len(self.typevars) == 1 + len(self.inst.other_typevars)
|
||||||
|
return (self.inst, self.typevars)
|
||||||
|
|
||||||
|
def __call__(self, *args):
|
||||||
|
"""
|
||||||
|
Create an `ast.Apply` AST node representing the application of this
|
||||||
|
instruction to the arguments.
|
||||||
|
"""
|
||||||
|
from cretonne.ast import Apply
|
||||||
|
return Apply(self, args)
|
||||||
@@ -6,19 +6,15 @@ instructions.
|
|||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
import importlib
|
import importlib
|
||||||
from cdsl import camel_case
|
|
||||||
from cdsl.predicates import And
|
from cdsl.predicates import And
|
||||||
from cdsl.types import ValueType
|
|
||||||
from cdsl.typevar import TypeVar
|
from cdsl.typevar import TypeVar
|
||||||
from cdsl.operands import Operand
|
|
||||||
from cdsl.formats import InstructionFormat
|
|
||||||
|
|
||||||
# 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.
|
||||||
try:
|
try:
|
||||||
from typing import Tuple, Union, Any, Iterable, Sequence, TYPE_CHECKING # noqa
|
from typing import Tuple, Union, Any, Iterable, Sequence, TYPE_CHECKING # noqa
|
||||||
from cdsl.predicates import Predicate, FieldPredicate # noqa
|
from cdsl.predicates import Predicate, FieldPredicate # noqa
|
||||||
MaybeBoundInst = Union['Instruction', 'BoundInstruction']
|
from cdsl.instructions import MaybeBoundInst # noqa
|
||||||
AnyPredicate = Union['Predicate', 'FieldPredicate']
|
AnyPredicate = Union['Predicate', 'FieldPredicate']
|
||||||
except ImportError:
|
except ImportError:
|
||||||
TYPE_CHECKING = False
|
TYPE_CHECKING = False
|
||||||
@@ -27,310 +23,6 @@ if TYPE_CHECKING:
|
|||||||
from cdsl.typevar import TypeVar # noqa
|
from cdsl.typevar import TypeVar # noqa
|
||||||
|
|
||||||
|
|
||||||
# Defining instructions.
|
|
||||||
|
|
||||||
|
|
||||||
class InstructionGroup(object):
|
|
||||||
"""
|
|
||||||
Every instruction must belong to exactly one instruction group. A given
|
|
||||||
target architecture can support instructions from multiple groups, and it
|
|
||||||
does not necessarily support all instructions in a group.
|
|
||||||
|
|
||||||
New instructions are automatically added to the currently open instruction
|
|
||||||
group.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# The currently open instruction group.
|
|
||||||
_current = None # type: InstructionGroup
|
|
||||||
|
|
||||||
def open(self):
|
|
||||||
# type: () -> None
|
|
||||||
"""
|
|
||||||
Open this instruction group such that future new instructions are
|
|
||||||
added to this group.
|
|
||||||
"""
|
|
||||||
assert InstructionGroup._current is None, (
|
|
||||||
"Can't open {} since {} is already open"
|
|
||||||
.format(self, InstructionGroup._current))
|
|
||||||
InstructionGroup._current = self
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
# type: () -> None
|
|
||||||
"""
|
|
||||||
Close this instruction group. This function should be called before
|
|
||||||
opening another instruction group.
|
|
||||||
"""
|
|
||||||
assert InstructionGroup._current is self, (
|
|
||||||
"Can't close {}, the open instuction group is {}"
|
|
||||||
.format(self, InstructionGroup._current))
|
|
||||||
InstructionGroup._current = None
|
|
||||||
|
|
||||||
def __init__(self, name, doc):
|
|
||||||
# type: (str, str) -> None
|
|
||||||
self.name = name
|
|
||||||
self.__doc__ = doc
|
|
||||||
self.instructions = [] # type: List[Instruction]
|
|
||||||
self.open()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def append(inst):
|
|
||||||
# type: (Instruction) -> None
|
|
||||||
assert InstructionGroup._current, \
|
|
||||||
"Open an instruction group before defining instructions."
|
|
||||||
InstructionGroup._current.instructions.append(inst)
|
|
||||||
|
|
||||||
|
|
||||||
class Instruction(object):
|
|
||||||
"""
|
|
||||||
The operands to the instruction are specified as two tuples: ``ins`` and
|
|
||||||
``outs``. Since the Python singleton tuple syntax is a bit awkward, it is
|
|
||||||
allowed to specify a singleton as just the operand itself, i.e., `ins=x`
|
|
||||||
and `ins=(x,)` are both allowed and mean the same thing.
|
|
||||||
|
|
||||||
:param name: Instruction mnemonic, also becomes opcode name.
|
|
||||||
:param doc: Documentation string.
|
|
||||||
:param ins: Tuple of input operands. This can be a mix of SSA value
|
|
||||||
operands and other operand kinds.
|
|
||||||
:param outs: Tuple of output operands. The output operands must be SSA
|
|
||||||
values or `variable_args`.
|
|
||||||
:param is_terminator: This is a terminator instruction.
|
|
||||||
:param is_branch: This is a branch instruction.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, name, doc, ins=(), outs=(), **kwargs):
|
|
||||||
# type: (str, str, Union[Sequence[Operand], Operand], Union[Sequence[Operand], Operand], **Any) -> None # noqa
|
|
||||||
self.name = name
|
|
||||||
self.camel_name = camel_case(name)
|
|
||||||
self.__doc__ = doc
|
|
||||||
self.ins = self._to_operand_tuple(ins)
|
|
||||||
self.outs = self._to_operand_tuple(outs)
|
|
||||||
self.format = InstructionFormat.lookup(self.ins, self.outs)
|
|
||||||
# Indexes into outs for value results. Others are `variable_args`.
|
|
||||||
self.value_results = tuple(
|
|
||||||
i for i, o in enumerate(self.outs) if o.is_value())
|
|
||||||
self._verify_polymorphic()
|
|
||||||
InstructionGroup.append(self)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
prefix = ', '.join(o.name for o in self.outs)
|
|
||||||
if prefix:
|
|
||||||
prefix = prefix + ' = '
|
|
||||||
suffix = ', '.join(o.name for o in self.ins)
|
|
||||||
return '{}{} {}'.format(prefix, self.name, suffix)
|
|
||||||
|
|
||||||
def snake_name(self):
|
|
||||||
# type: () -> str
|
|
||||||
"""
|
|
||||||
Get the snake_case name of this instruction.
|
|
||||||
|
|
||||||
Keywords in Rust and Python are altered by appending a '_'
|
|
||||||
"""
|
|
||||||
if self.name == 'return':
|
|
||||||
return 'return_'
|
|
||||||
else:
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def blurb(self):
|
|
||||||
"""Get the first line of the doc comment"""
|
|
||||||
for line in self.__doc__.split('\n'):
|
|
||||||
line = line.strip()
|
|
||||||
if line:
|
|
||||||
return line
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def _verify_polymorphic(self):
|
|
||||||
"""
|
|
||||||
Check if this instruction is polymorphic, and verify its use of type
|
|
||||||
variables.
|
|
||||||
"""
|
|
||||||
poly_ins = [
|
|
||||||
i for i in self.format.value_operands
|
|
||||||
if self.ins[i].typ.free_typevar()]
|
|
||||||
poly_outs = [
|
|
||||||
i for i, o in enumerate(self.outs)
|
|
||||||
if o.typ.free_typevar()]
|
|
||||||
self.is_polymorphic = len(poly_ins) > 0 or len(poly_outs) > 0
|
|
||||||
if not self.is_polymorphic:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Prefer to use the typevar_operand to infer the controlling typevar.
|
|
||||||
self.use_typevar_operand = False
|
|
||||||
typevar_error = None
|
|
||||||
if self.format.typevar_operand is not None:
|
|
||||||
try:
|
|
||||||
tv = self.ins[self.format.typevar_operand].typ
|
|
||||||
if tv is tv.free_typevar():
|
|
||||||
self.other_typevars = self._verify_ctrl_typevar(tv)
|
|
||||||
self.ctrl_typevar = tv
|
|
||||||
self.use_typevar_operand = True
|
|
||||||
except RuntimeError as e:
|
|
||||||
typevar_error = e
|
|
||||||
|
|
||||||
if not self.use_typevar_operand:
|
|
||||||
# The typevar_operand argument doesn't work. Can we infer from the
|
|
||||||
# first result instead?
|
|
||||||
if len(self.outs) == 0:
|
|
||||||
if typevar_error:
|
|
||||||
raise typevar_error
|
|
||||||
else:
|
|
||||||
raise RuntimeError(
|
|
||||||
"typevar_operand must be a free type variable")
|
|
||||||
tv = self.outs[0].typ
|
|
||||||
if tv is not tv.free_typevar():
|
|
||||||
raise RuntimeError("first result must be a free type variable")
|
|
||||||
self.other_typevars = self._verify_ctrl_typevar(tv)
|
|
||||||
self.ctrl_typevar = tv
|
|
||||||
|
|
||||||
def _verify_ctrl_typevar(self, ctrl_typevar):
|
|
||||||
"""
|
|
||||||
Verify that the use of TypeVars is consistent with `ctrl_typevar` as
|
|
||||||
the controlling type variable.
|
|
||||||
|
|
||||||
All polymorhic inputs must either be derived from `ctrl_typevar` or be
|
|
||||||
independent free type variables only used once.
|
|
||||||
|
|
||||||
All polymorphic results must be derived from `ctrl_typevar`.
|
|
||||||
|
|
||||||
Return list of other type variables used, or raise an error.
|
|
||||||
"""
|
|
||||||
other_tvs = []
|
|
||||||
# Check value inputs.
|
|
||||||
for opidx in self.format.value_operands:
|
|
||||||
typ = self.ins[opidx].typ
|
|
||||||
tv = typ.free_typevar()
|
|
||||||
# Non-polymorphic or derived form ctrl_typevar is OK.
|
|
||||||
if tv is None or tv is ctrl_typevar:
|
|
||||||
continue
|
|
||||||
# No other derived typevars allowed.
|
|
||||||
if typ is not tv:
|
|
||||||
raise RuntimeError(
|
|
||||||
"{}: type variable {} must be derived from {}"
|
|
||||||
.format(self.ins[opidx], typ.name, ctrl_typevar))
|
|
||||||
# Other free type variables can only be used once each.
|
|
||||||
if tv in other_tvs:
|
|
||||||
raise RuntimeError(
|
|
||||||
"type variable {} can't be used more than once"
|
|
||||||
.format(tv.name))
|
|
||||||
other_tvs.append(tv)
|
|
||||||
|
|
||||||
# Check outputs.
|
|
||||||
for result in self.outs:
|
|
||||||
typ = result.typ
|
|
||||||
tv = typ.free_typevar()
|
|
||||||
# Non-polymorphic or derived from ctrl_typevar is OK.
|
|
||||||
if tv is None or tv is ctrl_typevar:
|
|
||||||
continue
|
|
||||||
raise RuntimeError(
|
|
||||||
"type variable in output not derived from ctrl_typevar")
|
|
||||||
|
|
||||||
return other_tvs
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _to_operand_tuple(x):
|
|
||||||
# type: (Union[Sequence[Operand], Operand]) -> Tuple[Operand, ...]
|
|
||||||
# Allow a single Operand instance instead of the awkward singleton
|
|
||||||
# tuple syntax.
|
|
||||||
if isinstance(x, Operand):
|
|
||||||
x = (x,)
|
|
||||||
else:
|
|
||||||
x = tuple(x)
|
|
||||||
for op in x:
|
|
||||||
assert isinstance(op, Operand)
|
|
||||||
return x
|
|
||||||
|
|
||||||
def bind(self, *args):
|
|
||||||
# type: (*ValueType) -> BoundInstruction
|
|
||||||
"""
|
|
||||||
Bind a polymorphic instruction to a concrete list of type variable
|
|
||||||
values.
|
|
||||||
"""
|
|
||||||
assert self.is_polymorphic
|
|
||||||
return BoundInstruction(self, args)
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
# type: (str) -> BoundInstruction
|
|
||||||
"""
|
|
||||||
Bind a polymorphic instruction to a single type variable with dot
|
|
||||||
syntax:
|
|
||||||
|
|
||||||
>>> iadd.i32
|
|
||||||
"""
|
|
||||||
return self.bind(ValueType.by_name(name))
|
|
||||||
|
|
||||||
def fully_bound(self):
|
|
||||||
# type: () -> Tuple[Instruction, Tuple[ValueType, ...]]
|
|
||||||
"""
|
|
||||||
Verify that all typevars have been bound, and return a
|
|
||||||
`(inst, typevars)` pair.
|
|
||||||
|
|
||||||
This version in `Instruction` itself allows non-polymorphic
|
|
||||||
instructions to duck-type as `BoundInstruction`\s.
|
|
||||||
"""
|
|
||||||
assert not self.is_polymorphic, self
|
|
||||||
return (self, ())
|
|
||||||
|
|
||||||
def __call__(self, *args):
|
|
||||||
"""
|
|
||||||
Create an `ast.Apply` AST node representing the application of this
|
|
||||||
instruction to the arguments.
|
|
||||||
"""
|
|
||||||
from .ast import Apply
|
|
||||||
return Apply(self, args)
|
|
||||||
|
|
||||||
|
|
||||||
class BoundInstruction(object):
|
|
||||||
"""
|
|
||||||
A polymorphic `Instruction` bound to concrete type variables.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, inst, typevars):
|
|
||||||
# type: (Instruction, Tuple[ValueType, ...]) -> None
|
|
||||||
self.inst = inst
|
|
||||||
self.typevars = typevars
|
|
||||||
assert len(typevars) <= 1 + len(inst.other_typevars)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '.'.join([self.inst.name, ] + list(map(str, self.typevars)))
|
|
||||||
|
|
||||||
def bind(self, *args):
|
|
||||||
# type: (*ValueType) -> BoundInstruction
|
|
||||||
"""
|
|
||||||
Bind additional typevars.
|
|
||||||
"""
|
|
||||||
return BoundInstruction(self.inst, self.typevars + args)
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
# type: (str) -> BoundInstruction
|
|
||||||
"""
|
|
||||||
Bind an additional typevar dot syntax:
|
|
||||||
|
|
||||||
>>> uext.i32.i8
|
|
||||||
"""
|
|
||||||
return self.bind(ValueType.by_name(name))
|
|
||||||
|
|
||||||
def fully_bound(self):
|
|
||||||
# type: () -> Tuple[Instruction, Tuple[ValueType, ...]]
|
|
||||||
"""
|
|
||||||
Verify that all typevars have been bound, and return a
|
|
||||||
`(inst, typevars)` pair.
|
|
||||||
"""
|
|
||||||
if len(self.typevars) < 1 + len(self.inst.other_typevars):
|
|
||||||
unb = ', '.join(
|
|
||||||
str(tv) for tv in
|
|
||||||
self.inst.other_typevars[len(self.typevars) - 1:])
|
|
||||||
raise AssertionError("Unbound typevar {} in {}".format(unb, self))
|
|
||||||
assert len(self.typevars) == 1 + len(self.inst.other_typevars)
|
|
||||||
return (self.inst, self.typevars)
|
|
||||||
|
|
||||||
def __call__(self, *args):
|
|
||||||
"""
|
|
||||||
Create an `ast.Apply` AST node representing the application of this
|
|
||||||
instruction to the arguments.
|
|
||||||
"""
|
|
||||||
from .ast import Apply
|
|
||||||
return Apply(self, args)
|
|
||||||
|
|
||||||
|
|
||||||
# Defining target ISAs.
|
# Defining target ISAs.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ This module defines classes that can be used to create abstract syntax trees
|
|||||||
for patern matching an rewriting of cretonne instructions.
|
for patern matching an rewriting of cretonne instructions.
|
||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
import cretonne
|
from cdsl import instructions
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from typing import Union, Tuple # noqa
|
from typing import Union, Tuple # noqa
|
||||||
@@ -20,7 +20,7 @@ class Def(object):
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
>>> from .base import iadd_cout, iconst
|
>>> from base.instructions import iadd_cout, iconst
|
||||||
>>> x = Var('x')
|
>>> x = Var('x')
|
||||||
>>> y = Var('y')
|
>>> y = Var('y')
|
||||||
>>> x << iconst(4)
|
>>> x << iconst(4)
|
||||||
@@ -162,7 +162,7 @@ class Apply(Expr):
|
|||||||
instructions. This applies to both bound and unbound polymorphic
|
instructions. This applies to both bound and unbound polymorphic
|
||||||
instructions:
|
instructions:
|
||||||
|
|
||||||
>>> from .base import jump, iadd
|
>>> from base.instructions import jump, iadd
|
||||||
>>> jump('next', ())
|
>>> jump('next', ())
|
||||||
Apply(jump, ('next', ()))
|
Apply(jump, ('next', ()))
|
||||||
>>> iadd.i32('x', 'y')
|
>>> iadd.i32('x', 'y')
|
||||||
@@ -174,12 +174,12 @@ class Apply(Expr):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, inst, args):
|
def __init__(self, inst, args):
|
||||||
# type: (Union[cretonne.Instruction, cretonne.BoundInstruction], Tuple[Expr, ...]) -> None # noqa
|
# type: (instructions.MaybeBoundInst, Tuple[Expr, ...]) -> None # noqa
|
||||||
if isinstance(inst, cretonne.BoundInstruction):
|
if isinstance(inst, instructions.BoundInstruction):
|
||||||
self.inst = inst.inst
|
self.inst = inst.inst
|
||||||
self.typevars = inst.typevars
|
self.typevars = inst.typevars
|
||||||
else:
|
else:
|
||||||
assert isinstance(inst, cretonne.Instruction)
|
assert isinstance(inst, instructions.Instruction)
|
||||||
self.inst = inst
|
self.inst = inst
|
||||||
self.typevars = ()
|
self.typevars = ()
|
||||||
self.args = args
|
self.args = args
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ 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 .base import iadd, iadd_cout, iadd_cin, iadd_carry
|
from base.instructions import iadd, iadd_cout, iadd_cin, iadd_carry
|
||||||
from .base import isub, isub_bin, isub_bout, isub_borrow
|
from base.instructions import isub, isub_bin, isub_bout, isub_borrow
|
||||||
from .base import band, bor, bxor, isplit_lohi, iconcat_lohi
|
from base.instructions import band, bor, bxor, isplit_lohi, iconcat_lohi
|
||||||
from .base import icmp
|
from base.instructions import icmp
|
||||||
from .ast import Var
|
from .ast import Var
|
||||||
from .xform import Rtl, XFormGroup
|
from .xform import Rtl, XFormGroup
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from __future__ import absolute_import
|
|||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from doctest import DocTestSuite
|
from doctest import DocTestSuite
|
||||||
from . import ast
|
from . import ast
|
||||||
from .base import jump, iadd
|
from base.instructions import jump, iadd
|
||||||
|
|
||||||
|
|
||||||
def load_tests(loader, tests, ignore):
|
def load_tests(loader, tests, ignore):
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from doctest import DocTestSuite
|
from doctest import DocTestSuite
|
||||||
|
from base.instructions import iadd, iadd_imm, iconst
|
||||||
from . import xform
|
from . import xform
|
||||||
from .base import iadd, iadd_imm, iconst
|
|
||||||
from .ast import Var
|
from .ast import Var
|
||||||
from .xform import Rtl, XForm
|
from .xform import Rtl, XForm
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class XForm(object):
|
|||||||
A legalization pattern must have a source pattern containing only a single
|
A legalization pattern must have a source pattern containing only a single
|
||||||
instruction.
|
instruction.
|
||||||
|
|
||||||
>>> from .base import iconst, iadd, iadd_imm
|
>>> from base.instructions import iconst, iadd, iadd_imm
|
||||||
>>> a = Var('a')
|
>>> a = Var('a')
|
||||||
>>> c = Var('c')
|
>>> c = Var('c')
|
||||||
>>> v = Var('v')
|
>>> v = Var('v')
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ 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 cdsl.operands
|
||||||
import cretonne
|
from cdsl.formats import InstructionFormat
|
||||||
|
|
||||||
|
|
||||||
def gen_formats(fmt):
|
def gen_formats(fmt):
|
||||||
@@ -21,7 +21,7 @@ def gen_formats(fmt):
|
|||||||
fmt.doc_comment('and the `InstructionData` enums.')
|
fmt.doc_comment('and the `InstructionData` enums.')
|
||||||
fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug)]')
|
fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug)]')
|
||||||
with fmt.indented('pub enum InstructionFormat {', '}'):
|
with fmt.indented('pub enum InstructionFormat {', '}'):
|
||||||
for f in cretonne.InstructionFormat.all_formats:
|
for f in InstructionFormat.all_formats:
|
||||||
fmt.doc_comment(str(f))
|
fmt.doc_comment(str(f))
|
||||||
fmt.line(f.name + ',')
|
fmt.line(f.name + ',')
|
||||||
fmt.line()
|
fmt.line()
|
||||||
@@ -34,7 +34,7 @@ def gen_formats(fmt):
|
|||||||
"fn from(inst: &'a InstructionData) -> InstructionFormat {",
|
"fn from(inst: &'a InstructionData) -> InstructionFormat {",
|
||||||
'}'):
|
'}'):
|
||||||
with fmt.indented('match *inst {', '}'):
|
with fmt.indented('match *inst {', '}'):
|
||||||
for f in cretonne.InstructionFormat.all_formats:
|
for f in InstructionFormat.all_formats:
|
||||||
fmt.line(('InstructionData::{} {{ .. }} => ' +
|
fmt.line(('InstructionData::{} {{ .. }} => ' +
|
||||||
'InstructionFormat::{},')
|
'InstructionFormat::{},')
|
||||||
.format(f.name, f.name))
|
.format(f.name, f.name))
|
||||||
@@ -55,7 +55,7 @@ def gen_arguments_method(fmt, is_mut):
|
|||||||
'pub fn {f}(&{m}self) -> [&{m}[Value]; 2] {{'
|
'pub fn {f}(&{m}self) -> [&{m}[Value]; 2] {{'
|
||||||
.format(f=method, m=mut), '}'):
|
.format(f=method, m=mut), '}'):
|
||||||
with fmt.indented('match *self {', '}'):
|
with fmt.indented('match *self {', '}'):
|
||||||
for f in cretonne.InstructionFormat.all_formats:
|
for f in InstructionFormat.all_formats:
|
||||||
n = 'InstructionData::' + f.name
|
n = 'InstructionData::' + f.name
|
||||||
has_varargs = cdsl.operands.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
|
||||||
@@ -118,7 +118,7 @@ def gen_instruction_data_impl(fmt):
|
|||||||
fmt.doc_comment('Get the opcode of this instruction.')
|
fmt.doc_comment('Get the opcode of this instruction.')
|
||||||
with fmt.indented('pub fn opcode(&self) -> Opcode {', '}'):
|
with fmt.indented('pub fn opcode(&self) -> Opcode {', '}'):
|
||||||
with fmt.indented('match *self {', '}'):
|
with fmt.indented('match *self {', '}'):
|
||||||
for f in cretonne.InstructionFormat.all_formats:
|
for f in InstructionFormat.all_formats:
|
||||||
fmt.line(
|
fmt.line(
|
||||||
'InstructionData::{} {{ opcode, .. }} => opcode,'
|
'InstructionData::{} {{ opcode, .. }} => opcode,'
|
||||||
.format(f.name))
|
.format(f.name))
|
||||||
@@ -126,7 +126,7 @@ def gen_instruction_data_impl(fmt):
|
|||||||
fmt.doc_comment('Type of the first result, or `VOID`.')
|
fmt.doc_comment('Type of the first result, or `VOID`.')
|
||||||
with fmt.indented('pub fn first_type(&self) -> Type {', '}'):
|
with fmt.indented('pub fn first_type(&self) -> Type {', '}'):
|
||||||
with fmt.indented('match *self {', '}'):
|
with fmt.indented('match *self {', '}'):
|
||||||
for f in cretonne.InstructionFormat.all_formats:
|
for f in InstructionFormat.all_formats:
|
||||||
fmt.line(
|
fmt.line(
|
||||||
'InstructionData::{} {{ ty, .. }} => ty,'
|
'InstructionData::{} {{ ty, .. }} => ty,'
|
||||||
.format(f.name))
|
.format(f.name))
|
||||||
@@ -135,7 +135,7 @@ def gen_instruction_data_impl(fmt):
|
|||||||
with fmt.indented(
|
with fmt.indented(
|
||||||
'pub fn first_type_mut(&mut self) -> &mut Type {', '}'):
|
'pub fn first_type_mut(&mut self) -> &mut Type {', '}'):
|
||||||
with fmt.indented('match *self {', '}'):
|
with fmt.indented('match *self {', '}'):
|
||||||
for f in cretonne.InstructionFormat.all_formats:
|
for f in InstructionFormat.all_formats:
|
||||||
fmt.line(
|
fmt.line(
|
||||||
'InstructionData::{} {{ ref mut ty, .. }} => ty,'
|
'InstructionData::{} {{ ref mut ty, .. }} => ty,'
|
||||||
.format(f.name))
|
.format(f.name))
|
||||||
@@ -147,7 +147,7 @@ def gen_instruction_data_impl(fmt):
|
|||||||
with fmt.indented(
|
with fmt.indented(
|
||||||
'pub fn second_result(&self) -> Option<Value> {', '}'):
|
'pub fn second_result(&self) -> Option<Value> {', '}'):
|
||||||
with fmt.indented('match *self {', '}'):
|
with fmt.indented('match *self {', '}'):
|
||||||
for f in cretonne.InstructionFormat.all_formats:
|
for f in InstructionFormat.all_formats:
|
||||||
if f.multiple_results:
|
if f.multiple_results:
|
||||||
fmt.line(
|
fmt.line(
|
||||||
'InstructionData::' + f.name +
|
'InstructionData::' + f.name +
|
||||||
@@ -164,7 +164,7 @@ def gen_instruction_data_impl(fmt):
|
|||||||
"pub fn second_result_mut<'a>(&'a mut self)" +
|
"pub fn second_result_mut<'a>(&'a mut self)" +
|
||||||
" -> Option<&'a mut Value> {", '}'):
|
" -> Option<&'a mut Value> {", '}'):
|
||||||
with fmt.indented('match *self {', '}'):
|
with fmt.indented('match *self {', '}'):
|
||||||
for f in cretonne.InstructionFormat.all_formats:
|
for f in InstructionFormat.all_formats:
|
||||||
if f.multiple_results:
|
if f.multiple_results:
|
||||||
fmt.line(
|
fmt.line(
|
||||||
'InstructionData::' + f.name +
|
'InstructionData::' + f.name +
|
||||||
@@ -180,7 +180,7 @@ def gen_instruction_data_impl(fmt):
|
|||||||
with fmt.indented(
|
with fmt.indented(
|
||||||
'pub fn typevar_operand(&self) -> Option<Value> {', '}'):
|
'pub fn typevar_operand(&self) -> Option<Value> {', '}'):
|
||||||
with fmt.indented('match *self {', '}'):
|
with fmt.indented('match *self {', '}'):
|
||||||
for f in cretonne.InstructionFormat.all_formats:
|
for f in InstructionFormat.all_formats:
|
||||||
n = 'InstructionData::' + f.name
|
n = 'InstructionData::' + f.name
|
||||||
if f.typevar_operand is None:
|
if f.typevar_operand is None:
|
||||||
fmt.line(n + ' { .. } => None,')
|
fmt.line(n + ' { .. } => None,')
|
||||||
@@ -612,7 +612,7 @@ def gen_builder(insts, fmt):
|
|||||||
"pub trait InstBuilder<'f>: InstBuilderBase<'f> {", '}'):
|
"pub trait InstBuilder<'f>: InstBuilderBase<'f> {", '}'):
|
||||||
for inst in insts:
|
for inst in insts:
|
||||||
gen_inst_builder(inst, fmt)
|
gen_inst_builder(inst, fmt)
|
||||||
for f in cretonne.InstructionFormat.all_formats:
|
for f in InstructionFormat.all_formats:
|
||||||
gen_format_constructor(f, fmt)
|
gen_format_constructor(f, fmt)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ from __future__ import absolute_import
|
|||||||
import srcgen
|
import srcgen
|
||||||
from unique_table import UniqueSeqTable
|
from unique_table import UniqueSeqTable
|
||||||
import constant_hash
|
import constant_hash
|
||||||
|
from cdsl import camel_case
|
||||||
from cdsl.settings import BoolSetting, NumSetting, EnumSetting
|
from cdsl.settings import BoolSetting, NumSetting, EnumSetting
|
||||||
from cretonne import camel_case
|
|
||||||
from base import settings
|
from base import settings
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ Commonly used definitions.
|
|||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from cretonne import TargetISA, CPUMode
|
from cretonne import TargetISA, CPUMode
|
||||||
import cretonne.base
|
import base.instructions
|
||||||
|
|
||||||
isa = TargetISA('riscv', [cretonne.base.instructions])
|
isa = TargetISA('riscv', [base.instructions.GROUP])
|
||||||
|
|
||||||
# CPU modes for 32-bit and 64-bit operation.
|
# CPU modes for 32-bit and 64-bit operation.
|
||||||
RV32 = CPUMode('RV32', isa)
|
RV32 = CPUMode('RV32', isa)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
RISC-V Encodings.
|
RISC-V Encodings.
|
||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from cretonne import base
|
from base import instructions as base
|
||||||
from .defs import RV32, RV64
|
from .defs import RV32, RV64
|
||||||
from .recipes import OPIMM, OPIMM32, OP, OP32, R, Rshamt, I
|
from .recipes import OPIMM, OPIMM32, OP, OP32, R, Rshamt, I
|
||||||
from .settings import use_m
|
from .settings import use_m
|
||||||
|
|||||||
Reference in New Issue
Block a user