automatically generate code to allocate the 'frag_arr' for fragile nodes; improve...
[libfirm] / scripts / gen_ir.py
1 #!/usr/bin/env python
2 import sys
3 import re
4 from jinja2 import Environment, Template
5 from jinja2.filters import do_dictsort
6 from spec_util import is_dynamic_pinned, verify_node, isAbstract, setdefault
7 from ir_spec import nodes
8
9 def format_parameterlist(parameterlist):
10         return "\n".join(parameterlist)
11
12 def format_nodearguments(node):
13         arguments = map(lambda arg: arg["name"], node.arguments)
14         return format_parameterlist(arguments)
15
16 def format_nodeparameters(node):
17         parameters = map(lambda arg: arg["type"] + " " + arg["name"], node.arguments)
18         return format_parameterlist(parameters)
19
20 def format_blockparameter(node):
21         if hasattr(node, "knownBlock"):
22                 if hasattr(node, "knownGraph"):
23                         return ""
24                 return "ir_graph *irg"
25         else:
26                 return "ir_node *block"
27
28 def format_blockargument(node):
29         if hasattr(node, "knownBlock"):
30                 if hasattr(node, "knownGraph"):
31                         return ""
32                 return "irg"
33         else:
34                 return "block"
35
36 def format_irgassign(node):
37         if hasattr(node, "knownGraph"):
38                 return "ir_graph *irg = %s;\n" % node.graph
39
40         if hasattr(node, "knownBlock"):
41                 return ""
42         else:
43                 return "ir_graph *irg = get_Block_irg(block);\n"
44
45 def format_curblock(node):
46         if hasattr(node, "knownBlock"):
47                 if hasattr(node, "knownGraph"):
48                         return ""
49                 return "current_ir_graph"
50         else:
51                 return "current_ir_graph->current_block"
52
53 def format_insdecl(node):
54         arity = node.arity
55         if arity == "variable" and len(node.ins) == 0 or arity == "dynamic" or arity == 0:
56                 return ""
57
58         if arity == "variable":
59                 insarity = len(node.ins)
60                 res  = "int r_arity = arity + " + `insarity` + ";"
61                 res += "\n\tir_node **r_in;"
62                 res += "\n\tNEW_ARR_A(ir_node *, r_in, r_arity);"
63                 i = 0
64                 for input in node.ins:
65                         res += "\n\tr_in[" + `i` + "] = irn_" + input + ";"
66                         i += 1
67                 res += "\n\tmemcpy(&r_in[" + `insarity` + "], in, sizeof(ir_node *) * arity);\n\t"
68         else:
69                 res = "ir_node *in[" + `arity` + "];"
70                 i = 0
71                 for input in node.ins:
72                         res += "\n\tin[" + `i` + "] = irn_" + input + ";"
73                         i += 1
74         return res
75
76 def format_arity_and_ins(node):
77         arity = node.arity
78         if arity == "dynamic":
79                 return "-1, NULL"
80         elif arity == "variable":
81                 if len(node.ins) == 0:
82                         return "arity, in"
83                 else:
84                         return "r_arity, r_in"
85         elif arity == 0:
86                 return "0, NULL"
87         else:
88                 return `arity` + ", in"
89
90 def format_arity(node):
91         if hasattr(node, "arity_override"):
92                 return node.arity_override
93         arity = node.arity
94         if arity == "dynamic":
95                 return "oparity_dynamic"
96         if arity == "variable":
97                 return "oparity_variable"
98         if arity == 0:
99                 return "oparity_zero"
100         if arity == 1:
101                 return "oparity_unary"
102         if arity == 2:
103                 return "oparity_binary"
104         if arity == 3:
105                 return "oparity_trinary"
106         return "oparity_any"
107
108 def format_pinned(node):
109         pinned = node.pinned
110         if pinned == "yes":
111                 return "op_pin_state_pinned"
112         if pinned == "no":
113                 return "op_pin_state_floats"
114         if pinned == "exception":
115                 return "op_pin_state_exc_pinned"
116         if pinned == "memory":
117                 return "op_pin_state_mem_pinned"
118         print "WARNING: Unknown pinned state %s in format pined" % pinned
119         return ""
120
121 def format_flags(node):
122         flags = map(lambda x : "irop_flag_" + x, node.flags)
123         if flags == []:
124                 flags = [ "irop_flag_none" ]
125         return " | ".join(flags)
126
127 def format_attr_size(node):
128         if not hasattr(node, "attr_struct"):
129                 return "0"
130         return "sizeof(%s)" % node.attr_struct
131
132 def format_opindex(node):
133         if hasattr(node, "op_index"):
134                 return node.op_index
135         return "-1"
136
137 def filter_isnot(list, flag):
138         return filter(lambda x: not hasattr(x, flag), list)
139
140 def filter_hasnot(list, flag):
141         return filter(lambda x: flag not in x, list)
142
143 def format_arguments(string, voidwhenempty = False):
144         args = re.split('\s*\n\s*', string)
145         if args[0] == '':
146                 args = args[1:]
147         if len(args) > 0 and args[-1] == '':
148                 args = args[:-1]
149         if len(args) == 0 and voidwhenempty:
150                 return "void"
151         return ", ".join(args)
152
153 def format_parameters(string):
154         return format_arguments(string, voidwhenempty = True)
155
156 env = Environment()
157 env.filters['parameterlist']  = format_parameterlist
158 env.filters['nodearguments']  = format_nodearguments
159 env.filters['nodeparameters'] = format_nodeparameters
160 env.filters['blockparameter'] = format_blockparameter
161 env.filters['blockargument']  = format_blockargument
162 env.filters['irgassign']      = format_irgassign
163 env.filters['curblock']       = format_curblock
164 env.filters['insdecl']        = format_insdecl
165 env.filters['arity_and_ins']  = format_arity_and_ins
166 env.filters['arity']          = format_arity
167 env.filters['pinned']         = format_pinned
168 env.filters['flags']          = format_flags
169 env.filters['attr_size']      = format_attr_size
170 env.filters['opindex']        = format_opindex
171 env.filters['isnot']          = filter_isnot
172 env.filters['hasnot']         = filter_hasnot
173 env.filters['arguments']      = format_arguments
174 env.filters['parameters']     = format_parameters
175
176 def prepare_attr(attr):
177         if "init" in attr:
178                 return dict(type = attr["type"], name = attr["name"], init = attr["init"])
179         else:
180                 return dict(type = attr["type"], name = attr["name"])
181
182 def preprocess_node(node):
183         verify_node(node)
184
185         setdefault(node, "attrs_name", node.name.lower())
186         setdefault(node, "block", "block")
187
188         # construct node arguments
189         arguments = [ ]
190         initattrs = [ ]
191         specialconstrs = [ ]
192         for input in node.ins:
193                 arguments.append(dict(type = "ir_node *", name = "irn_" + input))
194
195         if node.arity == "variable" or node.arity == "dynamic":
196                 arguments.append(dict(type = "int", name = "arity"))
197                 arguments.append(dict(type = "ir_node **", name = "in"))
198
199         if not hasattr(node, "mode"):
200                 arguments.append(dict(type = "ir_mode *", name = "mode"))
201                 node.mode = "mode"
202
203         attrs_with_special = 0
204         for attr in node.attrs:
205                 attr.setdefault("initname", "." + attr["name"])
206
207                 if "special" in attr:
208                         if not "init" in attr:
209                                 print "Node type %s has an attribute with a \"special\" entry but without \"init\"" % node.name
210                                 sys.exit(1)
211
212                         if attrs_with_special != 0:
213                                 print "Node type %s has more than one attribute with a \"special\" entry" % node.name
214                                 sys.exit(1)
215
216                         attrs_with_special += 1
217
218                         if "prefix" in attr["special"]:
219                                 specialname = attr["special"]["prefix"] + node.name
220                         elif "suffix" in attr["special"]:
221                                 specialname = node.name + attr["special"]["suffix"]
222                         else:
223                                 print "Unknown special constructor type for node type %s" % node.name
224                                 sys.exit(1)
225
226                         specialconstrs.append(
227                                 dict(
228                                         constrname = specialname,
229                                         attr = attr
230                                 )
231                         )
232                 elif not "init" in attr:
233                         arguments.append(prepare_attr(attr))
234
235         # dynamic pin state means more constructor arguments
236         if is_dynamic_pinned(node):
237                 if hasattr(node, "pinned_init"):
238                         initattrs.append(dict(
239                                 initname = ".exc.pin_state",
240                                 init     = node.pinned_init
241                         ))
242                 else:
243                         node.constructor_args.append(
244                                 dict(
245                                         name = "pin_state",
246                                         type = "op_pin_state"
247                                 )
248                         )
249                         initattrs.append(dict(
250                                 initname = ".exc.pin_state",
251                                 init     = "pin_state"
252                         ))
253
254         for arg in node.constructor_args:
255                 arguments.append(prepare_attr(arg))
256                 if arg["type"] == "ir_cons_flags":
257                         name = arg["name"]
258                         initattrs.append(dict(initname = ".exc.pin_state",
259                                 init = name + " & cons_floats ? op_pin_state_floats : op_pin_state_pinned"))
260                         initattrs.append(dict(initname = ".volatility",
261                                 init = name + " & cons_volatile ? volatility_is_volatile : volatility_non_volatile"))
262                         initattrs.append(dict(initname = ".aligned",
263                                 init = name + " & cons_unaligned ? align_non_aligned : align_is_aligned"))
264
265         node.arguments = arguments
266         node.initattrs = initattrs
267         node.special_constructors = specialconstrs
268
269 #############################
270
271 constructor_template = env.from_string('''
272
273 ir_node *new_rd_{{node.constrname}}(
274         {%- filter parameters %}
275                 dbg_info *dbgi
276                 {{node|blockparameter}}
277                 {{node|nodeparameters}}
278         {% endfilter %})
279 {
280         ir_node *res;
281         ir_graph *rem = current_ir_graph;
282         {{node|irgassign}}
283         {{node|insdecl}}
284         current_ir_graph = irg;
285         res = new_ir_node(
286                 {%- filter arguments %}
287                         dbgi
288                         irg
289                         {{node.block}}
290                         op_{{node.name}}
291                         {{node.mode}}
292                         {{node|arity_and_ins}}
293                 {% endfilter %});
294         {%- for attr in node.attrs %}
295         res->attr.{{node.attrs_name}}{{attr["initname"]}} =
296                 {%- if "init" in attr %} {{ attr["init"] -}};
297                 {%- else              %} {{ attr["name"] -}};
298                 {%- endif %}
299         {%- endfor %}
300         {%- for attr in node.initattrs %}
301         res->attr.{{node.attrs_name}}{{attr["initname"]}} = {{ attr["init"] -}};
302         {%- endfor %}
303         {{- node.init }}
304         {%- if node.optimize != False %}
305         res = optimize_node(res);
306         {%- endif %}
307         IRN_VRFY_IRG(res, irg);
308         current_ir_graph = rem;
309         return res;
310 }
311
312 ir_node *new_r_{{node.constrname}}(
313                 {%- filter parameters %}
314                         {{node|blockparameter}}
315                         {{node|nodeparameters}}
316                 {% endfilter %})
317 {
318         return new_rd_{{node.constrname}}(
319                 {%- filter arguments %}
320                         NULL
321                         {{node|blockargument}}
322                         {{node|nodearguments}}
323                 {% endfilter %});
324 }
325
326 ir_node *new_d_{{node.constrname}}(
327                 {%- filter parameters %}
328                         dbg_info *dbgi
329                         {{node|nodeparameters}}
330                 {% endfilter %})
331 {
332         ir_node *res;
333         res = new_rd_{{node.constrname}}(
334                 {%- filter parameters %}
335                         dbgi
336                         {{node|curblock}}
337                         {{node|nodearguments}}
338                 {% endfilter %});
339         {%- if "fragile" in node.flags %}
340         firm_alloc_frag_arr(res, op_{{node.name}}, &res->attr.except.frag_arr);
341         {%- endif %}
342         return res;
343 }
344
345 ir_node *new_{{node.constrname}}(
346                 {%- filter parameters %}
347                         {{node|nodeparameters}}
348                 {% endfilter %})
349 {
350         return new_d_{{node.constrname}}(
351                 {%- filter arguments %}
352                         NULL
353                         {{node|nodearguments}}
354                 {% endfilter %});
355 }
356 ''')
357
358 irnode_h_template = env.from_string('''
359 /* Warning: automatically generated code */
360
361 {%- for node in nodes|isnot('custom_is') %}
362 static inline int _is_{{node.name}}(const ir_node *node)
363 {
364         assert(node != NULL);
365         return _get_irn_op(node) == op_{{node.name}};
366 }
367 {%- endfor -%}
368
369 {% for node in nodes %}
370 #define is_{{node.name}}(node)    _is_{{node.name}}(node)
371 {%- endfor %}
372
373 ''')
374
375 irnode_template = env.from_string('''
376 /* Warning: automatically generated code */
377 {% for node in nodes %}
378 int (is_{{node.name}})(const ir_node *node)
379 {
380         return _is_{{node.name}}(node);
381 }
382 {% endfor %}
383
384 {%- for node in nodes %}
385 {%- for attr in node.attrs|hasnot("noprop") %}
386 {{attr.type}} (get_{{node.name}}_{{attr.name}})(const ir_node *node)
387 {
388         assert(is_{{node.name}}(node));
389         return node->attr.{{node.attrs_name}}.{{attr.name}};
390 }
391
392 void (set_{{node.name}}_{{attr.name}})(ir_node *node, {{attr.type}} {{attr.name}})
393 {
394         assert(is_{{node.name}}(node));
395         node->attr.{{node.attrs_name}}.{{attr.name}} = {{attr.name}};
396 }
397 {% endfor -%}
398 {% endfor -%}
399
400 {%- for node in nodes %}
401 {%- for in in node.ins %}
402 ir_node *(get_{{node.name}}_{{in}})(const ir_node *node)
403 {
404         assert(is_{{node.name}}(node));
405         return get_irn_n(node, {{node.ins.index(in)}});
406 }
407
408 void (set_{{node.name}}_{{in}})(ir_node *node, ir_node *{{in}})
409 {
410         assert(is_{{node.name}}(node));
411         set_irn_n(node, {{node.ins.index(in)}}, {{in}});
412 }
413 {% endfor %}
414 {% endfor %}
415 ''')
416
417 irop_template = env.from_string('''
418 /* Warning: automatically generated code */
419 {% for node in nodes %}
420 ir_op *op_{{node.name}}; ir_op *get_op_{{node.name}}(void) { return op_{{node.name}}; }
421 {%- endfor %}
422
423 void init_op(void)
424 {
425         {% for node in nodes %}
426         op_{{node.name}} = new_ir_op(
427                 {%- filter arguments %}
428                         iro_{{node.name}}
429                         "{{node.name}}"
430                         {{node|pinned}}
431                         {{node|flags}}
432                         {{node|arity}}
433                         {{node|opindex}}
434                         {{node|attr_size}}
435                         NULL
436                 {% endfilter %});
437         {%- endfor %}
438
439         be_init_op();
440 }
441
442 void finish_op(void)
443 {
444         {% for node in nodes %}
445         free_ir_op(op_{{node.name}}); op_{{node.name}} = NULL;
446         {%- endfor %}
447 }
448
449 ''')
450
451 projnumbers_h_template = env.from_string('''
452 /* Warning: automatically generated code */
453
454 {% for node in nodes -%}
455 {% if node.outs %}
456 /**
457  * Projection numbers for result of {{node.name}} node (use for Proj nodes)
458  */
459 typedef enum {
460         {% for out in node.outs -%}
461         pn_{{node.name}}_{{out[0]}}
462         {%- if out.__len__() > 2 %} = {{out[2]}}{% endif %}, /**< {{out[1]}} */
463         {% endfor -%}
464         pn_{{node.name}}_max
465 } pn_{{node.name}};
466 {% endif %}
467 {%- endfor %}
468
469 ''')
470
471 opcodes_h_template = env.from_string('''
472 /* Warning: automatically generated code */
473 #ifndef FIRM_IR_OPCODES_H
474 #define FIRM_IR_OPCODES_H
475
476 /** The opcodes of the libFirm predefined operations. */
477 typedef enum ir_opcode {
478 {%- for node in nodes %}
479         iro_{{node.name}},
480 {%- endfor %}
481         iro_First = iro_{{nodes[0].name}},
482         iro_Last = iro_{{nodes[-1].name}},
483
484         beo_First,
485         /* backend specific nodes */
486         beo_Spill = beo_First,
487         beo_Reload,
488         beo_Perm,
489         beo_MemPerm,
490         beo_Copy,
491         beo_Keep,
492         beo_CopyKeep,
493         beo_Call,
494         beo_Return,
495         beo_AddSP,
496         beo_SubSP,
497         beo_IncSP,
498         beo_Start,
499         beo_FrameAddr,
500         beo_Barrier,
501         /* last backend node number */
502         beo_Last = beo_Barrier,
503         iro_MaxOpcode
504 } ir_opcode;
505
506 {% for node in nodes %}
507 FIRM_API ir_op *op_{{node.name}};
508 {%- endfor %}
509
510 {% for node in nodes %}
511 FIRM_API ir_op *get_op_{{node.name}}(void);
512 {%- endfor %}
513
514 #endif
515 ''')
516
517 #############################
518
519 def prepare_nodes():
520         real_nodes = []
521         for node in nodes:
522                 if isAbstract(node):
523                         continue
524                 real_nodes.append(node)
525
526         for node in real_nodes:
527                 preprocess_node(node)
528
529         return real_nodes
530
531 def main(argv):
532         if len(argv) < 3:
533                 print "usage: %s specname(ignored) destdirectory" % argv[0]
534                 sys.exit(1)
535
536         gendir = argv[2]
537         # hardcoded path to libfirm/include/libfirm
538         gendir2 = argv[2] + "/../../include/libfirm"
539
540         # List of TODOs
541         niymap = [ "ASM", "Const", "Phi", "SymConst", "Sync"]
542
543         real_nodes = prepare_nodes()
544         file = open(gendir + "/gen_ir_cons.c.inl", "w")
545         for node in real_nodes:
546                 if node.name in niymap:
547                         continue
548
549                 if not isAbstract(node) and not hasattr(node, "singleton"):
550                         file.write(constructor_template.render(vars()))
551
552                         if hasattr(node, "special_constructors"):
553                                 for special in node.special_constructors:
554                                         node.constrname = special["constrname"]
555                                         special["attr"]["init"] = special["attr"]["special"]["init"]
556                                         file.write(constructor_template.render(vars()))
557         file.write("\n")
558         file.close()
559
560         file = open(gendir + "/gen_irnode.h", "w")
561         file.write(irnode_h_template.render(nodes = real_nodes))
562         file.close()
563
564         file = open(gendir + "/gen_irnode.c.inl", "w")
565         file.write(irnode_template.render(nodes = real_nodes))
566         file.close()
567
568         file = open(gendir + "/gen_irop.c.inl", "w")
569         file.write(irop_template.render(nodes = real_nodes))
570         file.close()
571
572         file = open(gendir2 + "/projnumbers.h", "w")
573         file.write(projnumbers_h_template.render(nodes = real_nodes))
574         file.close()
575
576         file = open(gendir2 + "/opcodes.h", "w")
577         file.write(opcodes_h_template.render(nodes = real_nodes))
578         file.close()
579
580 main(sys.argv)