output documentation to file on request
[libfirm] / scripts / ir_spec.py
1 from spec_util import abstract, setnodedefaults
2
3 class Op(object):
4         """Base class for firm nodes"""
5 abstract(Op)
6
7 class Unop(Op):
8         """Unary nodes have exactly 1 input"""
9         name     = "unop"
10         ins      = [
11                 ("op",  "operand"),
12         ]
13         op_index = 0
14         pinned   = "no"
15 abstract(Unop)
16
17 class Binop(Op):
18         """Binary nodes have exactly 2 inputs"""
19         name     = "binop"
20         ins      = [
21                 ( "left",   "first operand" ),
22                 ( "right", "second operand" ),
23         ]
24         op_index = 0
25         pinned   = "no"
26 abstract(Binop)
27
28 class Add(Binop):
29         """returns the sum of its operands"""
30         flags = [ "commutative" ]
31
32 class Alloc(Op):
33         """allocates a block of memory.
34         It can be specified whether the variable should be allocated to the stack
35         or to the heap."""
36         ins   = [
37                 ("mem",   "memory dependency" ),
38                 ("count", "number of objects to allocate" ),
39         ]
40         outs  = [
41                 ("M",         "memory result"),
42                 ("res",       "pointer to newly allocated memory"),
43                 ("X_regular", "control flow when no exception occurs"),
44                 ("X_except",  "control flow when exception occured"),
45         ]
46         attrs = [
47                 dict(
48                         name    = "type",
49                         type    = "ir_type*",
50                         comment = "type of the allocated variable",
51                 ),
52                 dict(
53                         name    = "where",
54                         type    = "ir_where_alloc",
55                         comment = "whether to allocate the variable on the stack or heap",
56                 )
57         ]
58         flags       = [ "fragile", "uses_memory" ]
59         pinned      = "exception"
60         throws_init = "false"
61         pinned_init = "op_pin_state_pinned"
62         attr_struct = "alloc_attr"
63
64 class Anchor(Op):
65         """utiliy node used to "hold" nodes in a graph that might possibly not be
66         reachable by other means or which should be reachable immediately without
67         searching through the graph.
68         Each firm-graph contains exactly one anchor node whose address is always
69         known. All other well-known graph-nodes like Start, End, NoMem, Bad, ...
70         are found by looking at the respective Anchor operand."""
71         mode             = "mode_ANY"
72         arity            = "variable"
73         flags            = [ "dump_noblock" ]
74         pinned           = "yes"
75         attr_struct      = "irg_attr"
76         knownBlock       = True
77         singleton        = True
78         noconstructor    = True
79         customSerializer = True
80
81 class And(Binop):
82         """returns the result of a bitwise and operation of its operands"""
83         flags    = [ "commutative" ]
84
85 class ASM(Op):
86         """executes assembler fragments of the target machine"""
87         mode             = "mode_T"
88         arity            = "variable"
89         flags            = [ "keep", "uses_memory" ]
90         pinned           = "memory"
91         pinned_init      = "op_pin_state_pinned"
92         attr_struct      = "asm_attr"
93         attrs_name       = "assem"
94         customSerializer = True
95         attrs = [
96                 dict(
97                         name    = "input_constraints",
98                         type    = "ir_asm_constraint*",
99                         comment = "input constraints",
100                 ),
101                 dict(
102                         name    = "n_output_constraints",
103                         type    = "size_t",
104                         noprop  = True,
105                         comment = "number of output constraints",
106                 ),
107                 dict(
108                         name    = "output_constraints",
109                         type    = "ir_asm_constraint*",
110                         comment = "output constraints",
111                 ),
112                 dict(
113                         name    = "n_clobbers",
114                         type    = "size_t",
115                         noprop  = True,
116                         comment = "number of clobbered registers/memory",
117                 ),
118                 dict(
119                         name    = "clobbers",
120                         type    = "ident**",
121                         comment = "list of clobbered registers/memory",
122                 ),
123                 dict(
124                         name    = "text",
125                         type    = "ident*",
126                         comment = "assembler text",
127                 ),
128         ]
129         # constructor is written manually at the moment, because of the clobbers+
130         # constraints arrays needing special handling (2 arguments for 1 attribute)
131         noconstructor = True
132
133 class Bad(Op):
134         """Bad nodes indicate invalid input, which is values which should never be
135         computed.
136
137         The typical use case for the Bad node is removing unreachable code.
138         Frontends should set the current_block to Bad when it is clear that
139         following code must be unreachable (ie. after a goto or return statement).
140         Optimisations also set block predecessors to Bad when it becomes clear,
141         that a control flow edge can never be executed.
142
143         The gigo optimisations ensures that nodes with Bad as their block, get
144         replaced by Bad themselfes. Nodes with at least 1 Bad input get exchanged
145         with Bad too. Exception to this rule are Block, Phi, Tuple and End node;
146         This is because removing inputs from a Block is hairy operation (requiring,
147         Phis to be shortened too for example). So instead of removing block inputs
148         they are set to Bad, and the actual removal is left to the control flow
149         optimisation phase. Block, Phi, Tuple with only Bad inputs however are
150         replaced by Bad right away."""
151         flags         = [ "start_block", "dump_noblock" ]
152         pinned        = "yes"
153         knownBlock    = True
154         block         = "get_irg_start_block(irg)"
155         attr_struct   = "bad_attr"
156         init = '''
157         res->attr.bad.irg.irg = irg;
158         '''
159
160 class Deleted(Op):
161         """Internal node which is temporary set to nodes which are already removed
162         from the graph."""
163         mode             = "mode_Bad"
164         flags            = [ ]
165         pinned           = "yes"
166         noconstructor    = True
167         customSerializer = True # this has no serializer
168
169 class Block(Op):
170         """A basic block"""
171         mode             = "mode_BB"
172         knownBlock       = True
173         block            = "NULL"
174         pinned           = "yes"
175         arity            = "variable"
176         flags            = [ "labeled" ]
177         attr_struct      = "block_attr"
178         attrs            = [
179                 dict(
180                         name    = "entity",
181                         type    = "ir_entity*",
182                         comment = "entity representing this block",
183                         init    = "NULL",
184                 ),
185         ]
186         customSerializer = True
187
188         init = '''
189         res->attr.block.irg.irg     = irg;
190         res->attr.block.backedge    = new_backedge_arr(irg->obst, arity);
191         set_Block_matured(res, 1);
192
193         /* Create and initialize array for Phi-node construction. */
194         if (get_irg_phase_state(irg) == phase_building) {
195                 res->attr.block.graph_arr = NEW_ARR_D(ir_node *, irg->obst, irg->n_loc);
196                 memset(res->attr.block.graph_arr, 0, irg->n_loc * sizeof(ir_node*));
197         }
198         '''
199
200 class Borrow(Binop):
201         """Returns the borrow bit from and implied subtractions of its 2 operands"""
202         flags = []
203
204 class Bound(Op):
205         """Performs a bounds-check: if lower <= index < upper then return index,
206         otherwise throw an exception."""
207         ins    = [
208                 ("mem",    "memory dependency"),
209                 ("index",  "value to test"),
210                 ("lower",  "lower bound (inclusive)"),
211                 ("upper",  "upper bound (exclusive)"),
212         ]
213         outs  = [
214                 ("M",         "memory result"),
215                 ("res",       "the checked index"),
216                 ("X_regular", "control flow when no exception occurs"),
217                 ("X_except",  "control flow when exception occured"),
218         ]
219         flags  = [ "fragile", "highlevel" ]
220         pinned = "exception"
221         pinned_init = "op_pin_state_pinned"
222         throws_init = "false"
223         attr_struct = "bound_attr"
224
225 class Builtin(Op):
226         """performs a backend-specific builtin."""
227         ins      = [
228                 ("mem", "memory dependency"),
229         ]
230         arity    = "variable"
231         outs     = [
232                 ("M", "memory result"),
233                 # results follow here
234         ]
235         flags    = [ "uses_memory" ]
236         attrs    = [
237                 dict(
238                         type    = "ir_builtin_kind",
239                         name    = "kind",
240                         comment = "kind of builtin",
241                 ),
242                 dict(
243                         type    = "ir_type*",
244                         name    = "type",
245                         comment = "method type for the builtin call",
246                 )
247         ]
248         pinned      = "memory"
249         pinned_init = "op_pin_state_pinned"
250         attr_struct = "builtin_attr"
251         init   = '''
252         assert((get_unknown_type() == type) || is_Method_type(type));
253         '''
254
255 class Call(Op):
256         """Calls other code. Control flow is transfered to ptr, additional
257         operands are passed to the called code. Called code usually performs a
258         return operation. The operands of this return operation are the result
259         of the Call node."""
260         ins      = [
261                 ("mem",   "memory dependency"),
262                 ("ptr",   "pointer to called code"),
263         ]
264         arity    = "variable"
265         outs     = [
266                 ("M",                "memory result"),
267                 ("T_result",         "tuple containing all results"),
268                 ("X_regular",        "control flow when no exception occurs"),
269                 ("X_except",         "control flow when exception occured"),
270         ]
271         flags    = [ "fragile", "uses_memory" ]
272         attrs    = [
273                 dict(
274                         type    = "ir_type*",
275                         name    = "type",
276                         comment = "type of the call (usually type of the called procedure)",
277                 ),
278         ]
279         attr_struct = "call_attr"
280         pinned      = "memory"
281         pinned_init = "op_pin_state_pinned"
282         throws_init = "false"
283         init = '''
284         assert((get_unknown_type() == type) || is_Method_type(type));
285         '''
286
287 class Carry(Binop):
288         """Computes the value of the carry-bit that would result when adding the 2
289         operands"""
290         flags = [ "commutative" ]
291
292 class Cast(Unop):
293         """perform a high-level type cast"""
294         mode     = "get_irn_mode(irn_op)"
295         flags    = [ "highlevel" ]
296         attrs    = [
297                 dict(
298                         type    = "ir_type*",
299                         name    = "type",
300                         comment = "target type of the case",
301                 )
302         ]
303         attr_struct = "cast_attr"
304         init     = "assert(is_atomic_type(type));"
305
306 class Cmp(Binop):
307         """Compares its two operands and checks whether a specified
308            relation (like less or equal) is fulfilled."""
309         flags = []
310         mode  = "mode_b"
311         attrs = [
312                 dict(
313                         type    = "ir_relation",
314                         name    = "relation",
315                         comment = "Comparison relation"
316                 )
317         ]
318         attr_struct = "cmp_attr"
319
320 class Cond(Op):
321         """Conditionally change control flow."""
322         ins      = [
323                 ("selector",  "condition parameter"),
324         ]
325         outs     = [
326                 ("false", "control flow if operand is \"false\""),
327                 ("true",  "control flow if operand is \"true\""),
328         ]
329         flags    = [ "cfopcode", "forking" ]
330         pinned   = "yes"
331         attrs    = [
332                 dict(
333                         name    = "jmp_pred",
334                         type    = "cond_jmp_predicate",
335                         init    = "COND_JMP_PRED_NONE",
336                         comment = "can indicate the most likely jump",
337                 ),
338         ]
339         attr_struct = "cond_attr"
340
341 class Switch(Op):
342         """Change control flow. The destination is choosen based on an integer input value which is looked up in a table.
343
344         Backends can implement this efficiently using a jump table."""
345         ins    = [
346                 ("selector", "input selector"),
347         ]
348         outs   = [
349                 ("default", "control flow if no other case matches"),
350         ]
351         flags  = [ "cfopcode", "forking" ]
352         pinned = "yes"
353         attrs  = [
354                 dict(
355                         name    = "n_outs",
356                         type    = "unsigned",
357                         comment = "number of outputs (including pn_Switch_default)",
358                 ),
359                 dict(
360                         name    = "table",
361                         type    = "ir_switch_table*",
362                         comment = "table describing mapping from input values to Proj numbers",
363                 ),
364         ]
365         attr_struct = "switch_attr"
366         attrs_name  = "switcha"
367
368 class Confirm(Op):
369         """Specifies constraints for a value. This allows explicit representation
370         of path-sensitive properties. (Example: This value is always >= 0 on 1
371         if-branch then all users within that branch are rerouted to a confirm-node
372         specifying this property).
373
374         A constraint is specified for the relation between value and bound.
375         value is always returned.
376         Note that this node does NOT check or assert the constraint, it merely
377         specifies it."""
378         ins      = [
379                 ("value",  "value to express a constraint for"),
380                 ("bound",  "value to compare against"),
381         ]
382         mode     = "get_irn_mode(irn_value)"
383         flags    = [ "highlevel" ]
384         pinned   = "yes"
385         attrs    = [
386                 dict(
387                         name    = "relation",
388                         type    = "ir_relation",
389                         comment = "relation of value to bound",
390                 ),
391         ]
392         attr_struct = "confirm_attr"
393
394 class Const(Op):
395         """Returns a constant value."""
396         flags      = [ "constlike", "start_block" ]
397         block      = "get_irg_start_block(irg)"
398         mode       = "get_tarval_mode(tarval)"
399         knownBlock = True
400         pinned     = "no"
401         attrs      = [
402                 dict(
403                         type    = "ir_tarval*",
404                         name    = "tarval",
405                         comment = "constant value (a tarval object)",
406                 )
407         ]
408         attr_struct = "const_attr"
409         attrs_name  = "con"
410
411 class Conv(Unop):
412         """Converts values between modes"""
413         flags = []
414         attrs = [
415                 dict(
416                         name    = "strict",
417                         type    = "int",
418                         init    = "0",
419                         comment = "force floating point to restrict precision even if backend computes in higher precision (deprecated)",
420                 )
421         ]
422         attr_struct = "conv_attr"
423
424 class CopyB(Op):
425         """Copies a block of memory"""
426         ins   = [
427                 ("mem",  "memory dependency"),
428                 ("dst",  "destination address"),
429                 ("src",  "source address"),
430         ]
431         outs  = [
432                 ("M",         "memory result"),
433                 ("X_regular", "control flow when no exception occurs"),
434                 ("X_except",  "control flow when exception occured"),
435         ]
436         flags = [ "fragile", "uses_memory" ]
437         attrs = [
438                 dict(
439                         name    = "type",
440                         type    = "ir_type*",
441                         comment = "type of copied data",
442                 )
443         ]
444         attr_struct = "copyb_attr"
445         pinned      = "memory"
446         pinned_init = "op_pin_state_pinned"
447         throws_init = "false"
448
449 class Div(Op):
450         """returns the quotient of its 2 operands"""
451         ins   = [
452                 ("mem",   "memory dependency"),
453                 ("left",  "first operand"),
454                 ("right", "second operand"),
455         ]
456         outs  = [
457                 ("M",         "memory result"),
458                 ("res",       "result of computation"),
459                 ("X_regular", "control flow when no exception occurs"),
460                 ("X_except",  "control flow when exception occured"),
461         ]
462         flags = [ "fragile", "uses_memory" ]
463         attrs = [
464                 dict(
465                         type    = "ir_mode*",
466                         name    = "resmode",
467                         comment = "mode of the result value",
468                 ),
469                 dict(
470                         name = "no_remainder",
471                         type = "int",
472                         init = "0",
473                 )
474         ]
475         attr_struct = "div_attr"
476         pinned      = "exception"
477         throws_init = "false"
478         op_index    = 1
479         arity_override = "oparity_binary"
480
481 class Dummy(Op):
482         """A placeholder value. This is used when constructing cyclic graphs where
483         you have cases where not all predecessors of a phi-node are known. Dummy
484         nodes are used for the unknown predecessors and replaced later."""
485         ins        = []
486         flags      = [ "cfopcode", "start_block", "constlike", "dump_noblock" ]
487         knownBlock = True
488         pinned     = "yes"
489         block      = "get_irg_start_block(irg)"
490
491 class End(Op):
492         """Last node of a graph. It references nodes in endless loops (so called
493         keepalive edges)"""
494         mode             = "mode_X"
495         pinned           = "yes"
496         arity            = "dynamic"
497         flags            = [ "cfopcode" ]
498         knownBlock       = True
499         block            = "get_irg_end_block(irg)"
500         singleton        = True
501
502 class Eor(Binop):
503         """returns the result of a bitwise exclusive or operation of its operands"""
504         flags    = [ "commutative" ]
505
506 class Free(Op):
507         """Frees a block of memory previously allocated by an Alloc node"""
508         ins    = [
509                 ("mem",   "memory dependency" ),
510                 ("ptr",   "pointer to the object to free"),
511                 ("count", "number of objects to allocate" ),
512         ]
513         mode   = "mode_M"
514         flags  = [ "uses_memory" ]
515         pinned = "yes"
516         attrs  = [
517                 dict(
518                         name    = "type",
519                         type    = "ir_type*",
520                         comment = "type of the allocated variable",
521                 ),
522                 dict(
523                         name    = "where",
524                         type    = "ir_where_alloc",
525                         comment = "whether allocation was on the stack or heap",
526                 )
527         ]
528         attr_struct = "free_attr"
529
530 class Id(Op):
531         """Returns its operand unchanged."""
532         ins    = [
533            ("pred", "the value which is returned unchanged")
534         ]
535         pinned = "no"
536         flags  = []
537
538 class IJmp(Op):
539         """Jumps to the code in its argument. The code has to be in the same
540         function and the the destination must be one of the blocks reachable
541         by the tuple results"""
542         mode     = "mode_X"
543         pinned   = "yes"
544         ins      = [
545            ("target", "target address of the jump"),
546         ]
547         flags    = [ "cfopcode", "forking", "keep", "unknown_jump" ]
548
549 class InstOf(Op):
550         """Tests whether an object is an instance of a class-type"""
551         ins   = [
552            ("store", "memory dependency"),
553            ("obj",   "pointer to object being queried")
554         ]
555         outs  = [
556                 ("M",         "memory result"),
557                 ("res",       "checked object pointer"),
558                 ("X_regular", "control flow when no exception occurs"),
559                 ("X_except",  "control flow when exception occured"),
560         ]
561         flags = [ "highlevel" ]
562         attrs = [
563                 dict(
564                         name    = "type",
565                         type    = "ir_type*",
566                         comment = "type to check ptr for",
567                 )
568         ]
569         attr_struct = "io_attr"
570         pinned      = "memory"
571         pinned_init = "op_pin_state_floats"
572
573 class Jmp(Op):
574         """Jumps to the block connected through the out-value"""
575         mode     = "mode_X"
576         pinned   = "yes"
577         ins      = []
578         flags    = [ "cfopcode" ]
579
580 class Load(Op):
581         """Loads a value from memory (heap or stack)."""
582         ins   = [
583                 ("mem", "memory dependency"),
584                 ("ptr",  "address to load from"),
585         ]
586         outs  = [
587                 ("M",         "memory result"),
588                 ("res",       "result of load operation"),
589                 ("X_regular", "control flow when no exception occurs"),
590                 ("X_except",  "control flow when exception occured"),
591         ]
592         flags    = [ "fragile", "uses_memory" ]
593         pinned   = "exception"
594         attrs    = [
595                 dict(
596                         type      = "ir_mode*",
597                         name      = "mode",
598                         comment   = "mode of the value to be loaded",
599                 ),
600                 dict(
601                         type      = "ir_volatility",
602                         name      = "volatility",
603                         comment   = "volatile loads are a visible side-effect and may not be optimized",
604                         init      = "flags & cons_volatile ? volatility_is_volatile : volatility_non_volatile",
605                         to_flags  = "%s == volatility_is_volatile ? cons_volatile : 0"
606                 ),
607                 dict(
608                         type      = "ir_align",
609                         name      = "unaligned",
610                         comment   = "pointers to unaligned loads don't need to respect the load-mode/type alignments",
611                         init      = "flags & cons_unaligned ? align_non_aligned : align_is_aligned",
612                         to_flags  = "%s == align_non_aligned ? cons_unaligned : 0"
613                 ),
614         ]
615         attr_struct = "load_attr"
616         constructor_args = [
617                 dict(
618                         type    = "ir_cons_flags",
619                         name    = "flags",
620                         comment = "specifies alignment, volatility and pin state",
621                 ),
622         ]
623         pinned_init = "flags & cons_floats ? op_pin_state_floats : op_pin_state_pinned"
624         throws_init = "(flags & cons_throws_exception) != 0"
625
626 class Minus(Unop):
627         """returns the difference between its operands"""
628         flags = []
629
630 class Mod(Op):
631         """returns the remainder of its operands from an implied division.
632
633         Examples:
634
635         * mod(5,3)   produces 2
636         * mod(5,-3)  produces 2
637         * mod(-5,3)  produces -2
638         * mod(-5,-3) produces -2
639         """
640         ins   = [
641                 ("mem",   "memory dependency"),
642                 ("left",  "first operand"),
643                 ("right", "second operand"),
644         ]
645         outs  = [
646                 ("M",         "memory result"),
647                 ("res",       "result of computation"),
648                 ("X_regular", "control flow when no exception occurs"),
649                 ("X_except",  "control flow when exception occured"),
650         ]
651         flags = [ "fragile", "uses_memory" ]
652         attrs = [
653                 dict(
654                         type    = "ir_mode*",
655                         name    = "resmode",
656                         comment = "mode of the result",
657                 ),
658         ]
659         attr_struct = "mod_attr"
660         pinned      = "exception"
661         throws_init = "false"
662         op_index    = 1
663         arity_override = "oparity_binary"
664
665 class Mul(Binop):
666         """returns the product of its operands"""
667         flags = [ "commutative" ]
668
669 class Mulh(Binop):
670         """returns the upper word of the product of its operands (the part which
671         would not fit into the result mode of a normal Mul anymore)"""
672         flags = [ "commutative" ]
673
674 class Mux(Op):
675         """returns the false or true operand depending on the value of the sel
676         operand"""
677         ins    = [
678            ("sel",   "value making the output selection"),
679            ("false", "selected if sel input is false"),
680            ("true",  "selected if sel input is true"),
681         ]
682         flags  = []
683         pinned = "no"
684
685 class NoMem(Op):
686         """Placeholder node for cases where you don't need any memory input"""
687         mode          = "mode_M"
688         flags         = [ "dump_noblock", "dump_noinput" ]
689         pinned        = "yes"
690         knownBlock    = True
691         block         = "get_irg_start_block(irg)"
692         singleton     = True
693
694 class Not(Unop):
695         """returns the logical complement of a value. Works for integer values too.
696         If the input is false/zero then true/one is returned, otherwise false/zero
697         is returned."""
698         flags = []
699
700 class Or(Binop):
701         """returns the result of a bitwise or operation of its operands"""
702         flags = [ "commutative" ]
703
704 class Phi(Op):
705         """Choose a value based on control flow. A phi node has 1 input for each
706         predecessor of its block. If a block is entered from its nth predecessor
707         all phi nodes produce their nth input as result."""
708         pinned        = "yes"
709         arity         = "variable"
710         flags         = []
711         attr_struct   = "phi_attr"
712         init          = '''
713         res->attr.phi.u.backedge = new_backedge_arr(irg->obst, arity);'''
714         init_after_opt = '''
715         /* Memory Phis in endless loops must be kept alive.
716            As we can't distinguish these easily we keep all of them alive. */
717         if (is_Phi(res) && mode == mode_M)
718                 add_End_keepalive(get_irg_end(irg), res);'''
719         customSerializer = True
720
721 class Pin(Op):
722         """Pin the value of the node node in the current block. No users of the Pin
723         node can float above the Block of the Pin. The node cannot float behind
724         this block. Often used to Pin the NoMem node."""
725         ins      = [
726                 ("op", "value which is pinned"),
727         ]
728         mode     = "get_irn_mode(irn_op)"
729         flags    = [ "highlevel" ]
730         pinned   = "yes"
731
732 class Proj(Op):
733         """returns an entry of a tuple value"""
734         ins              = [
735                 ("pred", "the tuple value from which a part is extracted"),
736         ]
737         flags            = []
738         pinned           = "no"
739         knownBlock       = True
740         knownGraph       = True
741         block            = "get_nodes_block(irn_pred)"
742         graph            = "get_irn_irg(irn_pred)"
743         attrs      = [
744                 dict(
745                         type    = "long",
746                         name    = "proj",
747                         comment = "number of tuple component to be extracted",
748                 ),
749         ]
750         attr_struct = "proj_attr"
751
752 class Raise(Op):
753         """Raises an exception. Unconditional change of control flow. Writes an
754         explicit Except variable to memory to pass it to the exception handler.
755         Must be lowered to a Call to a runtime check function."""
756         ins    = [
757                 ("mem",     "memory dependency"),
758                 ("exo_ptr", "pointer to exception object to be thrown"),
759         ]
760         outs  = [
761                 ("M", "memory result"),
762                 ("X", "control flow to exception handler"),
763         ]
764         flags  = [ "highlevel", "cfopcode" ]
765         pinned = "yes"
766
767 class Return(Op):
768         """Returns from the current function. Takes memory and return values as
769         operands."""
770         ins      = [
771                 ("mem", "memory dependency"),
772         ]
773         arity    = "variable"
774         mode     = "mode_X"
775         flags    = [ "cfopcode" ]
776         pinned   = "yes"
777
778 class Rotl(Binop):
779         """Returns its first operand bits rotated left by the amount in the 2nd
780         operand"""
781         flags    = []
782
783 class Sel(Op):
784         """Computes the address of a entity of a compound type given the base
785         address of an instance of the compound type.
786
787         Optimisations assume that a Sel node can only produce a NULL pointer if the
788         ptr input was NULL."""
789         ins    = [
790                 ("mem", "memory dependency"),
791                 ("ptr", "pointer to object to select from"),
792         ]
793         arity  = "variable"
794         flags  = []
795         mode   = "is_Method_type(get_entity_type(entity)) ? mode_P_code : mode_P_data"
796         pinned = "no"
797         attrs  = [
798                 dict(
799                         type    = "ir_entity*",
800                         name    = "entity",
801                         comment = "entity which is selected",
802                 )
803         ]
804         attr_struct = "sel_attr"
805
806 class Shl(Binop):
807         """Returns its first operands bits shifted left by the amount of the 2nd
808         operand"""
809         flags = []
810
811 class Shr(Binop):
812         """Returns its first operands bits shifted right by the amount of the 2nd
813         operand. No special handling for the sign bit (zero extension)"""
814         flags = []
815
816 class Shrs(Binop):
817         """Returns its first operands bits shifted right by the amount of the 2nd
818         operand. The leftmost bit (usually the sign bit) stays the same
819         (sign extension)"""
820         flags = []
821
822 class Start(Op):
823         """The first node of a graph. Execution starts with this node."""
824         outs       = [
825                 ("X_initial_exec", "control flow"),
826                 ("M",              "initial memory"),
827                 ("P_frame_base",   "frame base pointer"),
828                 ("T_args",         "function arguments")
829         ]
830         mode             = "mode_T"
831         pinned           = "yes"
832         flags            = [ "cfopcode" ]
833         singleton        = True
834         knownBlock       = True
835         block            = "get_irg_start_block(irg)"
836
837 class Store(Op):
838         """Stores a value into memory (heap or stack)."""
839         ins   = [
840            ("mem",   "memory dependency"),
841            ("ptr",   "address to store to"),
842            ("value", "value to store"),
843         ]
844         outs  = [
845                 ("M",         "memory result"),
846                 ("X_regular", "control flow when no exception occurs"),
847                 ("X_except",  "control flow when exception occured"),
848         ]
849         flags    = [ "fragile", "uses_memory" ]
850         pinned   = "exception"
851         attr_struct = "store_attr"
852         pinned_init = "flags & cons_floats ? op_pin_state_floats : op_pin_state_pinned"
853         throws_init = "(flags & cons_throws_exception) != 0"
854         attrs = [
855                 dict(
856                         type      = "ir_volatility",
857                         name      = "volatility",
858                         comment   = "volatile stores are a visible side-effect and may not be optimized",
859                         init      = "flags & cons_volatile ? volatility_is_volatile : volatility_non_volatile",
860                         to_flags  = "%s == volatility_is_volatile ? cons_volatile : 0"
861                 ),
862                 dict(
863                         type      = "ir_align",
864                         name      = "unaligned",
865                         comment   = "pointers to unaligned stores don't need to respect the load-mode/type alignments",
866                         init      = "flags & cons_unaligned ? align_non_aligned : align_is_aligned",
867                         to_flags  = "%s == align_non_aligned ? cons_unaligned : 0"
868                 ),
869         ]
870         constructor_args = [
871                 dict(
872                         type    = "ir_cons_flags",
873                         name    = "flags",
874                         comment = "specifies alignment, volatility and pin state",
875                 ),
876         ]
877
878 class Sub(Binop):
879         """returns the difference of its operands"""
880         flags = []
881
882 class SymConst(Op):
883         """A symbolic constant.
884
885          - *symconst_type_size* The symbolic constant represents the size of a type.
886                                 The type of which the constant represents the size
887                                 is given explicitly.
888          - *symconst_type_align* The symbolic constant represents the alignment of a
889                                 type.  The type of which the constant represents the
890                                 size is given explicitly.
891          - *symconst_addr_ent*  The symbolic constant represents the address of an
892                                 entity (variable or method).  The variable is given
893                                 explicitly by a firm entity.
894          - *symconst_ofs_ent*   The symbolic constant represents the offset of an
895                                 entity in its owner type.
896          - *symconst_enum_const* The symbolic constant is a enumeration constant of
897                                 an enumeration type."""
898         mode       = "mode_P"
899         flags      = [ "constlike", "start_block" ]
900         knownBlock = True
901         pinned     = "no"
902         attrs      = [
903                 dict(
904                         type    = "ir_entity*",
905                         name    = "entity",
906                         noprop  = True,
907                         comment = "entity whose address is returned",
908                 )
909         ]
910         attr_struct = "symconst_attr"
911         customSerializer = True
912         # constructor is written manually at the moment, because of the strange
913         # union argument
914         noconstructor = True
915
916 class Sync(Op):
917         """The Sync operation unifies several partial memory blocks. These blocks
918         have to be pairwise disjunct or the values in common locations have to
919         be identical.  This operation allows to specify all operations that
920         eventually need several partial memory blocks as input with a single
921         entrance by unifying the memories with a preceding Sync operation."""
922         mode     = "mode_M"
923         flags    = []
924         pinned   = "no"
925         arity    = "dynamic"
926
927 class Tuple(Op):
928         """Builds a Tuple from single values.
929
930         This is needed to implement optimizations that remove a node that produced
931         a tuple.  The node can be replaced by the Tuple operation so that the
932         following Proj nodes have not to be changed. (They are hard to find due to
933         the implementation with pointers in only one direction.) The Tuple node is
934         smaller than any other node, so that a node can be changed into a Tuple by
935         just changing its opcode and giving it a new in array."""
936         arity  = "variable"
937         mode   = "mode_T"
938         pinned = "no"
939         flags  = [ "labeled" ]
940
941 class Unknown(Op):
942         """Returns an unknown (at compile- and runtime) value. It is a valid
943         optimisation to replace an Unknown by any other constant value."""
944         knownBlock = True
945         pinned     = "yes"
946         block      = "get_irg_start_block(irg)"
947         flags      = [ "start_block", "constlike", "dump_noblock" ]
948
949 # Prepare node list
950
951 def getOpList(namespace):
952         nodes = []
953         for t in namespace.values():
954                 if type(t) != type:
955                         continue
956
957                 if issubclass(t, Op):
958                         setnodedefaults(t)
959                         nodes.append(t)
960         return nodes
961
962 nodes = getOpList(globals())
963 nodes = sorted(nodes, lambda x,y: cmp(x.name, y.name))