from spec_util import abstract, setnodedefaults
class Op(object):
- "Base class for firm nodes"
+ """Base class for firm nodes"""
abstract(Op)
class Unop(Op):
- "Unary nodes have exactly 1 input"
+ """Unary nodes have exactly 1 input"""
name = "unop"
ins = [ "op" ]
op_index = 0
abstract(Unop)
class Binop(Op):
- "Binary nodes have exactly 2 inputs"
+ """Binary nodes have exactly 2 inputs"""
name = "binop"
ins = [ "left", "right" ]
op_index = 0
abstract(Binop)
class Add(Binop):
+ """returns the sum of its operands"""
flags = ["commutative"]
class Alloc(Op):
+ """allocates a block of memory.
+ It can be specified whether the variable should be allocated to the stack
+ or to the heap."""
ins = [ "mem", "count" ]
outs = [
("M", "memory result", "pn_Generic_M"),
attr_struct = "alloc_attr"
class Anchor(Op):
+ """utiliy node used to "hold" nodes in a graph that might possibly not be
+ reachable by other means or which should be reachable immediately without
+ searching through the graph.
+ Each firm-graph contains exactly one anchor node whose address is always
+ known. All other well-known graph-nodes like Start, End, NoMem, Bad, ...
+ are found by looking at the respective Anchor operand."""
mode = "mode_ANY"
arity = "variable"
flags = [ "dump_noblock" ]
customSerializer = True
class And(Binop):
+ """returns the result of a bitwise and operation of its operands"""
flags = [ "commutative" ]
class ASM(Op):
+ """executes assembler fragments of the target machine"""
mode = "mode_T"
arity = "variable"
flags = [ "keep", "uses_memory" ]
attr_struct = "asm_attr"
attrs_name = "assem"
customSerializer = True
- attrs = [
- dict(
- name = "input_constraints",
- type = "ir_asm_constraint*",
- ),
- dict(
- name = "n_output_constraints",
- type = "int",
- noprop = True,
- ),
- dict(
- name = "output_constraints",
- type = "ir_asm_constraint*",
- ),
- dict(
- name = "n_clobbers",
- type = "int",
- noprop = True,
- ),
- dict(
- name = "clobbers",
- type = "ident**",
- ),
- dict(
- name = "text",
- type = "ident*",
- ),
- ]
class Bad(Op):
+ """Bad nodes indicate invalid input, which is values which should never be
+ computed.
+
+ The typical use case for the Bad node is removing unreachable code.
+ Frontends should set the current_block to Bad when it is clear that
+ following code must be unreachable (ie. after a goto or return statement).
+ Optimisations also set block predecessors to Bad when it becomes clear,
+ that a control flow edge can never be executed.
+
+ The gigo optimisations ensures that nodes with Bad as their block, get
+ replaced by Bad themselfes. Nodes with at least 1 Bad input get exchanged
+ with Bad too. Exception to this rule are Block, Phi, Tuple and End node;
+ This is because removing inputs from a Block is hairy operation (requiring,
+ Phis to be shortened too for example). So instead of removing block inputs
+ they are set to Bad, and the actual removal is left to the control flow
+ optimisation phase. Block, Phi, Tuple with only Bad inputs however are
+ replaced by Bad right away."""
mode = "mode_T"
flags = [ "cfopcode", "start_block", "dump_noblock" ]
pinned = "yes"
'''
class Deleted(Op):
+ """Internal node which is temporary set to nodes which are already removed
+ from the graph."""
mode = "mode_Bad"
flags = [ ]
pinned = "yes"
customSerializer = True
class Block(Op):
+ """A basic block"""
mode = "mode_BB"
knownBlock = True
block = "NULL"
'''
class Borrow(Binop):
+ """Returns the borrow bit from and implied subtractions of its 2 operands"""
flags = []
class Bound(Op):
+ """Performs a bounds-check: if lower <= index < upper then return index,
+ otherwise throw an exception."""
ins = [ "mem", "index", "lower", "upper" ]
outs = [
("M", "memory result", "pn_Generic_M"),
attrs_name = "bound"
class Builtin(Op):
+ """performs a backend-specific builtin."""
ins = [ "mem" ]
arity = "variable"
outs = [
'''
class Call(Op):
+ """Calls other code. Control flow is transfered to ptr, additional
+ operands are passed to the called code. Called code usually performs a
+ return operation. The operands of this return operation are the result
+ of the Call node."""
ins = [ "mem", "ptr" ]
arity = "variable"
outs = [
'''
class Carry(Binop):
+ """Computes the value of the carry-bit that would result when adding the 2
+ operands"""
flags = [ "commutative" ]
class Cast(Unop):
+ """perform a high-level type cast"""
mode = "get_irn_mode(irn_op)"
flags = [ "highlevel" ]
attrs = [
init = "assert(is_atomic_type(type));"
class Cmp(Binop):
+ """Returns the relation of 2 operands"""
outs = [
("False", "always false", "0"),
("Eq", "equal", "1"),
flags = []
class Cond(Op):
+ """Conditionally change control flow. There are two versions of this node:
+
+ Boolean Cond:
+ Input: A value of mode_b
+ Output: A tuple of two control flows. The first is taken if the input is
+ false, the second if it is true.
+
+ Switch Cond:
+ Input: A value of mode_Iu
+ Output: A tuple of n control flows. If the Cond's input is i, control flow
+ will proceed along output i. If the input is >= n control flow proceeds
+ along output def_proj.
+ """
ins = [ "selector" ]
outs = [
("false", "control flow if operand is \"false\""),
attr_struct = "cond_attr"
class Confirm(Op):
+ """Specifies constraints for a value. This allows explicit representation
+ of path-sensitive properties. (Example: This value is always >= 0 on 1
+ if-branch then all users within that branch are rerouted to a confirm-node
+ specifying this property).
+
+ A constraint is specified for the relation between value and bound.
+ value is always returned.
+ Note that this node does NOT check or assert the constraint, it merely
+ specifies it."""
ins = [ "value", "bound" ]
mode = "get_irn_mode(irn_value)"
flags = [ "highlevel" ]
attrs_name = "confirm"
class Const(Op):
+ """Returns a constant value."""
mode = ""
flags = [ "constlike", "start_block" ]
knownBlock = True
attr_struct = "const_attr"
class Conv(Unop):
+ """Converts values between modes"""
flags = []
attrs = [
dict(
attrs_name = "conv"
class CopyB(Op):
+ """Copies a block of memory"""
ins = [ "mem", "dst", "src" ]
outs = [
("M", "memory result", "pn_Generic_M"),
("X_regular", "control flow when no exception occurs", "pn_Generic_X_regular"),
("X_except", "control flow when exception occured", "pn_Generic_X_except"),
]
- flags = [ "fragile", "highlevel", "uses_memory" ]
+ flags = [ "fragile", "uses_memory" ]
attrs = [
dict(
name = "type",
pinned_init = "op_pin_state_pinned"
class Div(Op):
+ """returns the quotient of its 2 operands, integer version"""
ins = [ "mem", "left", "right" ]
outs = [
("M", "memory result", "pn_Generic_M"),
arity_override = "oparity_binary"
class DivMod(Op):
+ """divides its 2 operands and computes the remainder of the division"""
ins = [ "mem", "left", "right" ]
outs = [
("M", "memory result", "pn_Generic_M"),
arity_override = "oparity_binary"
class Dummy(Op):
+ """A placeholder value. This is used when constructing cyclic graphs where
+ you have cases where not all predecessors of a phi-node are known. Dummy
+ nodes are used for the unknown predecessors and replaced later."""
ins = []
flags = [ "cfopcode", "start_block", "constlike", "dump_noblock" ]
knownBlock = True
block = "get_irg_start_block(irg)"
class End(Op):
+ """Last node of a graph. It references nodes in endless loops (so called
+ keepalive edges)"""
mode = "mode_X"
pinned = "yes"
arity = "dynamic"
customSerializer = True
class Eor(Binop):
+ """returns the result of a bitwise exclusive or operation of its operands"""
flags = [ "commutative" ]
class Free(Op):
+ """Frees a block of memory previously allocated by an Alloc node"""
ins = [ "mem", "ptr", "size" ]
mode = "mode_M"
flags = [ "uses_memory" ]
attr_struct = "free_attr"
class Id(Op):
+ """Returns its operand unchanged."""
ins = [ "pred" ]
pinned = "no"
flags = []
class IJmp(Op):
+ """Jumps to the code in its argument. The code has to be in the same
+ function and the the destination must be one of the blocks reachable
+ by the tuple results"""
mode = "mode_X"
pinned = "yes"
ins = [ "target" ]
flags = [ "cfopcode", "forking", "keep" ]
class InstOf(Op):
+ """Tests wether an object is an instance of a class-type"""
ins = [ "store", "obj" ]
outs = [
("M", "memory result", "pn_Generic_M"),
pinned_init = "op_pin_state_floats"
class Jmp(Op):
+ """Jumps to the block connected through the out-value"""
mode = "mode_X"
pinned = "yes"
ins = []
flags = [ "cfopcode" ]
class Load(Op):
+ """Loads a value from memory (heap or stack)."""
ins = [ "mem", "ptr" ]
outs = [
("M", "memory result", "pn_Generic_M"),
]
class Minus(Unop):
+ """returns the difference between its operands"""
flags = []
class Mod(Op):
+ """returns the remainder of its operands from an implied division.
+
+ Examples:
+ * mod(5,3) produces 2
+ * mod(5,-3) produces 2
+ * mod(-5,3) produces -2
+ * mod(-5,-3) produces -2
+ """
ins = [ "mem", "left", "right" ]
outs = [
("M", "memory result", "pn_Generic_M"),
arity_override = "oparity_binary"
class Mul(Binop):
+ """returns the product of its operands"""
flags = [ "commutative" ]
class Mulh(Binop):
+ """returns the upper word of the product of its operands (the part which
+ would not fit into the result mode of a normal Mul anymore)"""
flags = [ "commutative" ]
class Mux(Op):
+ """returns the false or true operand depending on the value of the sel
+ operand"""
ins = [ "sel", "false", "true" ]
flags = []
pinned = "no"
class NoMem(Op):
+ """Placeholder node for cases where you don't need any memory input"""
mode = "mode_M"
flags = [ "dump_noblock", "dump_noinput" ]
pinned = "yes"
singleton = True
class Not(Unop):
+ """returns the logical complement of a value. Works for integer values too.
+ If the input is false/zero then true/one is returned, otherwise false/zero
+ is returned."""
flags = []
class Or(Binop):
+ """returns the result of a bitwise or operation of its operands"""
flags = [ "commutative" ]
class Phi(Op):
+ """Choose a value based on control flow. A phi node has 1 input for each
+ predecessor of its block. If a block is entered from its nth predecessor
+ all phi nodes produce their nth input as result."""
pinned = "yes"
arity = "variable"
flags = []
'''
class Pin(Op):
+ """Pin the value of the node node in the current block. No users of the Pin
+ node can float above the Block of the Pin. The node cannot float behind
+ this block. Often used to Pin the NoMem node."""
ins = [ "op" ]
mode = "get_irn_mode(irn_op)"
flags = [ "highlevel" ]
pinned = "yes"
class Proj(Op):
+ """returns an entry of a tuple value"""
ins = [ "pred" ]
flags = []
pinned = "no"
attr_struct = "long"
class Quot(Op):
+ """returns the quotient of its 2 operands, floatingpoint version"""
ins = [ "mem", "left", "right" ]
outs = [
("M", "memory result", "pn_Generic_M"),
arity_override = "oparity_binary"
class Raise(Op):
+ """Raises an exception. Unconditional change of control flow. Writes an
+ explicit Except variable to memory to pass it to the exception handler.
+ Must be lowered to a Call to a runtime check function."""
ins = [ "mem", "exo_ptr" ]
outs = [
("M", "memory result", "pn_Generic_M"),
pinned = "yes"
class Return(Op):
+ """Returns from the current function. Takes memory and return values as
+ operands."""
ins = [ "mem" ]
arity = "variable"
mode = "mode_X"
pinned = "yes"
class Rotl(Binop):
+ """Returns its first operand bits rotated left by the amount in the 2nd
+ operand"""
flags = []
class Sel(Op):
+ """Computes the address of a entity of a compound type given the base
+ address of an instance of the compound type."""
ins = [ "mem", "ptr" ]
arity = "variable"
flags = []
attr_struct = "sel_attr"
class Shl(Binop):
+ """Returns its first operands bits shifted left by the amount of the 2nd
+ operand"""
flags = []
class Shr(Binop):
+ """Returns its first operands bits shifted right by the amount of the 2nd
+ operand. No special handling for the sign bit (zero extension)"""
flags = []
class Shrs(Binop):
+ """Returns its first operands bits shifted right by the amount of the 2nd
+ operand. The leftmost bit (usually the sign bit) stays the same
+ (sign extension)"""
flags = []
class Start(Op):
+ """The first node of a graph. Execution starts with this node."""
outs = [
("X_initial_exec", "control flow"),
("M", "initial memory"),
block = "get_irg_start_block(irg)"
class Store(Op):
+ """Stores a value into memory (heap or stack)."""
ins = [ "mem", "ptr", "value" ]
outs = [
("M", "memory result", "pn_Generic_M"),
]
class Sub(Binop):
+ """returns the difference of its operands"""
flags = []
class SymConst(Op):
+ """A symbolic constant.
+
+ - symconst_type_tag The symbolic constant represents a type tag. The
+ type the tag stands for is given explicitly.
+ - symconst_type_size The symbolic constant represents the size of a type.
+ The type of which the constant represents the size
+ is given explicitly.
+ - symconst_type_align The symbolic constant represents the alignment of a
+ type. The type of which the constant represents the
+ size is given explicitly.
+ - symconst_addr_ent The symbolic constant represents the address of an
+ entity (variable or method). The variable is given
+ explicitly by a firm entity.
+ - symconst_ofs_ent The symbolic constant represents the offset of an
+ entity in its owner type.
+ - symconst_enum_const The symbolic constant is a enumeration constant of
+ an enumeration type."""
mode = "mode_P"
flags = [ "constlike", "start_block" ]
knownBlock = True
customSerializer = True
class Sync(Op):
+ """The Sync operation unifies several partial memory blocks. These blocks
+ have to be pairwise disjunct or the values in common locations have to
+ be identical. This operation allows to specify all operations that
+ eventually need several partial memory blocks as input with a single
+ entrance by unifying the memories with a preceding Sync operation."""
mode = "mode_M"
flags = []
pinned = "no"
arity = "dynamic"
class Tuple(Op):
+ """Builds a Tuple from single values.
+
+ This is needed to implement optimizations that remove a node that produced
+ a tuple. The node can be replaced by the Tuple operation so that the
+ following Proj nodes have not to be changed. (They are hard to find due to
+ the implementation with pointers in only one direction.) The Tuple node is
+ smaller than any other node, so that a node can be changed into a Tuple by
+ just changing it's opcode and giving it a new in array."""
arity = "variable"
mode = "mode_T"
pinned = "no"
flags = [ "labeled" ]
class Unknown(Op):
+ """Returns an unknown (at compile- and runtime) value. It is a valid
+ optimisation to replace an Unknown by any other constant value."""
knownBlock = True
pinned = "yes"
block = "get_irg_start_block(irg)"