gen_docu: fix missing attributes, show generation time at the end
[libfirm] / scripts / gen_ir_io.py
index f7b3bd0..2fab4b0 100755 (executable)
@@ -1,61 +1,77 @@
 #!/usr/bin/env python
 import sys
+import re
 from jinja2 import Environment, Template
+from jinja2.filters import do_dictsort
+from spec_util import is_dynamic_pinned, verify_node, isAbstract
 import ir_spec
 
+def error(msg):
+       """writes an error message to stderr"""
+       sys.stderr.write("Error: " + msg + "\n");
+
+def warning(msg):
+       """writes a warning message to stderr"""
+       sys.stderr.write("Warning: " + msg + "\n");
+
 def format_args(arglist):
-       #argstrings = map(lambda arg : arg["name"], arglist)
-       #return ", ".join(argstrings)
-       s = ", ".join(arglist)
-       if len(s) == 0:
-         return "";
-       return ", " + s;
+       return "\n".join(arglist)
 
 def format_ifnset(string, node, key):
-       if key in node:
+       if hasattr(node, key):
                return ""
        return string
 
 def format_block(node):
-       if node.get("knownBlock"):
-               return ""
+       if hasattr(node, "knownBlock"):
+               if hasattr(node, "knownGraph"):
+                       return ""
+               return "irg"
        else:
-               return ", get_node(env, preds[0])"
+               return "preds[0]"
 
-env = Environment()
-env.filters['args']   = format_args
-env.filters['ifnset'] = format_ifnset
-env.filters['block']  = format_block
+def format_arguments(string):
+       args = re.split('\s*\n\s*', string)
+       if args[0] == '':
+               args = args[1:]
+       if len(args) > 0 and args[-1] == '':
+               args = args[:-1]
+       return ", ".join(args)
 
-def get_io_type(type, attrname, nodename):
-       if type == "tarval*":
-               importcmd = "tarval *%s = read_tv(env);" % attrname
+env = Environment()
+env.filters['args']      = format_args
+env.filters['ifnset']    = format_ifnset
+env.filters['block']     = format_block
+env.filters['arguments'] = format_arguments
+
+def get_io_type(type, attrname, node):
+       if type == "ir_tarval*":
+               importcmd = "ir_tarval *%s = read_tv(env);" % attrname
                exportcmd = "write_tarval(env, %(val)s);";
        elif type == "ir_mode*":
                importcmd = "ir_mode *%s = read_mode(env);" % attrname
                exportcmd = "write_mode(env, %(val)s);"
        elif type == "ir_entity*":
                importcmd = "ir_entity *%s = read_entity(env);" % attrname
-               exportcmd = """fprintf(env->file, "%%ld ", get_entity_nr(%(val)s));"""
+               exportcmd = "write_entity_ref(env, %(val)s);"
        elif type == "ir_type*":
                importcmd = "ir_type *%s = read_type(env);" % attrname
-               exportcmd = """fprintf(env->file, "%%ld ", get_type_nr(%(val)s));"""
-       elif type == "long" and nodename == "Proj":
+               exportcmd = "write_type_ref(env, %(val)s);"
+       elif type == "long" and node.name == "Proj":
                importcmd = "long %s = read_long(env);" % attrname
-               exportcmd = """fprintf(env->file, "%%ld ", %(val)s);"""
-       elif type == "pn_Cmp" or type == "ir_where_alloc":
+               exportcmd = "write_long(env, %(val)s);"
+       elif type == "ir_relation" or type == "ir_where_alloc":
                importcmd = "%s %s = (%s) read_long(env);" % (type, attrname, type)
