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