106c85f85ede1ab2447928204b83e992822cfebe
[libfirm] / scripts / gen_ir.py
1 #!/usr/bin/env python
2 import sys
3 from jinja2 import Environment, Template
4 from jinja2.filters import do_dictsort
5 import ir_spec
6
7 def format_argdecls(node, first = False):
8         if not node.has_key("args"):
9                 return ""
10
11         res = ""
12         if not first:
13                 comma = ", "
14         else:
15                 comma = ""
16         for arg in node["args"]:
17                 res = res + (comma + arg["type"] + " " + arg["name"])
18                 comma = ", "
19         return res
20
21 def format_args(node):
22         if not node.has_key("args"):
23                 return ""
24
25         res = ""
26         for arg in node["args"]:
27                 res = res + (", " + arg["name"])
28         return res
29
30 def format_blockdecl(node):
31         if node.get("knownBlock"):
32                 return ""
33         else:
34                 return ", ir_node *block"
35
36 def format_block(node):
37         if node.get("knownBlock"):
38                 return ""
39         else:
40                 return ", block"
41
42 def format_curblock(node):
43         if node.get("knownBlock"):
44                 return ""
45         else:
46                 return ", current_ir_graph->current_block"
47
48 def format_insdecl(node):
49         arity = node["arity"]
50         if arity == "variable" and len(node["ins"]) == 0 or arity == "dynamic" or arity == 0:
51                 return ""
52
53         if arity == "variable":
54                 insarity = len(node["ins"])
55                 res = "int r_arity = arity + " + `insarity` + ";\n\tir_node **r_in;\n\t" \
56                         + "NEW_ARR_A(ir_node *, r_in, r_arity);\n\t"
57                 i = 0
58                 for input in node["ins"]:
59                         res += "r_in[" + `i` + "] = irn_" + input + ";\n\t"
60                         i += 1
61                 res += "memcpy(&r_in[" + `insarity` + "], in, sizeof(ir_node *) * arity);\n\t"
62         else:
63                 res = "ir_node *in[" + `arity` + "];\n\t"
64                 i = 0
65                 for input in node["ins"]:
66                         res += "in[" + `i` + "] = irn_" + input + ";\n\t"
67                         i += 1
68         return res
69
70 def format_arity_and_ins(node):
71         arity = node["arity"]
72         if arity == "dynamic":
73                 return "-1, NULL"
74         elif arity == "variable":
75                 if len(node["ins"]) == 0:
76                         return "arity, in"
77                 else:
78                         return "r_arity, r_in"
79         elif arity == 0:
80                 return "0, NULL"
81         else:
82                 return `arity` + ", in"
83
84 env = Environment()
85 env.filters['argdecls']  = format_argdecls
86 env.filters['args']      = format_args
87 env.filters['blockdecl'] = format_blockdecl
88 env.filters['block']     = format_block
89 env.filters['curblock']  = format_curblock
90 env.filters['insdecl']       = format_insdecl
91 env.filters['arity_and_ins'] = format_arity_and_ins
92
93 def add_attr(list, type, name, init = None, initname = None):
94         if initname == None:
95                 initname = "." + name
96         if init != None:
97                 list.append(dict(type = type, name = name, init = init, initname = initname))
98         else:
99                 list.append(dict(type = type, name = name, initname = initname))
100
101 def prepare_attr(attr):
102         if "init" in attr:
103                 return dict(type = attr["type"], name = attr["name"], init = attr["init"])
104         else:
105                 return dict(type = attr["type"], name = attr["name"])
106
107 def preprocess_node(nodename, node):
108         print "nodename: " + nodename
109         if "is_a" in node:
110                 parent = ir_spec.nodes[node["is_a"]]
111                 node["ins"] = parent["ins"]
112                 if "outs" in parent:
113                         node["outs"] = parent["outs"]
114         if "ins" not in node:
115                 node["ins"] = []
116         if "outs" in node:
117                 node["mode"] = "mode_T"
118         if "arity" not in node:
119                 node["arity"] = len(node["ins"])
120         if "attrs" not in node:
121                 node["attrs"] = []
122         if "constructor_args" not in node:
123                 node["constructor_args"] = []
124         if "attrs_name" not in node:
125                 node["attrs_name"] = nodename.lower()
126         if "block" not in node:
127                 node["block"] = "block"
128         if "nodbginfo" in node:
129                 node["db"] = "NULL"
130                 node["dbdecl"] = ""
131                 node["dbdeclnocomma"] = ""
132         else:
133                 node["db"] = "db"
134                 node["dbdecl"] = "dbg_info *db, "
135                 node["dbdeclnocomma"] = "dbg_info *db"
136
137         # construct node arguments
138         arguments = [ ]
139         initargs = [ ]
140         initattrs = [ ]
141         specialconstrs = [ ]
142         i = 0
143         for input in node["ins"]:
144                 print "ins: " + input
145                 arguments.append(dict(type = "ir_node *", name = "irn_" + input))
146                 i += 1
147
148         # Special case for Builtin...
149         if nodename == "Builtin":
150                 for attr in node["attrs"]:
151                         if attr["name"] == "kind":
152                                 arguments.append(prepare_attr(attr))
153
154         if node["arity"] == "variable":
155                 arguments.append(dict(type = "int", name = "arity"))
156                 arguments.append(dict(type = "ir_node **", name = "in"))
157
158         if "mode" not in node:
159                 arguments.append(dict(type = "ir_mode *", name = "mode"))
160                 node["mode"] = "mode"
161
162         attrs_with_special = 0
163         for attr in node["attrs"]:
164                 print "attr: " + attr["name"]
165                 if nodename == "Builtin" and attr["name"] == "kind":
166                         continue
167
168                 if "initname" not in attr:
169                         attr["initname"] = "." + attr["name"]
170
171                 # "special" stuff does not work at all, yet
172                 if "special" in attr:
173                         if not "init" in attr:
174                                 print "Node type %s has an attribute with a \"special\" entry but without \"init\"" % nodename
175                                 sys.exit(1)
176
177                         if attrs_with_special != 0:
178                                 print "Node type %s has more than one attribute with a \"special\" entry" % nodename
179                                 sys.exit(1)
180
181                         attrs_with_special += 1
182
183                         if "prefix" in attr["special"]:
184                                 specialname = attr["special"]["prefix"] + nodename
185                         elif "suffix" in attr["special"]:
186                                 specialname = nodename + attr["special"]["suffix"]
187                         else:
188                                 print "Unknown special constructor type for node type %s" %nodename
189                                 sys.exit(1)
190
191                         specialconstrs.append(
192                                 dict(
193                                         constrname = specialname,
194                                         attrname = attr["name"],
195                                         value = attr["special"]["init"]
196                                 )
197                         )
198                 elif "init" in attr:
199                         initargs.append(attr["name"])
200                 else:
201                         arguments.append(prepare_attr(attr))
202
203         for arg in node["constructor_args"]:
204                 arguments.append(prepare_attr(arg))
205                 if arg["type"] == "ir_cons_flags":
206                         name = arg["name"]
207                         initattrs.append(dict(initname = ".exc.pin_state",
208                                 init = name + " & cons_floats ? op_pin_state_floats : op_pin_state_pinned"))
209                         initattrs.append(dict(initname = ".volatility",
210                                 init = name + " & cons_volatile ? volatility_is_volatile : volatility_non_volatile"))
211                         initattrs.append(dict(initname = ".aligned",
212                                 init = name + " & cons_unaligned ? align_non_aligned : align_is_aligned"))
213
214         node["args"] = arguments
215         node["initargs"] = initargs
216         node["initattrs"] = initattrs
217         node["special_constructors"] = specialconstrs
218
219 #############################
220
221 node_template = env.from_string('''
222 ir_node *new_rd_{{nodename}}({{node["dbdecl"]}}ir_graph *irg{{node|blockdecl}}{{node|argdecls}})
223 {
224         ir_node *res;
225         ir_graph *rem = current_ir_graph;
226         {{node|insdecl}}
227         current_ir_graph = irg;
228         res = new_ir_node({{node["db"]}}, irg, {{node["block"]}}, op_{{nodename}}, {{node["mode"]}}, {{node|arity_and_ins}});
229         {% for attr in node["attrs"] -%}
230                 res->attr.{{node["attrs_name"]}}{{attr["initname"]}} =
231                 {%- if "init" in attr %} {{ attr["init"] -}};
232                 {%- else              %} {{ attr["name"] -}};
233                 {% endif %}
234         {% endfor %}
235         {%- for attr in node["initattrs"] -%}
236                 res->attr.{{node["attrs_name"]}}{{attr["initname"]}} = {{ attr["init"] -}};
237         {% endfor %}
238         {{- node["init"] }}
239         {% if node["optimize"] != False -%}
240                 res = optimize_node(res);
241         {% endif -%}
242         IRN_VRFY_IRG(res, irg);
243         current_ir_graph = rem;
244         return res;
245 }
246
247 ir_node *new_r_{{nodename}}(ir_graph *irg{{node|blockdecl}}{{node|argdecls}})
248 {
249         {% if node["nodbginfo"] -%}
250                 return new_rd_{{nodename}}(irg{{node|block}}{{node|args}});
251         {%- else -%}
252                 return new_rd_{{nodename}}(NULL, irg{{node|block}}{{node|args}});
253         {%- endif %}
254 }
255
256 ir_node *new_d_{{nodename}}({{node["dbdeclnocomma"]}}{{node|argdecls(node["nodbginfo"])}})
257 {
258         ir_node *res;
259         {{ node["d_pre"] }}
260         {% if node["nodbginfo"] -%}
261                 res = new_rd_{{nodename}}(current_ir_graph{{node|curblock}}{{node|args}});
262         {%- else -%}
263                 res = new_rd_{{nodename}}(db, current_ir_graph{{node|curblock}}{{node|args}});
264         {%- endif %}
265         {{ node["d_post"] }}
266         return res;
267 }
268
269 ''')
270
271 #############################
272
273 def main(argv):
274         """the main function"""
275
276         if len(argv) < 3:
277                 print "usage: %s specname(ignored) destdirectory" % argv[0]
278                 sys.exit(1)
279
280         gendir = argv[2]
281
282         # List of TODOs
283         niymap = ["Alloc", "Anchor", "ASM", "Bad", "Bound", "Break", "Builtin",
284                 "Call", "CallBegin", "Cast", "Const", "Const_type", "Const_long", "CopyB",
285                 "defaultProj", "Div", "DivRL", "DivMod", "EndReg", "EndExcept",
286                 "Filter", "InstOf", "Mod", "NoMem", "Phi", "Quot", "Raise",
287                 "simpleSel", "strictConv", "SymConst", "SymConst_type", "Sync"]
288
289         file = open(gendir + "/gen_ir_cons_py.c.inl", "w")
290         for nodename, node in do_dictsort(ir_spec.nodes):
291                 if nodename in niymap:
292                         continue
293                 preprocess_node(nodename, node)
294                 if not "abstract" in node:
295                         file.write(node_template.render(vars()))
296         file.write("\n")
297         file.close()
298
299 if __name__ == "__main__":
300         main(sys.argv)