From 20183554a4b49b71794e7c022fd5b2ae4a7b9a2f Mon Sep 17 00:00:00 2001 From: Jakob Olesen Date: Fri, 12 Feb 2016 14:24:01 -0800 Subject: [PATCH] Add Instruction and Operand classes to the meta language. --- cranelift/docs/cton_domain.py | 44 +++++++++++++++++++++ cranelift/docs/metaref.rst | 9 +++++ meta/cretonne/__init__.py | 72 ++++++++++++++++++++++++++++++++++- 3 files changed, 124 insertions(+), 1 deletion(-) diff --git a/cranelift/docs/cton_domain.py b/cranelift/docs/cton_domain.py index 823ed9c8a5..6f20cf8d32 100644 --- a/cranelift/docs/cton_domain.py +++ b/cranelift/docs/cton_domain.py @@ -242,8 +242,52 @@ class TypeDocumenter(sphinx.ext.autodoc.Documenter): self.add_line(u':bytes: Can\'t be stored in memory', sourcename) +class InstDocumenter(sphinx.ext.autodoc.Documenter): + # Invoke with .. autoinst:: + objtype = 'inst' + # Convert into cton:inst directives + domain = 'cton' + directivetype = 'inst' + + @classmethod + def can_document_member(cls, member, membername, isattr, parent): + return False + + def resolve_name(self, modname, parents, path, base): + return 'cretonne.base', [ base ] + + def format_signature(self): + inst = self.object + sig = self.format_name() + if len(inst.outs) > 0: + sig = ', '.join([op.name for op in inst.outs]) + ' = ' + sig + if len(inst.ins) > 0: + sig = sig + ' ' + ', '.join([op.name for op in inst.ins]) + return sig + + def add_directive_header(self, sig): + """Add the directive header and options to the generated content.""" + domain = getattr(self, 'domain', 'cton') + directive = getattr(self, 'directivetype', self.objtype) + sourcename = self.get_sourcename() + self.add_line(u'.. %s:%s:: %s' % (domain, directive, sig), sourcename) + if self.options.noindex: + self.add_line(u' :noindex:', sourcename) + + def add_content(self, more_content, no_docstring=False): + super(InstDocumenter, self).add_content(more_content, no_docstring) + sourcename = self.get_sourcename() + + # Add inputs and outputs. + for op in self.object.ins: + self.add_line(u':in {} {}: {}'.format(op.typ.name, op.name, op.get_doc()), sourcename) + for op in self.object.outs: + self.add_line(u':out {} {}: {}'.format(op.typ.name, op.name, op.get_doc()), sourcename) + + def setup(app): app.add_domain(CretonneDomain) app.add_autodocumenter(TypeDocumenter) + app.add_autodocumenter(InstDocumenter) return { 'version' : '0.1' } diff --git a/cranelift/docs/metaref.rst b/cranelift/docs/metaref.rst index b4dda9576d..8d58757b81 100644 --- a/cranelift/docs/metaref.rst +++ b/cranelift/docs/metaref.rst @@ -63,3 +63,12 @@ indicated with an instance of :class:`ImmediateType`. :members: .. currentmodule:: cretonne + +Instructions +============ + +New instructions are defined as instances of the :class:`cretonne.Instruction` +class. + +.. autoclass:: Operand +.. autoclass:: Instruction diff --git a/meta/cretonne/__init__.py b/meta/cretonne/__init__.py index 60c3748106..fd0c4664dd 100644 --- a/meta/cretonne/__init__.py +++ b/meta/cretonne/__init__.py @@ -107,8 +107,9 @@ class TypeVar(object): instructions. This makes the instructions *polymorphic*. """ - def __init__(self, name): + def __init__(self, name, doc): self.name = name + self.__doc__ = doc # # Immediate operands. @@ -130,3 +131,72 @@ class ImmediateType(object): def __repr__(self): return 'ImmediateType({})'.format(self.name) + +# +# Defining instructions. +# + +class Operand(object): + """ + An instruction operand. + + An instruction operand can be either an *immediate* or an *SSA value*. The + type of the operand is one of: + + 1. A :py:class:`Type` 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:`ImmediateType` instance indicates an immediate operand + whose value is encoded in the instruction itself rather than being passed + as an SSA value. + + """ + def __init__(self, name, typ, doc=''): + self.name = name + self.typ = typ + self.__doc__ = doc + + def get_doc(self): + if self.__doc__: + return self.__doc__ + else: + return self.typ.__doc__ + +class Instruction(object): + """ + An instruction. + + 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 immediate operands. + :param outs: Tuple of output operands. The output operands can't be + immediates. + """ + + def __init__(self, name, doc, ins=(), outs=(), **kwargs): + self.name = name + self.__doc__ = doc + self.ins = self._to_operand_tuple(ins) + self.outs = self._to_operand_tuple(outs) + + @staticmethod + def _to_operand_tuple(x): + # 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