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