2cc4d3eae85904cd41c02dc33359a617226c5ba1
[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 ""
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 == "long":
83                 importcmd = "long %s = read_long(env);" % attrname
84                 exportcmd = """fprintf(env->file, "%%ld ", %(val)s);"""
85         else:
86                 error("cannot generate import/export for node %s: unsupported attribute type: %s" % (node.name, type))
87                 importcmd = """// BAD: %s %s
88                         %s %s = (%s) 0;""" % (type, attrname, type, attrname, type)
89                 exportcmd = "// BAD: %s" % type
90         return (importcmd, exportcmd)
91
92 def prepare_attr(node, attr):
93         (importcmd,exportcmd) = get_io_type(attr["type"], attr["name"], node)
94         attr["importcmd"] = importcmd
95         attr["exportcmd"] = exportcmd % {"val": "get_%s_%s(irn)" % (node.name, attr["name"])}
96
97
98 def preprocess_node(node):
99         # dynamic pin state means, we have to im/export that
100         if is_dynamic_pinned(node):
101                 newattr = dict(
102                         name = "state",
103                         type = "op_pin_state"
104                 )
105                 if hasattr(node, "pinned_init"):
106                         newattr["init"] = node.pinned_init
107                 node.attrs.append(newattr)
108
109         verify_node(node)
110
111         # construct node arguments
112         arguments = [ ]
113         initargs = [ ]
114         specialconstrs = [ ]
115         i = 0
116         for input in node.ins:
117                 arguments.append("prednodes[%i]" % i)
118                 i += 1
119
120         if node.arity == "variable" or node.arity == "dynamic":
121                 arguments.append("numpreds - %i" % (i + 1))
122                 arguments.append("prednodes + %i" % i)
123
124         if not hasattr(node, "mode"):
125                 arguments.append("mode")
126
127         attrs_with_special = 0
128         for attr in node.attrs:
129                 prepare_attr(node, attr)
130                 if "special" in attr:
131                         if not "init" in attr:
132                                 warning("Node type %s has an attribute with a \"special\" entry but without \"init\"" % node.name)
133                                 sys.exit(1)
134
135                         if attrs_with_special != 0:
136                                 warning("Node type %s has more than one attribute with a \"special\" entry" % node.name)
137                                 sys.exit(1)
138
139                         attrs_with_special += 1
140
141                         if "prefix" in attr["special"]:
142                                 specialname = attr["special"]["prefix"] + node.name
143                         elif "suffix" in attr["special"]:
144                                 specialname = node.name + attr["special"]["suffix"]
145                         else:
146                                 error("Unknown special constructor type for node type %s" % node.name)
147                                 sys.exit(1)
148
149                         specialconstrs.append(
150                                 dict(
151                                         constrname = specialname,
152                                         attrname = attr["name"],
153                                         value = attr["special"]["init"]
154                                 )
155                         )
156                 elif "init" in attr:
157                         if attr["type"] == "op_pin_state":
158                                 initfunc = "set_irn_pinned"
159                         else:
160                                 initfunc = "set_" + node.name + "_" + attr["name"]
161                         initargs.append((attr["name"], initfunc))
162                 else:
163                         arguments.append(attr["name"])
164
165         for arg in node.constructor_args:
166                 prepare_attr(node, arg)
167                 arguments.append(arg["name"])
168
169         node.arguments = arguments
170         node.initargs = initargs
171         node.special_constructors = specialconstrs
172
173 export_attrs_template = env.from_string('''
174         case iro_{{node.name}}:
175                 {{"write_mode(env, get_irn_mode(irn));"|ifnset(node,"mode")}}
176                 {% for attr in node.attrs %}{{attr.exportcmd}}
177                 {% endfor %}
178                 {% for attr in node.constructor_args %}{{attr.exportcmd}}
179                 {% endfor %}break;''')
180
181 import_attrs_template = env.from_string('''
182         case iro_{{node.name}}:
183         {
184                 {{"ir_mode *mode = read_mode(env);"|ifnset(node,"mode")}}
185                 {% for attr in node.attrs %}{{attr.importcmd}}
186                 {% endfor %}
187                 {% for attr in node.constructor_args %}{{attr.importcmd}}
188                 {% endfor %}
189                 {% for special in node.special_constructors %}if({{special.attrname}} == {{special.value}})
190                         newnode = new_r_{{special.constrname}}(current_ir_graph{{node|block}}{{node.arguments|args}});
191                 else{% endfor %}
192                 newnode = new_r_{{node.name}}(current_ir_graph{{node|block}}{{node.arguments|args}});
193                 {% for (initarg, initfunc) in node.initargs %}{{initfunc}}(newnode, {{initarg}});
194                 {% endfor %}
195                 break;
196         }
197 ''')
198
199 def main(argv):
200         """the main function"""
201
202         if len(argv) < 3:
203                 print "usage: %s specname(ignored) destdirectory" % argv[0]
204                 sys.exit(1)
205
206         gendir = argv[2]
207         # these nodes don't work correctly yet for some reasons...
208         niynodes = [ "EndExcept", "EndReg", "ASM" ]
209         # these have custom im-/export code
210         customcode = [ "Start", "End", "Anchor", "SymConst", "Block" ]
211
212         real_nodes = []
213         for node in ir_spec.nodes:
214                 if isAbstract(node):
215                         continue
216                 real_nodes.append(node)
217
218         file = open(gendir + "/gen_irio_export.inl", "w");
219         for node in real_nodes:
220                 if node.__name__ in niynodes:
221                         continue
222
223                 preprocess_node(node)
224                 file.write(export_attrs_template.render(vars()))
225         file.write("\n")
226         file.close()
227
228         file = open(gendir + "/gen_irio_import.inl", "w");
229         for node in real_nodes:
230                 if node.name in customcode or node.name in niynodes:
231                         continue
232                 file.write(import_attrs_template.render(vars()))
233         file.write("\n")
234         file.close()
235
236         file = open(gendir + "/gen_irio_lex.inl", "w");
237         for node in real_nodes:
238                 if node.name in niynodes:
239                         continue
240                 file.write("\tINSERT(\"" + node.name + "\", tt_iro, iro_" + node.name + ");\n");
241         file.close()
242
243 main(sys.argv)