more fixes (sorry for the breakages...)
[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
7 from ir_spec import nodes
8
9 def format_argdecls(node, first = False, voidwhenempty = False):
10         if not node.has_key("args") or len(node["args"]) == 0:
11                 if voidwhenempty:
12                         return "void"
13                 else:
14                         return ""
15
16         res = ""
17         if not first:
18                 comma = ", "
19         else:
20                 comma = ""
21         for arg in node["args"]:
22                 res = res + (comma + arg["type"] + " " + arg["name"])
23                 comma = ", "
24         return res
25
26 def format_args(node, first = False):
27         if not node.has_key("args"):
28                 return ""
29
30         res = ""
31         if not first:
32                 comma = ", "
33         else:
34                 comma = ""
35         for arg in node["args"]:
36                 res = res + (comma + arg["name"])
37                 comma = ", "
38         return res
39
40 def format_blockdecl(node):
41         if node.get("knownBlock"):
42                 return ""
43         else:
44                 return ", ir_node *block"
45
46 def format_block(node):
47         if node.get("knownBlock"):
48                 return ""
49         else:
50                 return ", block"
51
52 def format_curblock(node):
53         if node.get("knownBlock"):
54                 return ""
55         else:
56                 return ", current_ir_graph->current_block"
57
58 def format_insdecl(node):
59         arity = node["arity"]
60         if arity == "variable" and len(node["ins"]) == 0 or arity == "dynamic" or arity == 0:
61                 return ""
62
63         if arity == "variable":
64                 insarity = len(node["ins"])
65                 res = "int r_arity = arity + " + `insarity` + ";\n\tir_node **r_in;\n\t" \
66                         + "NEW_ARR_A(ir_node *, r_in, r_arity);\n\t"
67                 i = 0
68                 for input in node["ins"]:
69                         res += "r_in[" + `i` + "] = irn_" + input + ";\n\t"
70                         i += 1
71                 res += "memcpy(&r_in[" + `insarity` + "], in, sizeof(ir_node *) * arity);\n\t"
72         else:
73                 res = "ir_node *in[" + `arity` + "];\n\t"
74                 i = 0
75                 for input in node["ins"]:
76                         res += "in[" + `i` + "] = irn_" + input + ";\n\t"
77                         i += 1
78         return res
79
80 def format_arity_and_ins(node):
81         arity = node["arity"]
82         if arity == "dynamic":
83                 return "-1, NULL"
84         elif arity == "variable":
85                 if len(node["ins"]) == 0:
86                         return "arity, in"
87                 else:
88                         return "r_arity, r_in"
89         elif arity == 0:
90                 return "0, NULL"
91         else:
92                 return `arity` + ", in"
93
94 def format_arity(node):
95         arity = node['arity']
96         if arity == "dynamic":
97                 return "oparity_dynamic"
98         if arity == "variable":
99                 return "oparity_variable"
100         if arity == 0:
101                 return "oparity_zero"
102         if arity == 1:
103                 return "oparity_unary"
104         if arity == 2:
105                 return "oparity_binary"
106         if arity == 3:
107                 return "oparity_trinary"
108         return "oparity_any"
109
110 def format_pinned(node):
111         pinned = node["pinned"]
112         if pinned == "yes":
113                 return "op_pin_state_pinned"
114         if pinned == "no":
115                 return "op_pin_state_floats"
116         if pinned == "exception":
117                 return "op_pin_state_exc_pinned"
118         if pinned == "memory":
119                 return "op_pin_state_mem_pinned"
120         print "WARNING: Unknown pinned state %s in format pined" % pinned
121         return ""
122
123 def format_flags(node):
124         flags = node['flags']
125         flags = re.split("\s*,\s*", flags)
126         flags = map(lambda x : "irop_flag_" + x, flags)
127         return " | ".join(flags)
128
129 def format_attr_size(node):
130         if "attr_struct" not in node:
131                 return "0"
132         return "sizeof(%s)" % node['attr_struct']
133
134 def format_opindex(node):
135         if "op_index" in node:
136                 return node["op_index"]
137         return "-1"
138
139 def filter_isnot(list, flag):
140         result = []
141         for nodename, node in list:
142                 if flag in node:
143                         continue
144                 result.append((nodename, node))
145         return result
146
147 env = Environment()
148 env.filters['argdecls']      = format_argdecls
149 env.filters['args']          = format_args
150 env.filters['blockdecl']     = format_blockdecl
151 env.filters['block']         = format_block
152 env.filters['curblock']      = format_curblock
153 env.filters['insdecl']       = format_insdecl
154 env.filters['arity_and_ins'] = format_arity_and_ins
155 env.filters['arity']         = format_arity
156 env.filters['pinned']        = format_pinned
157 env.filters['flags']         = format_flags
158 env.filters['attr_size']     = format_attr_size
159 env.filters['isnot']         = filter_isnot
160 env.filters['opindex']       = format_opindex
161
162 def add_attr(list, type, name, init = None, initname = None):
163         if initname == None:
164                 initname = "." + name
165         if init != None:
166                 list.append(dict(type = type, name = name, init = init, initname = initname))
167         else:
168                 list.append(dict(type = type, name = name, initname = initname))
169
170 def prepare_attr(attr):
171         if "init" in attr:
172                 return dict(type = attr["type"], name = attr["name"], init = attr["init"])
173         else:
174                 return dict(type = attr["type"], name = attr["name"])
175
176 def preprocess_node(nodename, node):
177         # set default attributes
178         if "is_a" in node:
179                 parent = nodes[node["is_a"]]
180                 node["ins"] = parent["ins"]
181                 if "op_index" in parent:
182                         node["op_index"] = parent["op_index"]
183                 if "pinned" in parent:
184                         node["pinned"] = parent["pinned"]
185                 if "outs" in parent:
186                         node["outs"] = parent["outs"]
187
188         if "outs" in node:
189                 node["mode"] = "mode_T"
190         node["db"] = "db"
191         node["dbdecl"] = "dbg_info *db, "
192         node["dbdeclnocomma"] = "dbg_info *db"
193
194         if "flags" not in node and "abstract" not in node:
195                 print "WARNING: no flags specified for %s (you should say at least 'none')\n" % nodename
196
197         node.setdefault("ins", [])
198         node.setdefault("arity", len(node["ins"]))
199         node.setdefault("attrs", [])
200         node.setdefault("constrname", nodename);
201         node.setdefault("constructor_args", [])
202         node.setdefault("attrs_name", nodename.lower())
203         node.setdefault("block", "block")
204         node.setdefault("flags", "none")
205
206         verify_node(nodename, node)
207
208         # construct node arguments
209         arguments = [ ]
210         initattrs = [ ]
211         specialconstrs = [ ]
212         for input in node["ins"]:
213                 arguments.append(dict(type = "ir_node *", name = "irn_" + input))
214
215         if node["arity"] == "variable" or node["arity"] == "dynamic":
216                 arguments.append(dict(type = "int", name = "arity"))
217                 arguments.append(dict(type = "ir_node **", name = "in"))
218
219         if "mode" not in node:
220                 arguments.append(dict(type = "ir_mode *", name = "mode"))
221                 node["mode"] = "mode"
222
223         attrs_with_special = 0
224         for attr in node["attrs"]:
225                 attr.setdefault("initname", "." + attr["name"])
226
227                 if "special" in attr:
228                         if not "init" in attr:
229                                 print "Node type %s has an attribute with a \"special\" entry but without \"init\"" % nodename
230                                 sys.exit(1)
231
232                         if attrs_with_special != 0:
233                                 print "Node type %s has more than one attribute with a \"special\" entry" % nodename
234                                 sys.exit(1)
235
236                         attrs_with_special += 1
237
238                         if "prefix" in attr["special"]:
239                                 specialname = attr["special"]["prefix"] + nodename
240                         elif "suffix" in attr["special"]:
241                                 specialname = nodename + attr["special"]["suffix"]
242                         else:
243                                 print "Unknown special constructor type for node type %s" % nodename
244                                 sys.exit(1)
245
246                         specialconstrs.append(
247                                 dict(
248                                         constrname = specialname,
249                                         attr = attr
250                                 )
251                         )
252                 elif not "init" in attr:
253                         arguments.append(prepare_attr(attr))
254
255         # dynamic pin state means more constructor arguments
256         if is_dynamic_pinned(node):
257                 if "pinned_init" in node:
258                         initattrs.append(dict(
259                                 initname = ".exc.pin_state",
260                                 init     = node["pinned_init"]
261                         ))
262                 else:
263                         node["constructor_args"].append(
264                                 dict(
265                                         name = "pin_state",
266                                         type = "op_pin_state"
267                                 )
268                         )
269                         initattrs.append(dict(
270                                 initname = ".exc.pin_state",
271                                 init     = "pin_state"
272                         ))
273
274         for arg in node["constructor_args"]:
275                 arguments.append(prepare_attr(arg))
276                 if arg["type"] == "ir_cons_flags":
277                         name = arg["name"]
278                         initattrs.append(dict(initname = ".exc.pin_state",
279                                 init = name + " & cons_floats ? op_pin_state_floats : op_pin_state_pinned"))
280                         initattrs.append(dict(initname = ".volatility",
281                                 init = name + " & cons_volatile ? volatility_is_volatile : volatility_non_volatile"))
282                         initattrs.append(dict(initname = ".aligned",
283                                 init = name + " & cons_unaligned ? align_non_aligned : align_is_aligned"))
284
285         node["args"] = arguments
286         node["initattrs"] = initattrs
287         node["special_constructors"] = specialconstrs
288
289 #############################
290
291 constructor_template = env.from_string('''
292
293 ir_node *new_rd_{{node["constrname"]}}({{node["dbdecl"]}}ir_graph *irg{{node|blockdecl}}{{node|argdecls}})
294 {
295         ir_node *res;
296         ir_graph *rem = current_ir_graph;
297         {{node|insdecl}}
298         current_ir_graph = irg;
299         res = new_ir_node({{node["db"]}}, irg, {{node["block"]}}, op_{{nodename}}, {{node["mode"]}}, {{node|arity_and_ins}});
300         {% for attr in node["attrs"] -%}
301                 res->attr.{{node["attrs_name"]}}{{attr["initname"]}} =
302                 {%- if "init" in attr %} {{ attr["init"] -}};
303                 {%- else              %} {{ attr["name"] -}};
304                 {% endif %}
305         {% endfor %}
306         {%- for attr in node["initattrs"] -%}
307                 res->attr.{{node["attrs_name"]}}{{attr["initname"]}} = {{ attr["init"] -}};
308         {%- endfor %}
309         {{- node["init"] }}
310         {% if node["optimize"] != False -%}
311                 res = optimize_node(res);
312         {% endif -%}
313         IRN_VRFY_IRG(res, irg);
314         current_ir_graph = rem;
315         return res;
316 }
317
318 ir_node *new_r_{{node["constrname"]}}(ir_graph *irg{{node|blockdecl}}{{node|argdecls}})
319 {
320         {% if node["nodbginfo"] -%}
321                 return new_rd_{{node["constrname"]}}(irg{{node|block}}{{node|args}});
322         {%- else -%}
323                 return new_rd_{{node["constrname"]}}(NULL, irg{{node|block}}{{node|args}});
324         {%- endif %}
325 }
326
327 ir_node *new_d_{{node["constrname"]}}({{node["dbdeclnocomma"]}}{{node|argdecls(node["nodbginfo"])}})
328 {
329         ir_node *res;
330         {{ node["d_pre"] }}
331         {% if node["nodbginfo"] -%}
332                 res = new_rd_{{node["constrname"]}}(current_ir_graph{{node|curblock}}{{node|args}});
333         {%- else -%}
334                 res = new_rd_{{node["constrname"]}}(db, current_ir_graph{{node|curblock}}{{node|args}});
335         {%- endif %}
336         {{ node["d_post"] }}
337         return res;
338 }
339
340 ir_node *new_{{node["constrname"]}}({{node|argdecls(True, True)}})
341 {
342         {% if node["nodbginfo"] -%}
343                 return new_d_{{node["constrname"]}}({{node|args(True)}});
344         {%- else -%}
345                 return new_d_{{node["constrname"]}}(NULL{{node|args}});
346         {%- endif %}
347 }
348 ''')
349
350 irnode_h_template = env.from_string('''
351 /* Warning: automatically generated code */
352
353 {% for nodename, node in nodes|isnot('custom_is') %}
354 static inline int _is_{{nodename}}(const ir_node *node)
355 {
356         assert(node != NULL);
357         return _get_irn_op(node) == op_{{nodename}};
358 }
359 {% endfor %}
360
361 {% for nodename, node in nodes %}
362 #define is_{{nodename}}(node)    _is_{{nodename}}(node)
363 {%- endfor %}
364 ''')
365
366 irnode_template = env.from_string('''
367 /* Warning: automatically generated code */
368 {% for nodename, node in nodes %}
369 int (is_{{nodename}})(const ir_node *node)
370 {
371         return _is_{{nodename}}(node);
372 }
373 {% endfor %}
374 ''')
375
376 irop_template = env.from_string('''
377 /* Warning: automatically generated code */
378 {% for nodename, node in nodes %}
379 ir_op *op_{{nodename}}; ir_op *get_op_{{nodename}}(void) { return op_{{nodename}}; }
380 {%- endfor %}
381
382 void init_op(void)
383 {
384         {% for nodename, node in nodes %}
385         op_{{nodename}} = new_ir_op(iro_{{nodename}}, "{{nodename}}", {{node|pinned}}, {{node|flags}}, {{node|arity}}, {{node|opindex}}, {{node|attr_size}}, NULL);
386         {%- endfor %}
387
388         be_init_op();
389 }
390
391 void finish_op(void)
392 {
393         {% for nodename, node in nodes %}
394         free_ir_op(op_{{nodename}}); op_{{nodename}} = NULL;
395         {%- endfor %}
396 }
397 ''')
398
399 #############################
400
401 def main(argv):
402         """the main function"""
403
404         if len(argv) < 3:
405                 print "usage: %s specname(ignored) destdirectory" % argv[0]
406                 sys.exit(1)
407
408         gendir = argv[2]
409
410         # List of TODOs
411         niymap = ["ASM", "CallBegin", "Const", "Const_type", "Const_long",
412                 "defaultProj", "Dummy", "Phi", "simpleSel", "SymConst", "SymConst_type",
413                 "Sync"]
414
415         file = open(gendir + "/gen_ir_cons.c.inl", "w")
416         for nodename, node in do_dictsort(nodes):
417                 preprocess_node(nodename, node)
418                 if nodename in niymap:
419                         continue
420                 if "abstract" not in node and "singleton" not in node:
421                         file.write(constructor_template.render(vars()))
422
423                         if "special_constructors" in node:
424                                 for special in node["special_constructors"]:
425                                         node["constrname"] = special["constrname"]
426                                         special["attr"]["init"] = special["attr"]["special"]["init"]
427                                         file.write(constructor_template.render(vars()))
428         file.write("\n")
429         file.close()
430
431         real_nodes = dict()
432         for nodename, node in nodes.iteritems():
433                 if "abstract" in node:
434                         continue
435                 real_nodes[nodename] = node
436         real_nodes = do_dictsort(real_nodes)
437
438         file = open(gendir + "/gen_irnode.h", "w")
439         file.write(irnode_h_template.render(nodes = real_nodes))
440         file.close()
441
442         file = open(gendir + "/gen_irnode.c.inl", "w")
443         file.write(irnode_template.render(nodes = real_nodes))
444         file.close()
445
446         file = open(gendir + "/gen_irop.c.inl", "w")
447         file.write(irop_template.render(nodes = real_nodes))
448         file.close()
449
450 if __name__ == "__main__":
451         main(sys.argv)