clarify some node comments
[libfirm] / scripts / gen_ir_io.py
index 58100c9..5c86c84 100755 (executable)
 #!/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
+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;
-
-def format_ifnset(string, node, key):
-       if key in node:
-               return ""
-       return string
+       return "\n".join(arglist)
 
 def format_block(node):
-       if node.get("knownBlock"):
-               return ""
+       if hasattr(node, "knownBlock"):
+               if hasattr(node, "knownGraph"):
+                       return ""
+               return "env->irg"
        else:
-               return ", get_node(env, preds[0])"
+               return "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 filter_isnot(list, flag):
+       return filter(lambda x: not hasattr(x, flag), list)
+
+def filter_notset(list, flag):
+       return filter(lambda x: not getattr(x,flag), list)
+
+def filter_hasnot(list, flag):
+       return filter(lambda x: flag not in x, list)
 
 env = Environment()
-env.filters['args']   = format_args
-env.filters['ifnset'] = format_ifnset
-env.filters['block']  = format_block
-
-def get_io_type(type, attrname, nodename):
-       if type == "tarval*":
-               importcmd = "tarval *%s = read_tv(env);" % attrname
-               exportcmd = "write_tarval(env, %(val)s);";
+env.filters['args']      = format_args
+env.filters['block']     = format_block
+env.filters['arguments'] = format_arguments
+env.filters['isnot']     = filter_isnot
+env.filters['notset']    = filter_notset
+env.filters['hasnot']    = filter_hasnot
+
+def get_io_type(type, attrname, node):
+       if type == "ir_tarval*":
+               importcmd = "read_tarval(env)"
+               exportcmd = "write_tarval(env, %(val)s);"
        elif type == "ir_mode*":
