redo pinned mode handling in spec generator
[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(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         # Special case for Builtin...
131         if nodename == "Builtin":
132                 for attr in node["attrs"]:
133                         if attr["name"] == "kind":
134                                 prepare_attr(nodename, attr)
135                                 arguments.append(attr["name"])
136
137         if node["arity"] == "variable" or node["arity"] == "dynamic":
138                 arguments.append("numpreds - %i" % (i + 1))
139                 arguments.append("prednodes + %i" % i)
140
141         if "mode" not in node:
142                 arguments.append("mode")
143
144         attrs_with_special = 0
145         for attr in node["attrs"]:
146                 if nodename == "Builtin" and attr["name"] == "kind":
147                         continue
148                 prepare_attr(nodename, attr)
149                 if "special" in attr:
150                         if not "init" in attr:
151                                 print "Node type %s has an attribute with a \"special\" entry but without \"init\"" % nodename
152                                 sys.exit(1)
153
154                         if attrs_with_special != 0:
155                                 print "Node type %s has more than one attribute with a \"special\" entry" % nodename
156                                 sys.exit(1)
157
158                         attrs_with_special += 1
159
160                         if "prefix" in attr["special"]:
161                                 specialname = attr["special"]["prefix"] + nodename
162                         elif "suffix" in attr["special"]:
163                                 specialname = nodename + attr["special"]["suffix"]
164                         else:
165                                 print "Unknown special constructor type for node type %s" %nodename
166                                 sys.exit(1)
167
168                         specialconstrs.append(
169                                 dict(
170                                         constrname = specialname,
171                                         attrname = attr["name"],
172                                         value = attr["special"]["init"]
173                                 )
174                         )
175                 elif "init" in attr:
176                         if attr["type"] == "op_pin_state":
177                                 initfunc = "set_irn_pinned"
178                         else:
179                                 initfunc = "set_" + nodename + "_" + attr["name"]
180                         initargs.append((attr["name"], initfunc))
181                 else:
182                         arguments.append(attr["name"])
183
184         for arg in node["constructor_args"]:
185                 prepare_attr(nodename, arg)
186                 arguments.append(arg["name"])
187
188         node["arguments"] = arguments
189         node["initargs"] = initargs
190         node["special_constructors"] = specialconstrs
191
192 export_attrs_template = env.from_string('''
193         case iro_{{nodename}}:
194                 {{"write_mode(env, get_irn_mode(irn));"|ifnset(node,"mode")}}
195                 {% for attr in node.attrs %}{{attr.exportcmd}}
196                 {% endfor %}
197                 {% for attr in node.constructor_args %}{{attr.exportcmd}}
198                 {% endfor %}break;''')
199
200 import_attrs_template = env.from_string('''
201         case iro_{{nodename}}:
202         {
203                 {{"ir_mode *mode = read_mode(env);"|ifnset(node,"mode")}}
204                 {% for attr in node.attrs %}{{attr.importcmd}}
205                 {% endfor %}
206                 {% for attr in node.constructor_args %}{{attr.importcmd}}
207                 {% endfor %}
208                 {% for special in node.special_constructors %}if({{special.attrname}} == {{special.value}})
209                         newnode = new_r_{{special.constrname}}(current_ir_graph{{node|block}}{{node["arguments"]|args}});
210                 else{% endfor %}
211                 newnode = new_r_{{nodename}}(current_ir_graph{{node|block}}{{node["arguments"]|args}});
212                 {% for (initarg, initfunc) in node.initargs %}{{initfunc}}(newnode, {{initarg}});
213                 {% endfor %}
214                 break;
215         }
216 ''')
217
218 def main(argv):
219         """the main function"""
220
221         if len(argv) < 3:
222                 print "usage: %s specname(ignored) destdirectory" % argv[0]
223                 sys.exit(1)
224
225         gendir = argv[2]
226
227         sortednodes = do_dictsort(ir_spec.nodes)
228
229         file = open(gendir + "/gen_irio_export.inl", "w");
230         for nodename, node in sortednodes:
231                 preprocess_node(nodename, node)
232                 if not "abstract" in node:
233                         file.write(export_attrs_template.render(vars()))
234         file.write("\n")
235         file.close()
236
237         file = open(gendir + "/gen_irio_import.inl", "w");
238         for nodename, node in sortednodes:
239                 if not "abstract" in node and nodename != "Start" and nodename != "End" and nodename != "Anchor" and nodename != "SymConst" and nodename != "Block":
240                         file.write(import_attrs_template.render(vars()))
241         # TODO: SymConst
242         file.write("\n")
243         file.close()
244
245         file = open(gendir + "/gen_irio_lex.inl", "w");
246         for nodename, node in sortednodes:
247                 if not "abstract" in node:
248                         file.write("\tINSERT(\"" + nodename + "\", tt_iro, iro_" + nodename + ");\n");
249         file.close()
250
251 if __name__ == "__main__":
252         main(sys.argv)