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