-               exportcmd = """fprintf(env->file, "%%ld ", (long) %(val)s);"""
-       elif type == "cons_flags" and nodename == "Store":
-               importcmd = "ir_cons_flags %s = get_cons_flags(env);" % attrname
-               exportcmd = """write_pin_state(env, irn);
-                       write_volatility(env, irn);
-                       write_align(env, irn);"""
-       elif type == "cons_flags" and nodename == "Load":
-               importcmd = "ir_cons_flags %s = get_cons_flags(env);" % attrname
-               exportcmd = """write_pin_state(env, irn);
-                       write_volatility(env, irn);
-                       write_align(env, irn);"""
+               exportcmd = "write_long(env, (long) %(val)s);"
+       elif type == "ir_align":
+               importcmd = "ir_align %s = read_align(env);" % attrname
+               exportcmd = "write_align(env, %(val)s);"
+       elif type == "ir_volatility":
+               importcmd = "ir_volatility %s = read_volatility(env);" % attrname
+               exportcmd = "write_volatility(env, %(val)s);"
+       elif type == "ir_cons_flags":
+               importcmd = "ir_cons_flags %s = cons_none;" % attrname
+               exportcmd = "" # can't really export cons_flags
        elif type == "op_pin_state":
                importcmd = "op_pin_state %s = read_pin_state(env);" % attrname
                exportcmd = "write_pin_state(env, irn);"
@@ -69,157 +85,75 @@ def get_io_type(type, attrname, nodename):
                importcmd = "cond_jmp_predicate %s = read_cond_jmp_predicate(env);" % attrname
                exportcmd = "write_cond_jmp_predicate(env, irn);"
        elif type == "int":
-               importcmd = "int %s = (int) read_long(env);" % attrname
-               exportcmd = """fprintf(env->file, "%%d ", %(val)s);"""
+               importcmd = "int %s = read_int(env);" % attrname
+               exportcmd = "write_int(env, %(val)s);"
+       elif type == "unsigned":
+               importcmd = "unsigned %s = read_unsigned(env);" % attrname
+               exportcmd = "write_unsigned(env, %(val)s);"
        elif type == "long":
                importcmd = "long %s = read_long(env);" % attrname
-               exportcmd = """fprintf(env->file, "%%ld ", %(val)s);"""
+               exportcmd = "write_long(env, %(val)s);"
        else:
-               print "UNKNOWN TYPE: %s" % type
+               warning("cannot generate import/export for node %s: unsupported attribute type: %s" % (node.name, type))
                importcmd = """// BAD: %s %s
                        %s %s = (%s) 0;""" % (type, attrname, type, attrname, type)
                exportcmd = "// BAD: %s" % type
        return (importcmd, exportcmd)
 
-"""    if type == "ir_type*":
-               java_type    = "firm.Type"
-               wrap_type    = "Pointer"
-               to_wrapper   = "%s.ptr"
-               from_wrapper = "firm.Type.createWrapper(%s)"
-       elif type == "ir_mode*":
-               java_type    = "firm.Mode"
-               wrap_type    = "Pointer"
-               to_wrapper   = "%s.ptr"
-               from_wrapper = "new firm.Mode(%s)"
-       elif type == "tarval*":
-               java_type    = "firm.TargetValue"
-               wrap_type    = "Pointer"
-               to_wrapper   = "%s.ptr"
-               from_wrapper = "new firm.TargetValue(%s)"
-       elif type == "pn_Cmp":
-               java_type    = "int"
-               wrap_type    = "int"
-               to_wrapper   = "%s"
-               from_wrapper = "%s"
-       elif type == "long":
-               java_type    = "int"
-               wrap_type    = "com.sun.jna.NativeLong"
-               to_wrapper   = "new com.sun.jna.NativeLong(%s)"
-               from_wrapper = "%s.intValue()"
-       elif type == "cons_flags":
-               java_type    = "firm.bindings.binding_ircons.ir_cons_flags"
-               wrap_type    = "int"
-               to_wrapper   = "%s.val"
-               from_wrapper = "firm.bindings.binding_ircons.ir_cons_flags.getEnum(%s)"
-       elif type == "ir_where_alloc":
-               java_type    = "firm.bindings.binding_ircons.ir_where_alloc"
-               wrap_type    = "int"
-               to_wrapper   = "%s.val"
-               from_wrapper = "firm.bindings.binding_ircons.ir_where_alloc.getEnum(%s)"
-       elif type == "ir_entity*":
-               java_type    = "firm.Entity"
-               wrap_type    = "Pointer"
-               to_wrapper   = "%s.ptr"
-               from_wrapper = "new firm.Entity(%s)"
-       else:
-               print "UNKNOWN TYPE"
-               java_type    = "BAD"
-               wrap_type    = "BAD"
-               to_wrapper   = "BAD"
-               from_wrapper = "BAD"
-       return (java_type,wrap_type,to_wrapper,from_wrapper)"""
-
-def prepare_attr(nodename, attr):
-       (importcmd,exportcmd) = get_io_type(attr["type"], attr["name"], nodename)
+def prepare_attr(node, attr):
+       (importcmd,exportcmd) = get_io_type(attr["type"], attr["name"], node)
        attr["importcmd"] = importcmd
