X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=scripts%2Fir_spec.py;h=f264b82cec92440f0b1e43f49b5927f59111e4e8;hb=6b45fde8adadc605dfe4c3a181c7fd8f78ac227c;hp=aeed4f99194f38de4cf698f64e81cf5c56a7d744;hpb=c8e1cf6a41fa2077058cce740783ab78990ac0ab;p=libfirm diff --git a/scripts/ir_spec.py b/scripts/ir_spec.py index aeed4f991..f264b82ce 100755 --- a/scripts/ir_spec.py +++ b/scripts/ir_spec.py @@ -1,141 +1,186 @@ 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" ] + ins = [ + ("op", "operand"), + ] op_index = 0 pinned = "no" abstract(Unop) class Binop(Op): - "Binary nodes have exactly 2 inputs" + """Binary nodes have exactly 2 inputs""" name = "binop" - ins = [ "left", "right" ] + ins = [ + ( "left", "first operand" ), + ( "right", "second operand" ), + ] op_index = 0 pinned = "no" abstract(Binop) -class Abs(Unop): - flags = [] - class Add(Binop): - flags = ["commutative"] + """returns the sum of its operands""" + flags = [ "commutative" ] class Alloc(Op): - ins = [ "mem", "count" ] + """allocates a block of memory. + It can be specified whether the variable should be allocated to the stack + or to the heap.""" + ins = [ + ("mem", "memory dependency" ), + ("count", "number of objects to allocate" ), + ] 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"), - ("res", "pointer to newly allocated memory", "pn_Generic_other"), + ("M", "memory result"), + ("res", "pointer to newly allocated memory"), + ("X_regular", "control flow when no exception occurs"), + ("X_except", "control flow when exception occured"), ] - flags = [ "fragile", "uses_memory" ] attrs = [ dict( - name = "type", - type = "ir_type*" + name = "type", + type = "ir_type*", + comment = "type of the allocated variable", ), dict( - name = "where", - type = "ir_where_alloc" + name = "where", + type = "ir_where_alloc", + comment = "whether to allocate the variable on the stack or heap", ) ] - pinned = "yes" + flags = [ "fragile", "uses_memory" ] + pinned = "exception" + throws_init = "false" + pinned_init = "op_pin_state_pinned" attr_struct = "alloc_attr" class Anchor(Op): - mode = "mode_ANY" - arity = "variable" - flags = [ "dump_noblock" ] - pinned = "yes" - attr_struct = "irg_attr" - knownBlock = True - singleton = True + """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" ] + pinned = "yes" + attr_struct = "irg_attr" + knownBlock = True + singleton = True + noconstructor = True + customSerializer = True class And(Binop): + """returns the result of a bitwise and operation of its operands""" flags = [ "commutative" ] class ASM(Op): - mode = "mode_T" - arity = "variable" - flags = [ "keep", "uses_memory" ] - pinned = "memory" - pinned_init = "op_pin_state_pinned" - attr_struct = "asm_attr" - attrs_name = "assem" + """executes assembler fragments of the target machine""" + mode = "mode_T" + arity = "variable" + flags = [ "keep", "uses_memory" ] + pinned = "memory" + pinned_init = "op_pin_state_pinned" + attr_struct = "asm_attr" + attrs_name = "assem" + customSerializer = True attrs = [ dict( - name = "input_constraints", - type = "ir_asm_constraint*", + name = "input_constraints", + type = "ir_asm_constraint*", + comment = "input constraints", ), dict( - name = "n_output_constraints", - type = "int", - noprop = True, + name = "n_output_constraints", + type = "int", + noprop = True, + comment = "number of output constraints", ), dict( - name = "output_constraints", - type = "ir_asm_constraint*", + name = "output_constraints", + type = "ir_asm_constraint*", + comment = "output constraints", ), dict( - name = "n_clobbers", - type = "int", - noprop = True, + name = "n_clobbers", + type = "int", + noprop = True, + comment = "number of clobbered registers/memory", ), dict( - name = "clobbers", - type = "ident**", + name = "clobbers", + type = "ident**", + comment = "list of clobbered registers/memory", ), dict( - name = "text", - type = "ident*", + name = "text", + type = "ident*", + comment = "assembler text", ), ] - java_noconstr = True + # constructor is written manually at the moment, because of the clobbers+ + # constraints arrays needing special handling (2 arguments for 1 attribute) + noconstructor = True class Bad(Op): - mode = "mode_Bad" - flags = [ "cfopcode", "start_block", "dump_noblock" ] - pinned = "yes" - knownBlock = True - singleton = True - attr_struct = "irg_attr" + """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.""" + flags = [ "start_block", "dump_noblock" ] + pinned = "yes" + knownBlock = True + block = "get_irg_start_block(irg)" + attr_struct = "bad_attr" init = ''' - res->attr.irg.irg = irg; + res->attr.bad.irg.irg = irg; ''' +class Deleted(Op): + """Internal node which is temporary set to nodes which are already removed + from the graph.""" + mode = "mode_Bad" + flags = [ ] + pinned = "yes" + noconstructor = True + customSerializer = True + class Block(Op): - mode = "mode_BB" - knownBlock = True - block = "NULL" - pinned = "yes" - optimize = False - arity = "variable" - flags = [ "labeled" ] - attr_struct = "block_attr" - java_noconstr = True + """A basic block""" + mode = "mode_BB" + knownBlock = True + block = "NULL" + pinned = "yes" + arity = "variable" + flags = [ "labeled" ] + attr_struct = "block_attr" + customSerializer = True init = ''' - /* macroblock header */ - res->in[0] = res; - - res->attr.block.is_dead = 0; - res->attr.block.is_mb_head = 1; res->attr.block.irg.irg = irg; res->attr.block.backedge = new_backedge_arr(irg->obst, arity); - res->attr.block.in_cg = NULL; - res->attr.block.cg_backedge = NULL; - res->attr.block.extblk = NULL; - res->attr.block.mb_depth = 0; - res->attr.block.entity = NULL; - set_Block_matured(res, 1); - set_Block_block_visited(res, 0); /* Create and initialize array for Phi-node construction. */ if (get_irg_phase_state(irg) == phase_building) { @@ -144,66 +189,53 @@ class Block(Op): } ''' - java_add = ''' - public void addPred(Node node) { - binding_cons.add_immBlock_pred(ptr, node.ptr); - } - - public void mature() { - binding_cons.mature_immBlock(ptr); - } - - @Override - public Block getBlock() { - return null; - } - - public boolean blockVisited() { - return 0 != binding.Block_block_visited(ptr); - } - - public void markBlockVisited() { - binding.mark_Block_block_visited(ptr); - } - - public boolean isBad() { - return binding.is_Bad(ptr) != 0; - } - ''' - class Borrow(Binop): + """Returns the borrow bit from and implied subtractions of its 2 operands""" flags = [] class Bound(Op): - ins = [ "mem", "index", "lower", "upper" ] + """Performs a bounds-check: if lower <= index < upper then return index, + otherwise throw an exception.""" + ins = [ + ("mem", "memory dependency"), + ("index", "value to test"), + ("lower", "lower bound (inclusive)"), + ("upper", "upper bound (exclusive)"), + ] 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"), - ("res", "the checked index", "pn_Generic_other"), + ("M", "memory result"), + ("res", "the checked index"), + ("X_regular", "control flow when no exception occurs"), + ("X_except", "control flow when exception occured"), ] flags = [ "fragile", "highlevel" ] pinned = "exception" pinned_init = "op_pin_state_pinned" + throws_init = "false" attr_struct = "bound_attr" attrs_name = "bound" class Builtin(Op): - ins = [ "mem" ] + """performs a backend-specific builtin.""" + ins = [ + ("mem", "memory dependency"), + ] arity = "variable" outs = [ - ("M", "memory result", "pn_Generic_M"), - ("1_result", "first result", "pn_Generic_other"), + ("M", "memory result"), + ("1_result", "first result"), ] flags = [ "uses_memory" ] attrs = [ dict( - type = "ir_builtin_kind", - name = "kind" + type = "ir_builtin_kind", + name = "kind", + comment = "kind of builtin", ), dict( - type = "ir_type*", - name = "type" + type = "ir_type*", + name = "type", + comment = "method type for the builtin call", ) ] pinned = "memory" @@ -214,73 +246,93 @@ class Builtin(Op): ''' class Call(Op): - ins = [ "mem", "ptr" ] + """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", "memory dependency"), + ("ptr", "pointer to called code"), + ] arity = "variable" 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"), - ("T_result", "tuple containing all results", "pn_Generic_other"), - ("P_value_res_base", "pointer to memory register containing copied results passed by value"), + ("M", "memory result"), + ("T_result", "tuple containing all results"), + ("X_regular", "control flow when no exception occurs"), + ("X_except", "control flow when exception occured"), ] flags = [ "fragile", "uses_memory" ] attrs = [ dict( - type = "ir_type*", - name = "type" + type = "ir_type*", + name = "type", + comment = "type of the call (usually type of the called procedure)", ), dict( type = "unsigned", name = "tail_call", # the tail call attribute can only be set by analysis - init = "0" + init = "0", ) ] attr_struct = "call_attr" pinned = "memory" pinned_init = "op_pin_state_pinned" + throws_init = "false" init = ''' assert((get_unknown_type() == type) || is_Method_type(type)); ''' 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 = [ dict( - type = "ir_type*", - name = "type" + type = "ir_type*", + name = "type", + comment = "target type of the case", ) ] attr_struct = "cast_attr" init = "assert(is_atomic_type(type));" class Cmp(Binop): - outs = [ - ("False", "always false", "0"), - ("Eq", "equal", "1"), - ("Lt", "less", "2"), - ("Le", "less or equal", "pn_Cmp_Eq|pn_Cmp_Lt"), - ("Gt", "greater", "4"), - ("Ge", "greater or equal", "pn_Cmp_Eq|pn_Cmp_Gt"), - ("Lg", "less or greater ('not equal' for integer numbers)", "pn_Cmp_Lt|pn_Cmp_Gt"), - ("Leg", "less, equal or greater ('not unordered')", "pn_Cmp_Lt|pn_Cmp_Eq|pn_Cmp_Gt"), - ("Uo", "unordered", "8"), - ("Ue", "unordered or equal", "pn_Cmp_Uo|pn_Cmp_Eq"), - ("Ul", "unordered or less", "pn_Cmp_Uo|pn_Cmp_Lt"), - ("Ule", "unordered, less or equal", "pn_Cmp_Uo|pn_Cmp_Lt|pn_Cmp_Eq"), - ("Ug", "unordered or greater", "pn_Cmp_Uo|pn_Cmp_Gt"), - ("Uge", "onordered, greater or equal", "pn_Cmp_Uo|pn_Cmp_Gt|pn_Cmp_Eq"), - ("Ne", "unordered, less or greater ('not equal' for floatingpoint numbers)", "pn_Cmp_Uo|pn_Cmp_Lt|pn_Cmp_Gt"), - ("True", "always true", "15"), - ] + """Compares its two operands and checks whether a specified + relation (like less or equal) is fulfilled.""" flags = [] + mode = "mode_b" + attrs = [ + dict( + type = "ir_relation", + name = "relation", + comment = "Comparison relation" + ) + ] + attr_struct = "cmp_attr" class Cond(Op): - ins = [ "selector" ] + """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", "condition parameter"), + ] outs = [ ("false", "control flow if operand is \"false\""), ("true", "control flow if operand is \"true\""), @@ -289,191 +341,224 @@ class Cond(Op): pinned = "yes" attrs = [ dict( - name = "default_proj", - type = "long", - init = "0" + name = "default_proj", + type = "long", + init = "0", + comment = "Proj-number of default case for switch-Cond", ), dict( - name = "jmp_pred", - type = "cond_jmp_predicate", - init = "COND_JMP_PRED_NONE" + name = "jmp_pred", + type = "cond_jmp_predicate", + init = "COND_JMP_PRED_NONE", + comment = "can indicate the most likely jump", ) ] attr_struct = "cond_attr" class Confirm(Op): - ins = [ "value", "bound" ] + """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", "value to express a constraint for"), + ("bound", "value to compare against"), + ] mode = "get_irn_mode(irn_value)" flags = [ "highlevel" ] pinned = "yes" attrs = [ dict( - name = "cmp", - type = "pn_Cmp" + name = "relation", + type = "ir_relation", + comment = "relation of value to bound", ), ] attr_struct = "confirm_attr" attrs_name = "confirm" class Const(Op): - mode = "" + """Returns a constant value.""" flags = [ "constlike", "start_block" ] + block = "get_irg_start_block(irg)" + mode = "get_tarval_mode(tarval)" knownBlock = True pinned = "no" - attrs_name = "con" attrs = [ dict( - type = "tarval*", - name = "tarval", + type = "ir_tarval*", + name = "tarval", + comment = "constant value (a tarval object)", ) ] attr_struct = "const_attr" + attrs_name = "con" class Conv(Unop): + """Converts values between modes""" flags = [] attrs = [ dict( - name = "strict", - type = "int", - init = "0", - special = dict( - prefix = "strict", - init = "1" - ) + name = "strict", + type = "int", + init = "0", + comment = "force floating point to restrict precision even if backend computes in higher precision (deprecated)", ) ] attr_struct = "conv_attr" attrs_name = "conv" class CopyB(Op): - ins = [ "mem", "dst", "src" ] + """Copies a block of memory""" + ins = [ + ("mem", "memory dependency"), + ("dst", "destination address"), + ("src", "source address"), + ] 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"), + ("M", "memory result"), + ("X_regular", "control flow when no exception occurs"), + ("X_except", "control flow when exception occured"), ] - flags = [ "fragile", "highlevel", "uses_memory" ] + flags = [ "fragile", "uses_memory" ] attrs = [ dict( - name = "type", - type = "ir_type*" + name = "type", + type = "ir_type*", + comment = "type of copied data", ) ] attr_struct = "copyb_attr" attrs_name = "copyb" pinned = "memory" pinned_init = "op_pin_state_pinned" + throws_init = "false" class Div(Op): - ins = [ "mem", "left", "right" ] + """returns the quotient of its 2 operands""" + ins = [ + ("mem", "memory dependency"), + ("left", "first operand"), + ("right", "second operand"), + ] 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"), - ("res", "result of computation", "pn_Generic_other"), + ("M", "memory result"), + ("res", "result of computation"), + ("X_regular", "control flow when no exception occurs"), + ("X_except", "control flow when exception occured"), ] flags = [ "fragile", "uses_memory" ] - attrs_name = "divmod" + attrs_name = "div" attrs = [ dict( - type = "ir_mode*", - name = "resmode" + type = "ir_mode*", + name = "resmode", + comment = "mode of the result value", ), dict( name = "no_remainder", type = "int", init = "0", - special = dict( - suffix = "RL", - init = "1" - ) ) ] - attr_struct = "divmod_attr" - pinned = "exception" - op_index = 1 - arity_override = "oparity_binary" - -class DivMod(Op): - ins = [ "mem", "left", "right" ] - 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"), - ("res_div", "result of computation a/b", "pn_Generic_other"), - ("res_mod", "result of computation a%b"), - ] - flags = [ "fragile", "uses_memory" ] - attrs_name = "divmod" - attrs = [ - dict( - type = "ir_mode*", - name = "resmode" - ), - ] - attr_struct = "divmod_attr" + attr_struct = "div_attr" pinned = "exception" + throws_init = "false" op_index = 1 arity_override = "oparity_binary" class Dummy(Op): - ins = [] - flags = [ "cfopcode", "start_block", "constlike", "dump_noblock" ] + """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 pinned = "yes" block = "get_irg_start_block(irg)" class End(Op): - mode = "mode_X" - pinned = "yes" - arity = "dynamic" - flags = [ "cfopcode" ] - singleton = True + """Last node of a graph. It references nodes in endless loops (so called + keepalive edges)""" + mode = "mode_X" + pinned = "yes" + arity = "dynamic" + flags = [ "cfopcode" ] + knownBlock = True + block = "get_irg_end_block(irg)" + singleton = True + customSerializer = True class Eor(Binop): + """returns the result of a bitwise exclusive or operation of its operands""" flags = [ "commutative" ] class Free(Op): - ins = [ "mem", "ptr", "size" ] + """Frees a block of memory previously allocated by an Alloc node""" + ins = [ + ("mem", "memory dependency" ), + ("ptr", "pointer to the object to free"), + ("size", "number of objects to allocate" ), + ] mode = "mode_M" flags = [ "uses_memory" ] pinned = "yes" attrs = [ dict( - name = "type", - type = "ir_type*" + name = "type", + type = "ir_type*", + comment = "type of the allocated variable", ), dict( - name = "where", - type = "ir_where_alloc" + name = "where", + type = "ir_where_alloc", + comment = "whether allocation was on the stack or heap", ) ] attr_struct = "free_attr" class Id(Op): - ins = [ "pred" ] + """Returns its operand unchanged.""" + ins = [ + ("pred", "the value which is returned unchanged") + ] 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" ] + ins = [ + ("target", "target address of the jump"), + ] + flags = [ "cfopcode", "forking", "keep", "unknown_jump" ] class InstOf(Op): - ins = [ "store", "obj" ] + """Tests whether an object is an instance of a class-type""" + ins = [ + ("store", "memory dependency"), + ("obj", "pointer to object being queried") + ] 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"), - ("res", "checked object pointer", "pn_Generic_other"), + ("M", "memory result"), + ("res", "checked object pointer"), + ("X_regular", "control flow when no exception occurs"), + ("X_except", "control flow when exception occured"), ] flags = [ "highlevel" ] attrs = [ dict( - name = "type", - type = "ir_type*" + name = "type", + type = "ir_type*", + comment = "type to check ptr for", ) ] attr_struct = "io_attr" @@ -481,253 +566,376 @@ class InstOf(Op): 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): - ins = [ "mem", "ptr" ] + """Loads a value from memory (heap or stack).""" + ins = [ + ("mem", "memory dependency"), + ("ptr", "address to load from"), + ] 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"), - ("res", "result of load operation", "pn_Generic_other"), + ("M", "memory result"), + ("res", "result of load operation"), + ("X_regular", "control flow when no exception occurs"), + ("X_except", "control flow when exception occured"), ] flags = [ "fragile", "uses_memory" ] pinned = "exception" - pinned_init = "flags & cons_floats ? op_pin_state_floats : op_pin_state_pinned" attrs = [ dict( - type = "ir_mode*", - name = "mode", - java_name = "load_mode" + type = "ir_mode*", + name = "mode", + comment = "mode of the value to be loaded", + ), + dict( + type = "ir_volatility", + name = "volatility", + comment = "volatile loads are a visible side-effect and may not be optimized", + init = "flags & cons_volatile ? volatility_is_volatile : volatility_non_volatile", + ), + dict( + type = "ir_align", + name = "unaligned", + comment = "pointers to unaligned loads don't need to respect the load-mode/type alignments", + init = "flags & cons_unaligned ? align_non_aligned : align_is_aligned", ), ] attr_struct = "load_attr" constructor_args = [ dict( - type = "ir_cons_flags", - name = "flags", + type = "ir_cons_flags", + name = "flags", + comment = "specifies alignment, volatility and pin state", ), ] + pinned_init = "flags & cons_floats ? op_pin_state_floats : op_pin_state_pinned" + throws_init = "(flags & cons_throws_exception) != 0" class Minus(Unop): + """returns the difference between its operands""" flags = [] class Mod(Op): - ins = [ "mem", "left", "right" ] + """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", "memory dependency"), + ("left", "first operand"), + ("right", "second operand"), + ] 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"), - ("res", "result of computation", "pn_Generic_other"), + ("M", "memory result"), + ("res", "result of computation"), + ("X_regular", "control flow when no exception occurs"), + ("X_except", "control flow when exception occured"), ] flags = [ "fragile", "uses_memory" ] - attrs_name = "divmod" + attrs_name = "mod" attrs = [ dict( - type = "ir_mode*", - name = "resmode" + type = "ir_mode*", + name = "resmode", + comment = "mode of the result", ), ] - attr_struct = "divmod_attr" + attr_struct = "mod_attr" pinned = "exception" + throws_init = "false" op_index = 1 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): - ins = [ "sel", "false", "true" ] + """returns the false or true operand depending on the value of the sel + operand""" + ins = [ + ("sel", "value making the output selection"), + ("false", "selected if sel input is false"), + ("true", "selected if sel input is true"), + ] flags = [] pinned = "no" class NoMem(Op): - mode = "mode_M" - flags = [ "dump_noblock", "dump_noinput" ] - pinned = "yes" - knownBlock = True - singleton = True + """Placeholder node for cases where you don't need any memory input""" + mode = "mode_M" + flags = [ "dump_noblock", "dump_noinput" ] + pinned = "yes" + knownBlock = True + block = "get_irg_start_block(irg)" + 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 = [] attr_struct = "phi_attr" - java_noconstr = True - init = ''' + init = ''' + res->attr.phi.u.backedge = new_backedge_arr(irg->obst, arity);''' + init_after_opt = ''' /* Memory Phis in endless loops must be kept alive. As we can't distinguish these easily we keep all of them alive. */ - if (is_Phi(res) && mode == mode_M) - add_End_keepalive(get_irg_end(irg), res); - ''' + if (is_Phi(res) && mode == mode_M) + add_End_keepalive(get_irg_end(irg), res);''' class Pin(Op): - ins = [ "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", "value which is pinned"), + ] mode = "get_irn_mode(irn_op)" flags = [ "highlevel" ] pinned = "yes" class Proj(Op): - ins = [ "pred" ] - flags = [] - pinned = "no" - knownBlock = True - knownGraph = True - block = "get_nodes_block(irn_pred)" - graph = "get_irn_irg(irn_pred)" + """returns an entry of a tuple value""" + ins = [ + ("pred", "the tuple value from which a part is extracted"), + ] + flags = [] + pinned = "no" + knownBlock = True + knownGraph = True + block = "get_nodes_block(irn_pred)" + graph = "get_irn_irg(irn_pred)" + customSerializer = True attrs = [ dict( - type = "long", - name = "proj", - initname = "", - noprop = False, - ) - ] - attr_struct = "long" - -class Quot(Op): - ins = [ "mem", "left", "right" ] - 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"), - ("res", "result of computation", "pn_Generic_other"), - ] - flags = [ "fragile", "uses_memory" ] - attrs_name = "divmod" - attrs = [ - dict( - type = "ir_mode*", - name = "resmode" + type = "long", + name = "proj", + comment = "number of tuple component to be extracted", ), ] - attr_struct = "divmod_attr" - pinned = "exception" - op_index = 1 - arity_override = "oparity_binary" + attr_struct = "proj_attr" class Raise(Op): - ins = [ "mem", "exo_ptr" ] + """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", "memory dependency"), + ("exo_ptr", "pointer to exception object to be thrown"), + ] outs = [ - ("M", "memory result", "pn_Generic_M"), - ("X", "control flow to exception handler", "pn_Generic_X_regular"), + ("M", "memory result"), + ("X", "control flow to exception handler"), ] flags = [ "highlevel", "cfopcode" ] pinned = "yes" class Return(Op): - ins = [ "mem" ] + """Returns from the current function. Takes memory and return values as + operands.""" + ins = [ + ("mem", "memory dependency"), + ] arity = "variable" mode = "mode_X" flags = [ "cfopcode" ] pinned = "yes" class Rotl(Binop): + """Returns its first operand bits rotated left by the amount in the 2nd + operand""" flags = [] class Sel(Op): - ins = [ "mem", "ptr" ] + """Computes the address of a entity of a compound type given the base + address of an instance of the compound type.""" + ins = [ + ("mem", "memory dependency"), + ("ptr", "pointer to object to select from"), + ] arity = "variable" flags = [] mode = "is_Method_type(get_entity_type(entity)) ? mode_P_code : mode_P_data" pinned = "no" attrs = [ dict( - type = "ir_entity*", - name = "entity" + type = "ir_entity*", + name = "entity", + comment = "entity which is selected", ) ] 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"), ("P_frame_base", "frame base pointer"), - ("P_tls", "pointer to thread local storage segment"), ("T_args", "function arguments") ] - mode = "mode_T" - pinned = "yes" - flags = [ "cfopcode" ] - singleton = True + mode = "mode_T" + pinned = "yes" + flags = [ "cfopcode" ] + singleton = True + knownBlock = True + customSerializer = True + block = "get_irg_start_block(irg)" class Store(Op): - ins = [ "mem", "ptr", "value" ] + """Stores a value into memory (heap or stack).""" + ins = [ + ("mem", "memory dependency"), + ("ptr", "address to store to"), + ("value", "value to store"), + ] 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"), + ("M", "memory result"), + ("X_regular", "control flow when no exception occurs"), + ("X_except", "control flow when exception occured"), ] flags = [ "fragile", "uses_memory" ] pinned = "exception" attr_struct = "store_attr" pinned_init = "flags & cons_floats ? op_pin_state_floats : op_pin_state_pinned" + throws_init = "(flags & cons_throws_exception) != 0" + attrs = [ + dict( + type = "ir_volatility", + name = "volatility", + comment = "volatile stores are a visible side-effect and may not be optimized", + init = "flags & cons_volatile ? volatility_is_volatile : volatility_non_volatile", + ), + dict( + type = "ir_align", + name = "unaligned", + comment = "pointers to unaligned stores don't need to respect the load-mode/type alignments", + init = "flags & cons_unaligned ? align_non_aligned : align_is_aligned", + ), + ] constructor_args = [ dict( - type = "ir_cons_flags", - name = "flags", + type = "ir_cons_flags", + name = "flags", + comment = "specifies alignment, volatility and pin state", ), ] 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 pinned = "no" attrs = [ dict( - type = "ir_entity*", - name = "entity", - noprop = True + type = "ir_entity*", + name = "entity", + noprop = True, + comment = "entity whose address is returned", ) ] attr_struct = "symconst_attr" - java_noconstr = True + customSerializer = True + # constructor is written manually at the moment, because of the strange + # union argument + noconstructor = 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" - optimize = False 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 its opcode and giving it a new in array.""" arity = "variable" mode = "mode_T" pinned = "no" flags = [ "labeled" ] - java_noconstr = True 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)" - flags = [ "cfopcode", "start_block", "constlike", "dump_noblock" ] + flags = [ "start_block", "constlike", "dump_noblock" ] # Prepare node list