Add entity references as a new operand kind.
Define known entities in the cretonne.entities module.
This commit is contained in:
@@ -36,11 +36,11 @@ Here is the same function compiled into Cretonne IL:
|
|||||||
|
|
||||||
The first line of a function definition provides the function *name* and
|
The first line of a function definition provides the function *name* and
|
||||||
the :term:`function signature` which declares the argument and return types.
|
the :term:`function signature` which declares the argument and return types.
|
||||||
Then follows the :term:`function preample` which declares a number of entities
|
Then follows the :term:`function preamble` which declares a number of entities
|
||||||
that can be referenced inside the function. In the example above, the preample
|
that can be referenced inside the function. In the example above, the preamble
|
||||||
declares a single local variable, ``ss1``.
|
declares a single local variable, ``ss1``.
|
||||||
|
|
||||||
After the preample follows the :term:`function body` which consists of
|
After the preamble follows the :term:`function body` which consists of
|
||||||
:term:`extended basic block`\s, one of which is marked as the :term:`entry
|
:term:`extended basic block`\s, one of which is marked as the :term:`entry
|
||||||
block`. Every EBB ends with a :term:`terminator instruction`, so execution can
|
block`. Every EBB ends with a :term:`terminator instruction`, so execution can
|
||||||
never fall through to the next EBB without an explicit branch.
|
never fall through to the next EBB without an explicit branch.
|
||||||
@@ -49,7 +49,7 @@ A ``.cton`` file consists of a sequence of independent function definitions:
|
|||||||
|
|
||||||
.. productionlist::
|
.. productionlist::
|
||||||
function-list : { function }
|
function-list : { function }
|
||||||
function : function-spec "{" preample function-body "}"
|
function : function-spec "{" preamble function-body "}"
|
||||||
function-spec : "function" function-name signature
|
function-spec : "function" function-name signature
|
||||||
preamble : { preamble-decl }
|
preamble : { preamble-decl }
|
||||||
function-body : { extended-basic-block }
|
function-body : { extended-basic-block }
|
||||||
@@ -361,12 +361,12 @@ instruction in the EBB.
|
|||||||
blocks. Split critical edges as needed to work around this.
|
blocks. Split critical edges as needed to work around this.
|
||||||
|
|
||||||
:arg iN x: Integer index into jump table.
|
:arg iN x: Integer index into jump table.
|
||||||
:arg JT: Jump table which was declared in the preample.
|
:arg JT: Jump table which was declared in the preamble.
|
||||||
:result: None.
|
:result: None.
|
||||||
|
|
||||||
.. inst:: JT = jump_table EBB0, EBB1, ..., EBBn
|
.. inst:: JT = jump_table EBB0, EBB1, ..., EBBn
|
||||||
|
|
||||||
Declare a jump table in the :term:`function preample`.
|
Declare a jump table in the :term:`function preamble`.
|
||||||
|
|
||||||
This declares a jump table for use by the :inst:`br_table` indirect branch
|
This declares a jump table for use by the :inst:`br_table` indirect branch
|
||||||
instruction. Entries in the table are either EBB names, or ``0`` which
|
instruction. Entries in the table are either EBB names, or ``0`` which
|
||||||
@@ -433,7 +433,7 @@ dependent. They make it possible to call native functions on the target
|
|||||||
platform. When calling other Cretonne functions, the flags are not necessary.
|
platform. When calling other Cretonne functions, the flags are not necessary.
|
||||||
|
|
||||||
Functions that are called directly must be declared in the :term:`function
|
Functions that are called directly must be declared in the :term:`function
|
||||||
preample`:
|
preamble`:
|
||||||
|
|
||||||
.. inst:: F = function NAME signature
|
.. inst:: F = function NAME signature
|
||||||
|
|
||||||
@@ -476,7 +476,7 @@ This simple example illustrates direct function calls and signatures::
|
|||||||
return v1
|
return v1
|
||||||
}
|
}
|
||||||
|
|
||||||
Indirect function calls use a signature declared in the preample.
|
Indirect function calls use a signature declared in the preamble.
|
||||||
|
|
||||||
.. inst:: SIG = signature signature
|
.. inst:: SIG = signature signature
|
||||||
|
|
||||||
@@ -556,12 +556,12 @@ Local variables
|
|||||||
|
|
||||||
One set of restricted memory operations access the current function's stack
|
One set of restricted memory operations access the current function's stack
|
||||||
frame. The stack frame is divided into fixed-size stack slots that are
|
frame. The stack frame is divided into fixed-size stack slots that are
|
||||||
allocated in the :term:`function preample`. Stack slots are not typed, they
|
allocated in the :term:`function preamble`. Stack slots are not typed, they
|
||||||
simply represent a contiguous sequence of bytes in the stack frame.
|
simply represent a contiguous sequence of bytes in the stack frame.
|
||||||
|
|
||||||
.. inst:: SS = stack_slot Bytes, Flags...
|
.. inst:: SS = stack_slot Bytes, Flags...
|
||||||
|
|
||||||
Allocate a stack slot in the preample.
|
Allocate a stack slot in the preamble.
|
||||||
|
|
||||||
If no alignment is specified, Cretonne will pick an appropriate alignment
|
If no alignment is specified, Cretonne will pick an appropriate alignment
|
||||||
for the stack slot based on its size and access patterns.
|
for the stack slot based on its size and access patterns.
|
||||||
@@ -633,14 +633,14 @@ all process memory. Instead, it is given a small set of memory areas to work
|
|||||||
in, and all accesses are bounds checked. Cretonne models this through the
|
in, and all accesses are bounds checked. Cretonne models this through the
|
||||||
concept of *heaps*.
|
concept of *heaps*.
|
||||||
|
|
||||||
A heap is declared in the function preample and can be accessed with restricted
|
A heap is declared in the function preamble and can be accessed with restricted
|
||||||
instructions that trap on out-of-bounds accesses. Heap addresses can be smaller
|
instructions that trap on out-of-bounds accesses. Heap addresses can be smaller
|
||||||
than the native pointer size, for example unsigned :type:`i32` offsets on a
|
than the native pointer size, for example unsigned :type:`i32` offsets on a
|
||||||
64-bit architecture.
|
64-bit architecture.
|
||||||
|
|
||||||
.. inst:: H = heap Name
|
.. inst:: H = heap Name
|
||||||
|
|
||||||
Declare a heap in the function preample.
|
Declare a heap in the function preamble.
|
||||||
|
|
||||||
This doesn't allocate memory, it just retrieves a handle to a sandbox from
|
This doesn't allocate memory, it just retrieves a handle to a sandbox from
|
||||||
the runtime environment.
|
the runtime environment.
|
||||||
@@ -1034,9 +1034,9 @@ Glossary
|
|||||||
is not necessary to know when calling it, so it is just an attribute,
|
is not necessary to know when calling it, so it is just an attribute,
|
||||||
and not part of the signature.
|
and not part of the signature.
|
||||||
|
|
||||||
function preample
|
function preamble
|
||||||
A list of declarations of entities that are used by the function body.
|
A list of declarations of entities that are used by the function body.
|
||||||
Some of the entities that can be declared in the preample are:
|
Some of the entities that can be declared in the preamble are:
|
||||||
|
|
||||||
- Local variables.
|
- Local variables.
|
||||||
- Functions that are called directly.
|
- Functions that are called directly.
|
||||||
@@ -1045,7 +1045,7 @@ Glossary
|
|||||||
|
|
||||||
function body
|
function body
|
||||||
The extended basic blocks which contain all the executable code in a
|
The extended basic blocks which contain all the executable code in a
|
||||||
function. The function body follows the function preample.
|
function. The function body follows the function preamble.
|
||||||
|
|
||||||
basic block
|
basic block
|
||||||
A maximal sequence of instructions that can only be entered from the
|
A maximal sequence of instructions that can only be entered from the
|
||||||
|
|||||||
@@ -47,14 +47,14 @@ must be instances of the :class:`Operand` class.
|
|||||||
|
|
||||||
.. autoclass:: Operand
|
.. autoclass:: Operand
|
||||||
|
|
||||||
Cretonne uses two separate type systems for immediate operands and SSA values.
|
Cretonne uses two separate type systems for operand kinds and SSA values.
|
||||||
|
|
||||||
Type variables
|
Type variables
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
Instruction descriptions can be made polymorphic by using :class:`Operand`
|
Instruction descriptions can be made polymorphic by using :class:`Operand`
|
||||||
instances that refer to a *type variable* instead of a concrete value type.
|
instances that refer to a *type variable* instead of a concrete value type.
|
||||||
Polymorphism only works for SSA value operands. Immediate operands have a fixed
|
Polymorphism only works for SSA value operands. Other operands have a fixed
|
||||||
operand kind.
|
operand kind.
|
||||||
|
|
||||||
.. autoclass:: TypeVar
|
.. autoclass:: TypeVar
|
||||||
@@ -95,6 +95,18 @@ indicated with an instance of :class:`ImmediateKind`.
|
|||||||
|
|
||||||
.. currentmodule:: cretonne
|
.. currentmodule:: cretonne
|
||||||
|
|
||||||
|
Entity references
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Instruction operands can also refer to other entties in the same function. This
|
||||||
|
can be extended basic blocks, or entities declared in the function preamble.
|
||||||
|
|
||||||
|
.. autoclass:: EntityRefKind
|
||||||
|
|
||||||
|
.. automodule:: cretonne.entities
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. currentmodule:: cretonne
|
||||||
|
|
||||||
Value types
|
Value types
|
||||||
-----------
|
-----------
|
||||||
@@ -133,13 +145,14 @@ representation depends on the input operand kinds and whether the instruction
|
|||||||
can produce multiple results.
|
can produce multiple results.
|
||||||
|
|
||||||
.. autoclass:: OperandKind
|
.. autoclass:: OperandKind
|
||||||
|
.. inheritance-diagram:: OperandKind ImmediateKind EntityRefkind
|
||||||
|
|
||||||
Since all SSA value operands are represented as a `Value` in Rust code, value
|
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:: args
|
.. autodata:: variable_args
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -42,6 +42,12 @@ class OperandKind(object):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return 'OperandKind({})'.format(self.name)
|
return 'OperandKind({})'.format(self.name)
|
||||||
|
|
||||||
|
def operand_kind(self):
|
||||||
|
"""
|
||||||
|
An `OperandKind` instance can be used directly as the type of an
|
||||||
|
`Operand` when defining an instruction.
|
||||||
|
"""
|
||||||
|
return self
|
||||||
|
|
||||||
#: An SSA value operand. This is a value defined by another instruction.
|
#: An SSA value operand. This is a value defined by another instruction.
|
||||||
value = OperandKind(
|
value = OperandKind(
|
||||||
@@ -55,8 +61,8 @@ value = OperandKind(
|
|||||||
|
|
||||||
#: A variable-sized list of value operands. Use for Ebb and function call
|
#: A variable-sized list of value operands. Use for Ebb and function call
|
||||||
#: arguments.
|
#: arguments.
|
||||||
args = OperandKind(
|
variable_args = OperandKind(
|
||||||
'args', """
|
'variable_args', """
|
||||||
A variable size list of `value` operands.
|
A variable size list of `value` operands.
|
||||||
|
|
||||||
Use this to represent arguemtns passed to a function call, arguments
|
Use this to represent arguemtns passed to a function call, arguments
|
||||||
@@ -65,8 +71,8 @@ args = OperandKind(
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
# Instances of immediate operand types are provided in the cretonne.immediates
|
# Instances of immediate operand types are provided in the
|
||||||
# module.
|
# `cretonne.immediates` module.
|
||||||
class ImmediateKind(OperandKind):
|
class ImmediateKind(OperandKind):
|
||||||
"""
|
"""
|
||||||
The kind of an immediate instruction operand.
|
The kind of an immediate instruction operand.
|
||||||
@@ -79,12 +85,20 @@ class ImmediateKind(OperandKind):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return 'ImmediateKind({})'.format(self.name)
|
return 'ImmediateKind({})'.format(self.name)
|
||||||
|
|
||||||
def operand_kind(self):
|
|
||||||
"""
|
# Instances of entity reference operand types are provided in the
|
||||||
An `ImmediateKind` instance can be used directly as the type of an
|
# `cretonne.entities` module.
|
||||||
`Operand` when defining an instruction.
|
class EntityRefKind(OperandKind):
|
||||||
"""
|
"""
|
||||||
return self
|
The kind of an entity reference instruction operand.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name, doc):
|
||||||
|
self.name = name
|
||||||
|
self.__doc__ = doc
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return 'EntityRefKind({})'.format(self.name)
|
||||||
|
|
||||||
|
|
||||||
# ValueType instances (i8, i32, ...) are provided in the cretonne.types module.
|
# ValueType instances (i8, i32, ...) are provided in the cretonne.types module.
|
||||||
@@ -315,8 +329,8 @@ class InstructionGroup(object):
|
|||||||
|
|
||||||
class Operand(object):
|
class Operand(object):
|
||||||
"""
|
"""
|
||||||
An instruction operand can be either an *immediate* or an *SSA value*. The
|
An instruction operand can be an *immediate*, an *SSA value*, or an *entity
|
||||||
type of the operand is one of:
|
reference*. The type of the operand is one of:
|
||||||
|
|
||||||
1. A :py:class:`ValueType` instance indicates an SSA value operand with a
|
1. A :py:class:`ValueType` instance indicates an SSA value operand with a
|
||||||
concrete type.
|
concrete type.
|
||||||
@@ -329,6 +343,10 @@ class Operand(object):
|
|||||||
whose value is encoded in the instruction itself rather than being
|
whose value is encoded in the instruction itself rather than being
|
||||||
passed as an SSA value.
|
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=''):
|
def __init__(self, name, typ, doc=''):
|
||||||
self.name = name
|
self.name = name
|
||||||
@@ -429,9 +447,9 @@ class Instruction(object):
|
|||||||
:param name: Instruction mnemonic, also becomes opcode name.
|
:param name: Instruction mnemonic, also becomes opcode name.
|
||||||
:param doc: Documentation string.
|
:param doc: Documentation string.
|
||||||
:param ins: Tuple of input operands. This can be a mix of SSA value
|
:param ins: Tuple of input operands. This can be a mix of SSA value
|
||||||
operands and immediate operands.
|
operands and other operand kinds.
|
||||||
:param outs: Tuple of output operands. The output operands can't be
|
:param outs: Tuple of output operands. The output operands must be SSA
|
||||||
immediates.
|
values.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name, doc, ins=(), outs=(), **kwargs):
|
def __init__(self, name, doc, ins=(), outs=(), **kwargs):
|
||||||
|
|||||||
23
meta/cretonne/entities.py
Normal file
23
meta/cretonne/entities.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
"""
|
||||||
|
The `cretonne.entities` module predefines all the Cretonne entity reference
|
||||||
|
operand types. Thee are corresponding definitions in the `cretonne.entities`
|
||||||
|
Rust module.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from . import EntityRefKind
|
||||||
|
|
||||||
|
|
||||||
|
#: A reference to an extended basic block in the same function.
|
||||||
|
#: This is primarliy used in control flow instructions.
|
||||||
|
ebb = EntityRefKind('ebb', 'An extended basic block in the same function.')
|
||||||
|
|
||||||
|
#: A reference to a stack slot declared in the function preamble.
|
||||||
|
stack_slot = EntityRefKind('stack_slot', 'A stack slot.')
|
||||||
|
|
||||||
|
#: A reference to a function sugnature declared in the function preamble.
|
||||||
|
#: Tbis is used to provide the call signature in an indirect call instruction.
|
||||||
|
signature = EntityRefKind('signature', 'A function signature.')
|
||||||
|
|
||||||
|
#: A reference to an external function declared in the function preamble.
|
||||||
|
#: This is used to provide the callee and signature in a call instruction.
|
||||||
|
function = EntityRefKind('function', 'An external function.')
|
||||||
@@ -7,8 +7,9 @@ in this module.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
from . import InstructionFormat, value, args
|
from . import InstructionFormat, value, variable_args
|
||||||
from immediates import imm64, ieee32, ieee64, immvector
|
from immediates import imm64, ieee32, ieee64, immvector
|
||||||
|
from entities import function
|
||||||
|
|
||||||
Nullary = InstructionFormat()
|
Nullary = InstructionFormat()
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ Binary = InstructionFormat(value, value)
|
|||||||
BinaryImm = InstructionFormat(value, imm64)
|
BinaryImm = InstructionFormat(value, imm64)
|
||||||
BinaryImmRev = InstructionFormat(imm64, value)
|
BinaryImmRev = InstructionFormat(imm64, value)
|
||||||
|
|
||||||
Call = InstructionFormat(args, multiple_results=True)
|
Call = InstructionFormat(function, variable_args, multiple_results=True)
|
||||||
|
|
||||||
# Finally extract the names of global variables in this module.
|
# Finally extract the names of global variables in this module.
|
||||||
InstructionFormat.extract_names(globals())
|
InstructionFormat.extract_names(globals())
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
The cretonne.immediates module predefines all the Cretonne immediate operand
|
The `cretonne.immediates` module predefines all the Cretonne immediate operand
|
||||||
types.
|
types.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|||||||
@@ -300,19 +300,19 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
// Parse a whole function definition.
|
// Parse a whole function definition.
|
||||||
//
|
//
|
||||||
// function ::= * function-spec "{" preample function-body "}"
|
// function ::= * function-spec "{" preamble function-body "}"
|
||||||
//
|
//
|
||||||
fn parse_function(&mut self) -> Result<Function> {
|
fn parse_function(&mut self) -> Result<Function> {
|
||||||
let (name, sig) = try!(self.parse_function_spec());
|
let (name, sig) = try!(self.parse_function_spec());
|
||||||
let mut ctx = Context::new(Function::with_name_signature(name, sig));
|
let mut ctx = Context::new(Function::with_name_signature(name, sig));
|
||||||
|
|
||||||
// function ::= function-spec * "{" preample function-body "}"
|
// function ::= function-spec * "{" preamble function-body "}"
|
||||||
try!(self.match_token(Token::LBrace, "expected '{' before function body"));
|
try!(self.match_token(Token::LBrace, "expected '{' before function body"));
|
||||||
// function ::= function-spec "{" * preample function-body "}"
|
// function ::= function-spec "{" * preamble function-body "}"
|
||||||
try!(self.parse_preamble(&mut ctx));
|
try!(self.parse_preamble(&mut ctx));
|
||||||
// function ::= function-spec "{" preample * function-body "}"
|
// function ::= function-spec "{" preamble * function-body "}"
|
||||||
try!(self.parse_function_body(&mut ctx));
|
try!(self.parse_function_body(&mut ctx));
|
||||||
// function ::= function-spec "{" preample function-body * "}"
|
// function ::= function-spec "{" preamble function-body * "}"
|
||||||
try!(self.match_token(Token::RBrace, "expected '}' after function body"));
|
try!(self.match_token(Token::RBrace, "expected '}' after function body"));
|
||||||
|
|
||||||
Ok(ctx.function)
|
Ok(ctx.function)
|
||||||
|
|||||||
Reference in New Issue
Block a user