-       attr["exportcmd"] = exportcmd % {"val": "get_%s_%s(irn)" % (nodename, attr["name"])}
+       attr["exportcmd"] = exportcmd % {"val": "get_%s_%s(irn)" % (node.name, attr["name"])}
 
-def preprocess_node(nodename, node):
-       if "is_a" in node:
-               parent = ir_spec.nodes[node["is_a"]]
-               node["ins"] = parent["ins"]
-               if "outs" in parent:
-                       node["outs"] = parent["outs"]
-       if "ins" not in node:
-               node["ins"] = []
-       if "outs" in node:
-               node["mode"] = "mode_T"
-       if "arity" not in node:
-               node["arity"] = len(node["ins"])
-       if "attrs" not in node:
-               node["attrs"] = []
-       if "constructor_args" not in node:
-               node["constructor_args"] = []
+
+def preprocess_node(node):
+       # dynamic pin state means, we have to im/export that
+       if is_dynamic_pinned(node):
+               newattr = dict(
+                       name = "state",
+                       type = "op_pin_state"
+               )
+               if hasattr(node, "pinned_init"):
+                       newattr["init"] = node.pinned_init
+               node.attrs.append(newattr)
+
+       verify_node(node)
 
        # construct node arguments
        arguments = [ ]
        initargs = [ ]
-       specialconstrs = [ ]
-       i = 0
-       for input in node["ins"]:
-               arguments.append("prednodes[%i]" % i)
+       i = 1
+       for input in node.ins:
+               arguments.append("preds[%i]" % i)
                i += 1
 
-       # Special case for Builtin...
-       if nodename == "Builtin":
-               for attr in node["attrs"]:
-                       if attr["name"] == "kind":
-                               prepare_attr(nodename, attr)
-                               arguments.append(attr["name"])
-
-       if node["arity"] == "variable" or node["arity"] == "dynamic":
-               arguments.append("numpreds - %i" % (i + 1))
-               arguments.append("prednodes + %i" % i)
+       if node.arity == "variable" or node.arity == "dynamic":
+               arguments.append("numpreds - %i" % i)
+               arguments.append("preds + %i" % i)
 
-       if "mode" not in node:
+       if not hasattr(node, "mode"):
                arguments.append("mode")
 
-       attrs_with_special = 0
-       for attr in node["attrs"]:
-               if nodename == "Builtin" and attr["name"] == "kind":
-                       continue
-               prepare_attr(nodename, attr)
-               if "special" in attr:
-                       if not "init" in attr:
-                               print "Node type %s has an attribute with a \"special\" entry but without \"init\"" % nodename
-                               sys.exit(1)
-
-                       if attrs_with_special != 0:
-                               print "Node type %s has more than one attribute with a \"special\" entry" % nodename
-                               sys.exit(1)
-
-                       attrs_with_special += 1
-
-                       if "prefix" in attr["special"]:
-                               specialname = attr["special"]["prefix"] + nodename
-                       elif "suffix" in attr["special"]:
-                               specialname = nodename + attr["special"]["suffix"]
+       for attr in node.attrs:
+               prepare_attr(node, attr)
+               if "init" in attr:
+                       if attr["type"] == "op_pin_state":
+                               initfunc = "set_irn_pinned"
                        else:
-                               print "Unknown special constructor type for node type %s" %nodename
-                               sys.exit(1)
-
-                       specialconstrs.append(
-                               dict(
-                                       constrname = specialname,
-                                       attrname = attr["name"],
-                                       value = attr["special"]["init"]
-                               )
-                       )
-               elif "init" in attr:
-                       initargs.append(attr["name"])
+                               initfunc = "set_" + node.name + "_" + attr["name"]
+                       initargs.append((attr["name"], initfunc))
                else:
                        arguments.append(attr["name"])
 
