output documentation to file on request
[libfirm] / scripts / gen_ir_io.py
1 #!/usr/bin/env python
2 import sys
3 import re
4 from jinja2 import Environment, Template
5 from jinja2.filters import do_dictsort
6 from spec_util import is_dynamic_pinned, verify_node, isAbstract
7 import ir_spec
8
9 def error(msg):
10         """writes an error message to stderr"""
11         sys.stderr.write("Error: " + msg + "\n");
12
13 def warning(msg):
14         """writes a warning message to stderr"""
15         sys.stderr.write("Warning: " + msg + "\n");
16
17 def format_args(arglist):
18         return "\n".join(arglist)
19
20 def format_block(node):
21         if hasattr(node, "knownBlock"):
22                 if hasattr(node, "knownGraph"):
23                         return ""
24                 return "env->irg"
25         else:
26                 return "block"
27
28 def format_arguments(string):
29         args = re.split('\s*\n\s*', string)
30         if args[0] == '':
31                 args = args[1:]
32         if len(args) > 0 and args[-1] == '':
33                 args = args[:-1]
34         return ", ".join(args)
35
36 def filter_isnot(list, flag):
37         return filter(lambda x: not hasattr(x, flag), list)
38
39 def filter_notset(list, flag):
40         return filter(lambda x: not getattr(x,flag), list)
41
42 def filter_hasnot(list, flag):
43         return filter(lambda x: flag not in x, list)
44
45 env = Environment()
46 env.filters['args']      = format_args
47 env.filters['block']     = format_block
48 env.filters['arguments'] = format_arguments
49 env.filters['isnot']     = filter_isnot
50 env.filters['notset']    = filter_notset
51 env.filters['hasnot']    = filter_hasnot
52
53 def get_io_type(type, attrname, node):
54         if type == "ir_tarval*":
55                 importcmd = "read_tarval(env)"
56                 exportcmd = "write_tarval(env, %(val)s);"
57         elif type == "ir_mode*":
58                 importcmd = "read_mode_ref(env)"
59                 exportcmd = "write_mode_ref(env, %(val)s);"
60         elif type == "ir_entity*":
61                 importcmd = "read_entity_ref(env)"
62                 exportcmd = "write_entity_ref(env, %(val)s);"
63         elif type == "ir_type*":
64                 importcmd = "read_type_ref(env)"
65                 exportcmd = "write_type_ref(env, %(val)s);"
66         elif type == "long":
67                 importcmd = "read_long(env)"
68                 exportcmd = "write_long(env, %(val)s);"
69         elif type == "ir_relation":
70                 importcmd = "read_relation(env)"
71                 exportcmd = "write_relation(env, %(val)s);"
72         elif type == "ir_where_alloc":
73                 importcmd = "read_where_alloc(env)"
74                 exportcmd = "write_where_alloc(env, %(val)s);"
75         elif type == "ir_align":
76                 importcmd = "read_align(env)"
77                 exportcmd = "write_align(env, %(val)s);"
78         elif type == "ir_volatility":
79                 importcmd = "read_volatility(env)"
80                 exportcmd = "write_volatility(env, %(val)s);"
81         elif type == "ir_cons_flags":
82                 importcmd = "cons_none"
83                 exportcmd = "" # can't really export cons_flags
84         elif type == "op_pin_state":
85                 importcmd = "read_pin_state(env)"
86                 exportcmd = "write_pin_state(env, node);"
87         elif type == "ir_builtin_kind":
88                 importcmd = "read_builtin_kind(env)"
89                 exportcmd = "write_builtin_kind(env, node);"
90         elif type == "cond_kind":
91                 importcmd = "read_cond_kind(env)"
92                 exportcmd = "write_cond_kind(env, node);"
93         elif type == "cond_jmp_predicate":
94                 importcmd = "read_cond_jmp_predicate(env)"
95                 exportcmd = "write_cond_jmp_predicate(env, node);"
96         elif type == "int":
97                 importcmd = "read_int(env)"
98                 exportcmd = "write_int(env, %(val)s);"
99         elif type == "unsigned":
100                 importcmd = "read_unsigned(env)"
101                 exportcmd = "write_unsigned(env, %(val)s);"
102         elif type == "long":
103                 importcmd = "read_long(env)"
104                 exportcmd = "write_long(env, %(val)s);"
105         elif type == "ir_switch_table*":
106                 importcmd = "read_switch_table(env)"
107                 exportcmd = "write_switch_table(env, %(val)s);"
108         else:
109                 warning("cannot generate import/export for node %s: unsupported attribute type: %s" % (node.name, type))
110                 importcmd = "/* BAD: %s %s */ (%s)0" % (type, attrname, type)
111                 exportcmd = "// BAD: %s" % type
112         return (importcmd, exportcmd)
113
114 def prepare_attr(node, attr):
115         (importcmd,exportcmd) = get_io_type(attr["type"], attr["name"], node)
116         attr["importcmd"] = importcmd
117         attr["exportcmd"] = exportcmd % {"val": "get_%s_%s(node)" % (node.name, attr["name"])}
118
119
120 def preprocess_node(node):
121         verify_node(node)
122
123         if node.customSerializer:
124                 return
125
126         # construct node arguments
127         arguments = [ ]
128         extraattrs = [ ]
129         for input in node.ins:
130                 arguments.append("in_%s" % input[0])
131
132         if node.arity == "variable" or node.arity == "dynamic":
133                 arguments.append("n_preds")
134                 arguments.append("preds")
135
136         if not hasattr(node, "mode"):
137                 arguments.append("mode")
138
139         for attr in node.attrs:
140                 prepare_attr(node, attr)
141                 if "to_flags" in attr:
142                         node.constructorFlags = True
143                         attr['to_flags'] = attr['to_flags'] % (attr["name"])
144                 elif "init" in attr:
145                         extraattrs.append(attr)
146                 else:
147                         arguments.append(attr["name"])
148
149         for arg in node.constructor_args:
150                 if arg['type'] != "ir_cons_flags" and arg['name'] != "flags":
151                         error("only ir_cons_flags constructor arg supported in irio")
152                         continue
153                 node.constructorFlags = True
154                 arguments.append("flags")
155
156         node.arguments  = arguments
157         node.extraattrs = extraattrs
158         node.dynamic_pinned = is_dynamic_pinned(node)
159
160 io_template = env.from_string('''/* Warning: automatically generated code */
161 {%- for node in nodes|notset('customSerializer') %}
162 static ir_node *read_{{node.name}}(read_env_t *env)
163 {
164         {%- if not node.knownBlock %}
165         ir_node *block = read_node_ref(env);
166         {%- endif %}
167         {%- for input in node.ins %}
168         ir_node *in_{{input[0]}} = read_node_ref(env);
169         {%- endfor %}
170         {%- if not hasattr(node, "mode") %}
171         ir_mode *mode = read_mode_ref(env);
172         {%- endif %}
173         {%- for attr in node.attrs %}
174         {{attr.type}} {{attr.name}} = {{attr.importcmd}};
175         {%- endfor %}
176         {%- if node.dynamic_pinned %}
177         op_pin_state pin_state = read_pin_state(env);
178         {%- endif %}
179         {%- if "fragile" in node.flags %}
180         bool throws = read_throws(env);
181         {%- endif %}
182         {%- if node.arity == "dynamic" or node.arity == "variable" %}
183         int       n_preds = read_preds(env);
184         ir_node **preds   = obstack_finish(&env->preds_obst);
185         {%- endif %}
186         {%- if node.constructorFlags %}
187         ir_cons_flags flags = cons_none;
188         {%- endif %}
189         ir_node *res;
190         {%- if node.constructorFlags %}
191                 {%- for attr in node.attrs %}
192                         {%- if "to_flags" in attr %}
193         flags |= {{attr.to_flags}};
194                         {%- endif %}
195                 {%- endfor %}
196                 {%- if node.dynamic_pinned %}
197         flags |= pin_state == op_pin_state_floats ? cons_floats : 0;
198                 {%- endif %}
199                 {%- if "fragile" in node.flags %}
200         flags |= throws ? cons_throws_exception : 0;
201                 {%- endif %}
202         {%- endif %}
203         res = new_r_{{node.name}}(
204                 {%- filter arguments %}
205 {{node|block}}
206 {{node.arguments|args}}
207                 {%- if node.dynamic_pinned and not hasattr(node, "pinned_init") %}
208 pin_state
209                 {%- endif %}
210 {% endfilter %});
211
212         {%- if node.arity == "dynamic" or node.arity == "variable" %}
213         obstack_free(&env->preds_obst, preds);
214         {%- endif %}
215         {%- for attr in node.extraattrs %}
216         set_{{node.name}}_{{attr.name}}(res, {{attr.name}});
217         {%- endfor %}
218         {%- if not node.constructorFlags %}
219                 {%- if node.dynamic_pinned and hasattr(node, "pinned_init") %}
220         set_irn_pinned(res, pin_state);
221                 {%- endif %}
222                 {%- if "fragile" in node.flags and hasattr(node, "throws_init") %}
223         ir_set_throws_exception(res, throws);
224                 {%- endif %}
225         {%- endif %}
226         return res;
227 }
228 {% endfor %}
229
230 {%- for node in nodes|notset('customSerializer') %}
231 static void write_{{node.name}}(write_env_t *env, const ir_node *node)
232 {
233         write_symbol(env, "{{node.name}}");
234         write_node_nr(env, node);
235         {%- if not node.knownBlock %}
236         write_node_ref(env, get_nodes_block(node));
237         {%- endif %}
238         {%- for input in node.ins %}
239         write_node_ref(env, get_{{node.name}}_{{input[0]}}(node));
240         {%- endfor %}
241         {%- if not hasattr(node, "mode") %}
242         write_mode_ref(env, get_irn_mode(node));
243         {%- endif %}
244         {%- for attr in node.attrs %}
245         {{attr.exportcmd}}
246         {%- endfor %}
247         {%- if node.dynamic_pinned %}
248         write_pin_state(env, get_irn_pinned(node));
249         {%- endif %}
250         {%- if "fragile" in node.flags %}
251         write_throws(env, ir_throws_exception(node));
252         {%- endif %}
253         {%- if node.arity == "dynamic" or node.arity == "variable" %}
254         write_pred_refs(env, node, {% if node.ins %}n_{{node.name}}_max+1{% else %}0{%endif%});
255         {%- endif %}
256 }
257 {% endfor %}
258
259 static void register_generated_node_readers(void)
260 {
261         {%- for node in nodes|notset('customSerializer') %}
262         register_node_reader(new_id_from_str("{{node.name}}"), read_{{node.name}});
263         {%- endfor %}
264 }
265
266 static void register_generated_node_writers(void)
267 {
268         {%- for node in nodes|notset('customSerializer') %}
269         register_node_writer(op_{{node.name}}, write_{{node.name}});
270         {%- endfor %}
271 }
272 ''')
273
274 def main(argv):
275         if len(argv) < 3:
276                 print "usage: %s specname(ignored) destdirectory" % argv[0]
277                 sys.exit(1)
278
279         gendir = argv[2]
280
281         real_nodes = []
282         for node in ir_spec.nodes:
283                 if isAbstract(node):
284                         continue
285                 preprocess_node(node)
286                 real_nodes.append(node)
287
288         file = open(gendir + "/gen_irio.inl", "w");
289         file.write(io_template.render(nodes = real_nodes, hasattr=hasattr))
290         file.close()
291
292 main(sys.argv)