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