73d529d10b2d3f73db7afd45f057dd23d331195a
[libfirm] / scripts / gen_ir_io.py
1 #!/usr/bin/env python
2 import sys
3 from jinja2 import Environment, Template
4 from jinja2.filters import do_dictsort
5 from spec_util import is_dynamic_pinned, verify_node
6 import ir_spec
7
8 def format_args(arglist):
9         #argstrings = map(lambda arg : arg["name"], arglist)
10         #return ", ".join(argstrings)
11         s = ", ".join(arglist)
12         if len(s) == 0:
13           return "";
14         return ", " + s;
15
16 def format_ifnset(string, node, key):
17         if key in node:
18                 return ""
19         return string
20
21 def format_block(node):
22         if node.get("knownBlock"):
23                 return ""
24         else:
25                 return ", get_node(env, preds[0])"
26
27 env = Environment()
28 env.filters['args']   = format_args
29 env.filters['ifnset'] = format_ifnset
30 env.filters['block']  = format_block
31
32 def get_io_type(type, attrname, nodename):
33         if type == "tarval*":
34                 importcmd = "tarval *%s = read_tv(env);" % attrname
35                 exportcmd = "write_tarval(env, %(val)s);";
36         elif type == "ir_mode*":
37                 importcmd = "ir_mode *%s = read_mode(env);" % attrname
38                 exportcmd = "write_mode(env, %(val)s);"
39         elif type == "ir_entity*":
40                 importcmd = "ir_entity *%s = read_entity(env);" % attrname
41                 exportcmd = """fprintf(env->file, "%%ld ", get_entity_nr(%(val)s));"""
42         elif type == "ir_type*":
43                 importcmd = "ir_type *%s = read_type(env);" % attrname
44                 exportcmd = """fprintf(env->file, "%%ld ", get_type_nr(%(val)s));"""
45         elif type == "long" and nodename == "Proj":
46                 importcmd = "long %s = read_long(env);" % attrname
47                 exportcmd = """fprintf(env->file, "%%ld ", %(val)s);"""
48         elif type == "pn_Cmp" or type == "ir_where_alloc":
49                 importcmd = "%s %s = (%s) read_long(env);" % (type, attrname, type)
50                 exportcmd = """fprintf(env->file, "%%ld ", (long) %(val)s);"""
51         elif type == "ir_cons_flags" and nodename == "Store":
52                 importcmd = "ir_cons_flags %s = get_cons_flags(env);" % attrname
53                 exportcmd = """write_pin_state(env, irn);
54                         write_volatility(env, irn);
55                         write_align(env, irn);"""
56         elif type == "ir_cons_flags" and nodename == "Load":
57                 importcmd = "ir_cons_flags %s = get_cons_flags(env);" % attrname
58                 exportcmd = """write_pin_state(env, irn);
59                         write_volatility(env, irn);
60                         write_align(env, irn);"""
61         elif type == "op_pin_state":
62                 importcmd = "op_pin_state %s = read_pin_state(env);" % attrname
63                 exportcmd = "write_pin_state(env, irn);"
64         elif type == "ir_builtin_kind":
65                 importcmd = "ir_builtin_kind %s = read_builtin_kind(env);" % attrname
66                 exportcmd = "write_builtin_kind(env, irn);"
67         elif type == "cond_kind":
68                 importcmd = "cond_kind %s = read_cond_kind(env);" % attrname
69                 exportcmd = "write_cond_kind(env, irn);"
70         elif type == "cond_jmp_predicate":
71                 importcmd = "cond_jmp_predicate %s = read_cond_jmp_predicate(env);" % attrname
72                 exportcmd = "write_cond_jmp_predicate(env, irn);"
73         elif type == "int":
74                 importcmd = "int %s = (int) read_long(env);" % attrname
75                 exportcmd = """fprintf(env->file, "%%d ", %(val)s);"""
76         elif type == "long":
77                 importcmd = "long %s = read_long(env);" % attrname
78                 exportcmd = """fprintf(env->file, "%%ld ", %(val)s);"""
79         else:
80                 print "UNKNOWN TYPE: %s" % type
81                 importcmd = """// BAD: %s %s
82                         %s %s = (%s) 0;""" % (type, attrname, type, attrname, type)
83                 exportcmd = "// BAD: %s" % type
84         return (importcmd, exportcmd)
85
86 def prepare_attr(nodename, attr):
87         (importcmd,exportcmd) = get_io_type(attr["type"], attr["name"], nodename)
88         attr["importcmd"] = importcmd
89         attr["exportcmd"] = exportcmd % {"val": "get_%s_%s(irn)" % (nodename, attr["name"])}
90
91 def preprocess_node(nodename, node):
92         if "is_a" in node:
93                 parent = ir_spec.nodes[node["is_a"]]
94                 node["ins"] = parent["ins"]
95                 if "outs" in parent:
96                         node["outs"] = parent["outs"]
97         if "ins" not in node:
98                 node["ins"] = []
99         if "outs" in node:
100                 node["mode"] = "mode_T"
101         if "arity" not in node:
102                 node["arity"] = len(node["ins"])
103         if "attrs" not in node:
104                 node["attrs"] = []
105         if "constructor_args" not in node:
106                 node["constructor_args"] = []
107         if "pinned" not in node:
108                 node["pinned"] = "no"
109         # dynamic pin state means, we have to im/export that
110         if is_dynamic_pinned(node):
111                 newattr = dict(
112                         name = "state",
113                         type = "op_pin_state"
114                 )
115                 if "pinned_init" in node:
116                         newattr["init"] = node["pinned_init"]
117                 node["attrs"].append(newattr)
118
119         verify_node(nodename, node)
120
121         # construct node arguments
122         arguments = [ ]
123         initargs = [ ]
124         specialconstrs = [ ]
125         i = 0
126         for input in node["ins"]:
127                 arguments.append("prednodes[%i]" % i)
128                 i += 1
129
130         if node["arity"] == "variable" or node["arity"] == "dynamic":
131                 arguments.append("numpreds - %i" % (i + 1))
132                 arguments.append("prednodes + %i" % i)
133
134         if "mode" not in node:
135                 arguments.append("mode")
136
137         attrs_with_special = 0
138         for attr in node["attrs"]:
139                 prepare_attr(nodename, attr)
140                 if "special" in attr:
141                         if not "init" in attr:
142                                 print "Node type %s has an attribute with a \"special\" entry but without \"init\"" % nodename
143                                 sys.exit(1)
144
145                         if attrs_with_special != 0:
146                                 print "Node type %s has more than one attribute with a \"special\" entry" % nodename
147                                 sys.exit(1)
148
149                         attrs_with_special += 1
150
151                         if "prefix" in attr["special"]:
152                                 specialname = attr["special"]["prefix"] + nodename
153                         elif "suffix" in attr["special"]:
154                                 specialname = nodename + attr["special"]["suffix"]
155                         else:
156                                 print "Unknown special constructor type for node type %s" %nodename
157                                 sys.exit(1)
158
159                         specialconstrs.append(
160                                 dict(
161                                         constrname = specialname,
162                                         attrname = attr["name"],
163                                         value = attr["special"]["init"]
164                                 )
165                         )
166                 elif "init" in attr:
167                         if attr["type"] == "op_pin_state":
168                                 initfunc = "set_irn_pinned"
169                         else:
170                                 initfunc = "set_" + nodename + "_" + attr["name"]
171                         initargs.append((attr["name"], initfunc))
172                 else:
173                         arguments.append(attr["name"])
174
175         for arg in node["constructor_args"]:
176                 prepare_attr(nodename, arg)
177                 arguments.append(arg["name"])
178
179         node["arguments"] = arguments
180         node["initargs"] = initargs
181         node["special_constructors"] = specialconstrs
182
183 export_attrs_template = env.from_string('''
184         case iro_{{nodename}}:
185                 {{"write_mode(env, get_irn_mode(irn));"|ifnset(node,"mode")}}
186                 {% for attr in node.attrs %}{{attr.exportcmd}}
187                 {% endfor %}
188                 {% for attr in node.constructor_args %}{{attr.exportcmd}}
189                 {% endfor %}break;''')
190
191 import_attrs_template = env.from_string('''
192         case iro_{{nodename}}:
193         {
194                 {{"ir_mode *mode = read_mode(env);"|ifnset(node,"mode")}}
195                 {% for attr in node.attrs %}{{attr.importcmd}}
196                 {% endfor %}
197                 {% for attr in node.constructor_args %}{{attr.importcmd}}
198                 {% endfor %}
199                 {% for special in node.special_constructors %}if({{special.attrname}} == {{special.value}})
200                         newnode = new_r_{{special.constrname}}(current_ir_graph{{node|block}}{{node["arguments"]|args}});
201                 else{% endfor %}
202                 newnode = new_r_{{nodename}}(current_ir_graph{{node|block}}{{node["arguments"]|args}});
203                 {% for (initarg, initfunc) in node.initargs %}{{initfunc}}(newnode, {{initarg}});
204                 {% endfor %}
205                 break;
206         }
207 ''')
208
209 def main(argv):
210         """the main function"""
211
212         if len(argv) < 3:
213                 print "usage: %s specname(ignored) destdirectory" % argv[0]
214                 sys.exit(1)
215
216         gendir = argv[2]
217         sortednodes = do_dictsort(ir_spec.nodes)
218         # these nodes don't work correctly yet for some reasons...
219         niynodes = [ "EndExcept", "EndReg", "ASM" ]
220         # these have custom im-/export code
221         customcode = [ "Start", "End", "Anchor", "SymConst", "Block" ]
222
223         file = open(gendir + "/gen_irio_export.inl", "w");
224         for nodename, node in sortednodes:
225                 if nodename in niynodes:
226                         continue
227
228                 preprocess_node(nodename, node)
229                 if "abstract" not in node:
230                         file.write(export_attrs_template.render(vars()))
231         file.write("\n")
232         file.close()
233
234         file = open(gendir + "/gen_irio_import.inl", "w");
235         for nodename, node in sortednodes:
236                 if "abstract" in node or nodename in customcode or nodename in niynodes:
237                         continue
238                 file.write(import_attrs_template.render(vars()))
239         file.write("\n")
240         file.close()
241
242         file = open(gendir + "/gen_irio_lex.inl", "w");
243         for nodename, node in sortednodes:
244                 if "abstract" not in node and nodename not in niynodes:
245                         file.write("\tINSERT(\"" + nodename + "\", tt_iro, iro_" + nodename + ");\n");
246         file.close()
247
248 if __name__ == "__main__":
249         main(sys.argv)