-               importcmd = "ir_mode *%s = read_mode(env);" % attrname
-               exportcmd = "write_mode(env, %(val)s);"
+               importcmd = "read_mode_ref(env)"
+               exportcmd = "write_mode_ref(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));"""
+               importcmd = "read_entity_ref(env)"
+               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":
-               importcmd = "long %s = read_long(env);" % attrname
-               exportcmd = """fprintf(env->file, "%%ld ", %(val)s);"""
-       elif type == "pn_Cmp" 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 == "ir_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 == "ir_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);"""
+               importcmd = "read_type_ref(env)"
+               exportcmd = "write_type_ref(env, %(val)s);"
+       elif type == "long":
+               importcmd = "read_long(env)"
+               exportcmd = "write_long(env, %(val)s);"
+       elif type == "ir_relation":
+               importcmd = "read_relation(env)"
+               exportcmd = "write_relation(env, %(val)s);"
+       elif type == "ir_where_alloc":
+               importcmd = "read_where_alloc(env)"
+               exportcmd = "write_where_alloc(env, %(val)s);"
+       elif type == "ir_align":
+               importcmd = "read_align(env)"
+               exportcmd = "write_align(env, %(val)s);"
+       elif type == "ir_volatility":
+               importcmd = "read_volatility(env)"
+               exportcmd = "write_volatility(env, %(val)s);"
+       elif type == "ir_cons_flags":
+               importcmd = "cons_none"
+               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);"
+               importcmd = "read_pin_state(env)"
+               exportcmd = "write_pin_state(env, node);"
        elif type == "ir_builtin_kind":
-               importcmd = "ir_builtin_kind %s = read_builtin_kind(env);" % attrname
-               exportcmd = "write_builtin_kind(env, irn);"
+               importcmd = "read_builtin_kind(env)"
+               exportcmd = "write_builtin_kind(env, node);"
        elif type == "cond_kind":
-               importcmd = "cond_kind %s = read_cond_kind(env);" % attrname
-               exportcmd = "write_cond_kind(env, irn);"
+               importcmd = "read_cond_kind(env)"
+               exportcmd = "write_cond_kind(env, node);"
        elif type == "cond_jmp_predicate":
-               importcmd = "cond_jmp_predicate %s = read_cond_jmp_predicate(env);" % attrname
-               exportcmd = "write_cond_jmp_predicate(env, irn);"
+               importcmd = "read_cond_jmp_predicate(env)"
+               exportcmd = "write_cond_jmp_predicate(env, node);"
        elif type == "int":
-               importcmd = "int %s = (int) read_long(env);" % attrname
-               exportcmd = """fprintf(env->file, "%%d ", %(val)s);"""
+               importcmd = "read_int(env)"
+               exportcmd = "write_int(env, %(val)s);"
+       elif type == "unsigned":
+               importcmd = "read_unsigned(env)"
+               exportcmd = "write_unsigned(env, %(val)s);"
        elif type == "long":
-               importcmd = "long %s = read_long(env);" % attrname
-               exportcmd = """fprintf(env->file, "%%ld ", %(val)s);"""
+               importcmd = "read_long(env)"
+               exportcmd = "write_long(env, %(val)s);"
+       elif type == "ir_switch_table*":
+               importcmd = "read_switch_table(env)"
+               exportcmd = "write_switch_table(env, %(val)s);"
        else:
-               print "UNKNOWN TYPE: %s" % type
-               importcmd = """// BAD: %s %s
-                       %s %s = (%s) 0;""" % (type, attrname, type, attrname, type)
+               warning("cannot generate import/export for node %s: unsupported attribute type: %s" % (node.name, type))
+               importcmd = "/* BAD: %s %s */ (%s)0" % (type, attrname, type)
                exportcmd = "// BAD: %s" % type
        return (importcmd, exportcmd)
 
-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"])}
-
-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"] = []
-       if "pinned" not in node:
-               node["pinned"] = "no"
-       # dynamic pin state means, we have to im/export that
-       if is_dynamic_pinned(node):
-               newattr = dict(
-                       name = "state",
-                       type = "op_pin_state"
-               )
-               if "pinned_init" in node:
-                       newattr["init"] = node["pinned_init"]
-               node["attrs"].append(newattr)
+       attr["exportcmd"] = exportcmd % {"val": "get_%s_%s(node)" % (node.name, attr["name"])}
+
 
+def preprocess_node(node):
        verify_node(node)
 
+       if node.customSerializer:
+               return
+
        # construct node arguments
        arguments = [ ]
-       initargs = [ ]
-       specialconstrs = [ ]
-       i = 0
-       for input in node["ins"]:
-               arguments.append("prednodes[%i]" % i)
-               i += 1
-
-       if node["arity"] == "variable" or node["arity"] == "dynamic":
-               arguments.append("numpreds - %i" % (i + 1))
-               arguments.append("prednodes + %i" % i)
-
-       if "mode" not in node:
+       extraattrs = [ ]
+       for input in node.ins:
+               arguments.append("in_%s" % input[0])
+
+       if node.arity == "variable" or node.arity == "dynamic":
+               arguments.append("n_preds")
+               arguments.append("preds")
+
+       if not hasattr(node, "mode"):
                arguments.append("mode")
 
-       attrs_with_special = 0
-       for attr in node["attrs"]:
-               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"]
-                       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"]
-                               )
-                       )
+       for attr in node.attrs:
+               prepare_attr(node, attr)
+               if "to_flags" in attr:
+                       node.constructorFlags = True
+                       attr['to_flags'] = attr['to_flags'] % (attr["name"])
                elif "init" in attr:
-                       if attr["type"] == "op_pin_state":
-                               initfunc = "set_irn_pinned"
-                       else:
-                               initfunc = "set_" + nodename + "_" + attr["name"]
-                       initargs.append((attr["name"], initfunc))
+                       extraattrs.append(attr)
                else:
                        arguments.append(attr["name"])
 
-       for arg in node["constructor_args"]:
-               prepare_attr(nodename, arg)
-               arguments.append(arg["name"])
-
-       node["arguments"] = arguments
-       node["initargs"] = initargs
-       node["special_constructors"] = specialconstrs
-
-export_attrs_template = env.from_string('''
-       case iro_{{nodename}}:
-               {{"write_mode(env, get_irn_mode(irn));"|ifnset(node,"mode")}}
-               {% for attr in node.attrs %}{{attr.exportcmd}}
-               {% endfor %}
-               {% for attr in node.constructor_args %}{{attr.exportcmd}}
-               {% endfor %}break;''')
-
-import_attrs_template = env.from_string('''
-       case iro_{{nodename}}:
-       {
-               {{"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, initfunc) in node.initargs %}{{initfunc}}(newnode, {{initarg}});
-               {% endfor %}
-               break;
-       }
+       for arg in node.constructor_args:
+               if arg['type'] != "ir_cons_flags" and arg['name'] != "flags":
+                       error("only ir_cons_flags constructor arg supported in irio")
+                       continue
+               node.constructorFlags = True
+               arguments.append("flags")
+
+       node.arguments  = arguments
+       node.extraattrs = extraattrs
+       node.dynamic_pinned = is_dynamic_pinned(node)
+
+io_template = env.from_string('''/* Warning: automatically generated code */
+{%- for node in nodes|notset('customSerializer') %}
+static ir_node *read_{{node.name}}(read_env_t *env)
+{
+       {%- if not node.knownBlock %}
+       ir_node *block = read_node_ref(env);
+       {%- endif %}
+       {%- for input in node.ins %}
+       ir_node *in_{{input[0]}} = read_node_ref(env);
+       {%- endfor %}
+       {%- if not hasattr(node, "mode") %}
+       ir_mode *mode = read_mode_ref(env);
+       {%- endif %}
+       {%- for attr in node.attrs %}
+       {{attr.type}} {{attr.name}} = {{attr.importcmd}};
+       {%- endfor %}
+       {%- if node.dynamic_pinned %}
+       op_pin_state pin_state = read_pin_state(env);
+       {%- endif %}
+       {%- if "fragile" in node.flags %}
+       bool throws = read_throws(env);
+       {%- endif %}
+       {%- if node.arity == "dynamic" or node.arity == "variable" %}
+       int       n_preds = read_preds(env);
+       ir_node **preds   = obstack_finish(&env->preds_obst);
+       {%- endif %}
+       {%- if node.constructorFlags %}
+       ir_cons_flags flags = cons_none;
+       {%- endif %}
+       ir_node *res;
+       {%- if node.constructorFlags %}
+               {%- for attr in node.attrs %}
+                       {%- if "to_flags" in attr %}
+       flags |= {{attr.to_flags}};
+                       {%- endif %}
+               {%- endfor %}
+               {%- if node.dynamic_pinned %}
+       flags |= pin_state == op_pin_state_floats ? cons_floats : 0;
+               {%- endif %}
+               {%- if "fragile" in node.flags %}
+       flags |= throws ? cons_throws_exception : 0;
+               {%- endif %}
+       {%- endif %}
+       res = new_r_{{node.name}}(
+               {%- filter arguments %}
+{{node|block}}
+{{node.arguments|args}}
+               {%- if node.dynamic_pinned and not hasattr(node, "pinned_init") %}
+pin_state
+               {%- endif %}
+{% endfilter %});
+
+       {%- if node.arity == "dynamic" or node.arity == "variable" %}
+       obstack_free(&env->preds_obst, preds);
+       {%- endif %}
+       {%- for attr in node.extraattrs %}
+       set_{{node.name}}_{{attr.name}}(res, {{attr.name}});
+       {%- endfor %}
+       {%- if not node.constructorFlags %}
+               {%- if node.dynamic_pinned and hasattr(node, "pinned_init") %}
+       set_irn_pinned(res, pin_state);
+               {%- endif %}
+               {%- if "fragile" in node.flags and hasattr(node, "throws_init") %}
+       ir_set_throws_exception(res, throws);
+               {%- endif %}
+       {%- endif %}
+       return res;
+}
+{% endfor %}
+
+{%- for node in nodes|notset('customSerializer') %}
+static void write_{{node.name}}(write_env_t *env, const ir_node *node)
+{
+       write_symbol(env, "{{node.name}}");
+       write_node_nr(env, node);
+       {%- if not node.knownBlock %}
+       write_node_ref(env, get_nodes_block(node));
+       {%- endif %}
+       {%- for input in node.ins %}
+       write_node_ref(env, get_{{node.name}}_{{input[0]}}(node));
+       {%- endfor %}
+       {%- if not hasattr(node, "mode") %}
+       write_mode_ref(env, get_irn_mode(node));
+       {%- endif %}
+       {%- for attr in node.attrs %}
+       {{attr.exportcmd}}
+       {%- endfor %}
+       {%- if node.dynamic_pinned %}
+       write_pin_state(env, get_irn_pinned(node));
+       {%- endif %}
+       {%- if "fragile" in node.flags %}
+       write_throws(env, ir_throws_exception(node));
+       {%- endif %}
+       {%- if node.arity == "dynamic" or node.arity == "variable" %}
+       write_pred_refs(env, node, {% if node.ins %}n_{{node.name}}_max+1{% else %}0{%endif%});
+       {%- endif %}
+}
+{% endfor %}
+
+static void register_generated_node_readers(void)
+{
+       {%- for node in nodes|notset('customSerializer') %}
+       register_node_reader(new_id_from_str("{{node.name}}"), read_{{node.name}});
+       {%- endfor %}
+}
+
+static void register_generated_node_writers(void)
+{
+       {%- for node in nodes|notset('customSerializer') %}
+       register_node_writer(op_{{node.name}}, write_{{node.name}});
+       {%- endfor %}
+}
 ''')
 
 def main(argv):
-       """the main function"""
-
        if len(argv) < 3:
                print "usage: %s specname(ignored) destdirectory" % argv[0]
                sys.exit(1)
 
        gendir = argv[2]
-       sortednodes = do_dictsort(ir_spec.nodes)
-       # these nodes don't work correctly yet for some reasons...
-       niynodes = [ "EndExcept", "EndReg", "ASM" ]
-       # these have custom im-/export code
-       customcode = [ "Start", "End", "Anchor", "SymConst", "Block" ]
-
-       file = open(gendir + "/gen_irio_export.inl", "w");
-       for nodename, node in sortednodes:
-               if nodename in niynodes:
-                       continue
 
-               preprocess_node(nodename, node)
-               if "abstract" not in 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 sortednodes:
-               if "abstract" in node or nodename in customcode or nodename in niynodes:
+       real_nodes = []
+       for node in ir_spec.nodes:
+               if isAbstract(node):
                        continue
-               file.write(import_attrs_template.render(vars()))
-       file.write("\n")
-       file.close()
+               preprocess_node(node)
+               real_nodes.append(node)
 
-       file = open(gendir + "/gen_irio_lex.inl", "w");
-       for nodename, node in sortednodes:
-               if "abstract" not in node and nodename not in niynodes:
-                       file.write("\tINSERT(\"" + nodename + "\", tt_iro, iro_" + nodename + ");\n");
+       file = open(gendir + "/gen_irio.inl", "w");
+       file.write(io_template.render(nodes = real_nodes, hasattr=hasattr))
        file.close()
 
-if __name__ == "__main__":
-       main(sys.argv)
+main(sys.argv)