-       for arg in node["constructor_args"]:
-               prepare_attr(nodename, arg)
+       for arg in node.constructor_args:
+               prepare_attr(node, arg)
                arguments.append(arg["name"])
 
-       node["arguments"] = arguments
-       node["initargs"] = initargs
-       node["special_constructors"] = specialconstrs
+       node.arguments = arguments
+       node.initargs = initargs
 
 export_attrs_template = env.from_string('''
-       case iro_{{nodename}}:
+       case iro_{{node.name}}:
                {{"write_mode(env, get_irn_mode(irn));"|ifnset(node,"mode")}}
                {% for attr in node.attrs %}{{attr.exportcmd}}
                {% endfor %}
@@ -227,19 +161,22 @@ export_attrs_template = env.from_string('''
                {% endfor %}break;''')
 
 import_attrs_template = env.from_string('''
-       case iro_{{nodename}}:
-       {
+       case iro_{{node.name}}: {
                {{"ir_mode *mode = read_mode(env);"|ifnset(node,"mode")}}
-               {% for attr in node.attrs %}{{attr.importcmd}}
-               {% endfor %}
-               {% for attr in node.constructor_args %}{{attr.importcmd}}
-               {% endfor %}
-               {% for special in node.special_constructors %}if({{special.attrname}} == {{special.value}})
-                       newnode = new_r_{{special.constrname}}(current_ir_graph{{node|block}}{{node["arguments"]|args}});
-               else{% endfor %}
-               newnode = new_r_{{nodename}}(current_ir_graph{{node|block}}{{node["arguments"]|args}});
-               {% for initarg in node.initargs %}set_{{nodename}}_{{initarg}}(newnode, {{initarg}});
-               {% endfor %}
+               {% for attr in node.attrs %}
+               {{attr.importcmd}}
+               {% endfor -%}
+               {% for attr in node.constructor_args %}
+               {{attr.importcmd}}
+               {% endfor -%}
+               newnode = new_r_{{node.name}}(
+{%- filter arguments %}
+{{node|block}}
+{{node.arguments|args}}
+{% endfilter %});
+               {% for (initarg, initfunc) in node.initargs %}
+               {{initfunc}}(newnode, {{initarg}});
+               {% endfor -%}
                break;
        }
 ''')
@@ -253,27 +190,36 @@ def main(argv):
 
        gendir = argv[2]
 
+       real_nodes = []
+       for node in ir_spec.nodes:
+               if isAbstract(node):
+                       continue
+               real_nodes.append(node)
+
        file = open(gendir + "/gen_irio_export.inl", "w");
-       for nodename, node in ir_spec.nodes.iteritems():
-               preprocess_node(nodename, node)
-               if not "abstract" in node:
-                       file.write(export_attrs_template.render(vars()))
+       file.write("/* Warning: automatically generated code */")
+       for node in real_nodes:
+               if node.customSerializer:
+                       continue
+
+               preprocess_node(node)
+               file.write(export_attrs_template.render(vars()))
        file.write("\n")
        file.close()
 
        file = open(gendir + "/gen_irio_import.inl", "w");
-       for nodename, node in ir_spec.nodes.iteritems():
-               if not "abstract" in node and nodename != "Start" and nodename != "End" and nodename != "Anchor" and nodename != "SymConst" and nodename != "Block":
-                       file.write(import_attrs_template.render(vars()))
-       # TODO: SymConst
+       file.write("/* Warning: automatically generated code */")
+       for node in real_nodes:
+               if node.customSerializer:
+                       continue
+               file.write(import_attrs_template.render(vars()))
        file.write("\n")
        file.close()
 
        file = open(gendir + "/gen_irio_lex.inl", "w");
-       for nodename, node in ir_spec.nodes.iteritems():
-               if not "abstract" in node:
-                       file.write("\tINSERT(\"" + nodename + "\", tt_iro, iro_" + nodename + ");\n");
+       file.write("/* Warning: automatically generated code */")
+       for node in real_nodes:
+               file.write("\tINSERT(tt_iro, \"%s\", iro_%s);\n" % (node.name, node.name));
        file.close()
 
-if __name__ == "__main__":
-       main(sys.argv)
+main(sys.argv)