Commit ce4907ea authored by Matthias Braun's avatar Matthias Braun
Browse files

gen_ir: move ir opcode related things to irops.py

parent f5bbd0f7
......@@ -114,7 +114,7 @@ IR_SPEC_GENERATED_INCLUDES := \
$(gendir)/ir/ir/gen_irdump.c.inl \
$(gendir)/ir/ir/gen_irnode.h
IR_SPEC_GENERATOR := $(srcdir)/scripts/gen_ir.py
IR_SPEC_GENERATOR_DEPS := $(IR_SPEC_GENERATOR) $(srcdir)/scripts/jinjautil.py $(srcdir)/scripts/spec_util.py $(srcdir)/scripts/filters.py
IR_SPEC_GENERATOR_DEPS := $(IR_SPEC_GENERATOR) $(srcdir)/scripts/jinjautil.py $(srcdir)/scripts/irops.py $(srcdir)/scripts/filters.py
IR_SPEC := $(srcdir)/scripts/ir_spec.py
libfirm_BUILDDIRS += $(gendir)/include/libfirm
......
......@@ -136,7 +136,7 @@ def specgen(out, template=None):
generator = "$srcdir/scripts/gen_ir.py"
specfile = "$srcdir/scripts/ir_spec.py"
deps = [template, specfile, generator, "$srcdir/scripts/jinjautil.py",
"$srcdir/scripts/spec_util.py", "$srcdir/scripts/filters.py"]
"$srcdir/scripts/irops.py", "$srcdir/scripts/filters.py"]
return build("GEN_IR", out, deps, specfile=specfile,
template=template, generatortool=generator)
......
......@@ -4,310 +4,11 @@
# Copyright (C) 2012 Karlsruhe Institute of Technology.
import sys
import argparse
from datetime import datetime
from jinja2 import Environment, Template
from jinjautil import export, export_filter
from irops import prepare_nodes, load_spec
import filters
import irops
import jinjautil
from spec_util import is_dynamic_pinned, isAbstract, setdefault, load_spec, Attribute
from filters import arguments, filtjoin, has, hasnot
def parameterlist(parameterlist):
return "\n".join(parameterlist)
def nodearguments(node):
arguments = [arg.name for arg in node.arguments]
return parameterlist(arguments)
def nodeparameters(node):
parameters = ["%s %s" % (arg.type, arg.name) for arg in node.arguments]
return parameterlist(parameters)
def nodeparametershelp(node):
res = ""
for param in node.arguments:
res += " * @param %-9s %s\n" % (param.name, param.comment)
return res
def a_an(text):
if text[0] in "aAeEuUoOiI":
return "an " + text
return "a " + text
def blockparameter(node):
if not node.block:
return "ir_node *block"
elif node.usesGraph:
return "ir_graph *irg"
else:
return ""
def blockparameterhelp(node):
if not node.block:
return " * @param block The IR block the node belongs to.\n"
elif node.usesGraph:
return " * @param irg The IR graph the node belongs to.\n"
else:
return ""
def blockargument(node):
if not node.block:
return "block"
elif node.usesGraph:
return "irg"
else:
return ""
def blockassign(node):
if node.block:
return "ir_node *block = %s;" % node.block
else:
return ""
def irgassign(node):
if node.usesGraph:
return ""
else:
return "ir_graph *irg = get_irn_irg(block);\n"
def curblock(node):
if not node.block:
return "get_cur_block()"
elif node.usesGraph:
return "current_ir_graph"
else:
return ""
def insdecl(node):
arity = node.arity
if arity == "dynamic" or arity == "variable":
if len(node.ins) == 0:
return ""
insarity = len(node.ins)
res = "int r_arity = arity + " + repr(insarity) + ";"
res += "\n\tir_node **r_in= ALLOCAN(ir_node*, r_arity);"
i = 0
for input in node.ins:
res += "\n\tr_in[" + repr(i) + "] = irn_" + input.name + ";"
i += 1
res += "\n\tmemcpy(&r_in[" + repr(insarity) + "], in, sizeof(ir_node *) * arity);\n\t"
elif arity == 0:
return ""
else:
res = "ir_node *in[" + repr(arity) + "];"
i = 0
for input in node.ins:
res += "\n\tin[" + repr(i) + "] = irn_" + input.name + ";"
i += 1
return res
def arity_and_ins(node):
arity = node.arity
if arity == "dynamic" or arity == "variable":
if len(node.ins) == 0:
return "arity, in"
else:
return "r_arity, r_in"
elif arity == 0:
return "0, NULL"
else:
return repr(arity) + ", in"
def arity(node):
if hasattr(node, "arity_override"):
return node.arity_override
arity = node.arity
if arity == "dynamic":
return "oparity_dynamic"
if arity == "variable":
return "oparity_variable"
return "oparity_any"
def pinned(node):
pinned = node.pinned
if pinned == "yes":
return "op_pin_state_pinned"
if pinned == "no":
return "op_pin_state_floats"
if pinned == "exception":
return "op_pin_state_exc_pinned"
print("WARNING: Unknown pinned state %s in format pined" % pinned)
return ""
def flags(node):
flags = list(map(lambda x : "irop_flag_" + x, node.flags))
if not flags:
flags = [ "irop_flag_none" ]
return " | ".join(flags)
def stringformat(string, *args):
return string % args
def attr_size(node):
if not hasattr(node, "attr_struct"):
return "0"
return "sizeof(%s)" % node.attr_struct
def opindex(node):
if hasattr(node, "op_index"):
return node.op_index
return "-1"
keywords = frozenset([ "true", "false" ])
def escape_keywords(word):
if word in keywords:
return word + "_"
return word
def parameters(string):
return arguments(string, voidwhenempty = True)
def args(arglist):
argument_names = [ arg.name for arg in arglist ]
return "\n".join(argument_names)
def block(node):
if not node.block:
return "block"
elif node.usesGraph:
return "env->irg"
else:
return ""
def simplify_type(string):
"""Returns a simplified version of a C type for use in a function name.
Stars are replaced with _ref, spaces removed and the ir_ firm namespace
prefix stripped."""
res = string.replace("*", "_ref").replace(" ", "")
if res.startswith("ir_"):
res = res[3:]
return res
def doxygrouplink(string, link=None):
global tags
if link == None:
link = string
if tags == None:
return string
e = tags.xpath("//compound[name/text()='%s']" % link)
if len(e) == 0:
return string
e = e[0]
anchorfile = e.xpath("filename/text()")
if len(anchorfile) == 0:
return string
global linkbase
return "<a href=\"%s%s\">%s</a>" % (linkbase, anchorfile[0], string)
tags = None
linkbase = None
def doxylink(string, link=None):
global tags
if link == None:
link = string
if tags == None:
return string
e = tags.xpath("//tagfile/compound[name/text()='%s']" % link)
if len(e) == 0:
return string
e = e[0]
anchorfile = e.xpath("anchorfile/text()")
anchor = e.xpath("anchor/text()")
if len(anchorfile) == 0 or len(anchor) == 0:
return string
global linkbase
return "<a href=\"%s%s#%s\">%s</a>" % (linkbase, anchorfile[0], anchor[0], string)
def docutils(string):
import docutils.writers.html4css1
import docutils.core
writer = docutils.writers.html4css1.Writer()
document = docutils.core.publish_parts(string, writer=writer)['body']
return document
def parse_tagfile(filename):
global tags
tagfile = open(filename)
try:
from lxml import etree
tags = etree.parse(tagfile)
except:
tags = None
for f in [a_an, args, arity_and_ins, arity, attr_size, blockargument, block,
blockparameter, blockparameterhelp, curblock, escape_keywords, flags,
insdecl, blockassign, irgassign, nodearguments, nodeparameters,
nodeparametershelp, opindex, parameterlist, parameters, pinned,
simplify_type, stringformat, docutils, doxylink, doxygrouplink ]:
export_filter(f)
export(is_dynamic_pinned)
def preprocess_node(node):
setdefault(node, "attrs_name", node.name.lower())
# construct node arguments
arguments = [ ]
initattrs = [ ]
for input in node.ins:
arguments.append(
Attribute("irn_" + input.name, type="ir_node *",
comment=input.name))
if node.arity == "variable" or node.arity == "dynamic":
arguments.append(
Attribute("arity", type="int",
comment="size of additional inputs array"))
arguments.append(
Attribute("in", type="ir_node *const *",
comment="additional inputs"))
if not hasattr(node, "mode"):
arguments.append(
Attribute("mode", type="ir_mode *",
comment = "mode of the operations result"))
for attr in node.attrs:
if attr.init is not None:
continue
arguments.append(attr)
# dynamic pin state means more constructor arguments
if is_dynamic_pinned(node):
if hasattr(node, "pinned_init"):
initattrs.append(
Attribute("pin_state", fqname="exc.pin_state",
type="op_pin_state", init=node.pinned_init))
else:
node.constructor_args.append(
Attribute("pin_state", type="op_pin_state",
comment = "pinned state"))
initattrs.append(
Attribute("pin_state", fqname="exc.pin_state",
type="op_pin_state", init="pin_state"))
if hasattr(node, "throws_init"):
initattrs.append(
Attribute("throws_exception", fqname="exc.throws_exception",
type="unsigned", init=node.throws_init))
for arg in node.constructor_args:
arguments.append(arg)
node.arguments = arguments
node.initattrs = initattrs
def prepare_nodes(nodes):
real_nodes = []
abstract_nodes = []
for node in nodes:
if isAbstract(node):
abstract_nodes.append(node)
else:
real_nodes.append(node)
for node in real_nodes:
preprocess_node(node)
return (real_nodes, abstract_nodes)
def main(argv):
parser = argparse.ArgumentParser(description='Generate code/docu from node specification', add_help=True)
......
......@@ -4,7 +4,7 @@
# Firm node specifications
# The comments are in (standard python) restructured text format and are used
# to generate documentation.
from spec_util import abstract, op, Attribute
from irops import abstract, op, Attribute
name = "ir"
......
# This file is part of libFirm.
# Copyright (C) 2012 Karlsruhe Institute of Technology.
import sys
import imp
from jinjautil import export_filter, export
from jinja2._compat import string_types
from filters import arguments
import imp
import sys
# Datastructures for specifying ir operation types.
abstracts = set()
def abstract(cls):
abstracts.add(cls)
return cls
def isAbstract(nodetype):
def is_abstract(nodetype):
return nodetype in abstracts
def op(cls):
cls.__is_firm_op = True
# Without new-style classes it is hard to detect the inheritance hierarchy
# later.
assert hasattr(cls, "__class__"), "must use new-style classes"
return cls
def isOp(nodetype):
def is_op(nodetype):
return hasattr(nodetype, "__is_firm_op")
class Attribute(object):
......@@ -29,34 +34,31 @@ class Attribute(object):
fqname = name
self.fqname = fqname
def is_dynamic_pinned(node):
return node.pinned == "exception"
class Operand(object):
pass
def is_fragile(node):
return hasattr(node, "flags") and "fragile" in node.flags
def Input(name, comment=None):
op = Operand()
op.name = name
op.comment = comment
return op
def inout_contains(l, name):
for entry in l:
if entry.name == name:
return True
return False
def Output(name, comment=None):
op = Operand()
op.name = name
op.comment = comment
return op
def verify_node(node):
if node.pinned not in ["yes", "no", "exception"]:
print("%s: UNKNOWN PINNED MODE: %s" % (node.name, node.pinned))
if not hasattr(node, "flags"):
if not isAbstract(node):
print("WARNING: no flags specified for %s\n" % node.name)
elif type(node.flags) != list:
print("ERROR: flags of %s not a list" % node.name)
if hasattr(node, "pinned_init") and not is_dynamic_pinned(node):
print("ERROR: node %s has pinned_init attribute but is not marked as dynamically pinned" % node.name)
if hasattr(node, "flags") and "uses_memory" in node.flags:
if "uses_memory" in node.flags:
if not inout_contains(node.ins, "mem"):
print("ERROR: memory op %s needs an input named 'mem'" % node.name)
if is_fragile(node):
if "fragile" in node.flags:
if not is_dynamic_pinned(node):
print("ERROR: fragile node %s must be dynamically pinned" % node.name)
if not hasattr(node, "throws_init"):
......@@ -80,43 +82,12 @@ def setdefault(node, attr, val):
if not hasattr(node, attr):
setattr(node, attr, val)
class Operand(object):
pass
def Input(name, comment=None):
op = Operand()
op.name = name
op.comment = comment
return op
def Output(name, comment=None):
op = Operand()
op.name = name
op.comment = comment
return op
def setnodedefaults(node):
setldefault(node, "name", node.__name__)
setdefault(node, "pinned", "no")
if isAbstract(node):
return
setdefault(node, "flags", [])
setdefault(node, "ins", [])
setdefault(node, "arity", len(node.ins))
setdefault(node, "attrs", [])
setdefault(node, "constructor", True)
setdefault(node, "constructor_args", [])
setdefault(node, "serializer", node.constructor)
setdefault(node, "block", None)
if hasattr(node, "__doc__"):
node.doc = trim_docstring(node.__doc__)
else:
node.doc = ""
if hasattr(node, "outs") and len(node.outs) > 1:
node.mode = "mode_T"
if "start_block" in node.flags:
node.block = "get_irg_start_block(irg)"
setdefault(node, "usesGraph", node.block != None)
# As a shortcut you can specify inputs either as a list of strings or
# as a list of (name, comment) tuples. Normalize it to Input objects
......@@ -138,36 +109,21 @@ def setnodedefaults(node):
new_outs.append(o)
node.outs = new_outs
def collect_ops(moduledict):
return [node for node in moduledict.values() if isOp(node) ]
def setdefaults(nodes):
for node in nodes:
setnodedefaults(node)
return nodes
def verify_spec(spec):
if len(spec.nodes) == 0:
sys.stderr.write("Warning: No nodes found in spec\n")
if not hasattr(spec, "name"):
sys.stderr.write("Warning: No name specified in node spec\n")
def load_spec(filename):
module = imp.load_source('spec', filename)
nodes = []
for x in module.__dict__.values():
if not isOp(x):
continue
setnodedefaults(x)
verify_node(x)
nodes.append(x)
nodes.sort(key=lambda x: x.name)
module.nodes = nodes
if len(nodes) == 0:
print("Warning: No nodes found in spec file '%s'" % filename)
if not hasattr(module, "name"):
print("Warning: No name specified in file '%s'" % filename)
return module
setdefault(node, "attrs", [])
setdefault(node, "constructor", True)
setdefault(node, "constructor_args", [])
setdefault(node, "serializer", node.constructor)
setdefault(node, "block", None)
if hasattr(node, "__doc__"):
node.doc = trim_docstring(node.__doc__)
else:
node.doc = ""
if hasattr(node, "outs") and len(node.outs) > 1:
node.mode = "mode_T"
if "start_block" in node.flags:
node.block = "get_irg_start_block(irg)"
if not is_abstract(node):
setdefault(node, "usesGraph", node.block != None)
def trim_docstring(docstring):
if not docstring:
......@@ -193,3 +149,341 @@ def trim_docstring(docstring):
trimmed.pop(0)
# Return a single string:
return '\n'.join(trimmed)
def parameterlist(parameterlist):
return "\n".join(parameterlist)
def nodearguments(node):
arguments = [arg.name for arg in node.arguments]
return parameterlist(arguments)
def nodeparameters(node):
parameters = ["%s %s" % (arg.type, arg.name) for arg in node.arguments]
return parameterlist(parameters)
def nodeparametershelp(node):
res = ""
for param in node.arguments:
res += " * @param %-9s %s\n" % (param.name, param.comment)
return res
def a_an(text):
if text[0] in "aAeEuUoOiI":
return "an " + text
return "a " + text
def blockparameter(node):
if not node.block:
return "ir_node *block"
elif node.usesGraph:
return "ir_graph *irg"
else:
return ""
def blockparameterhelp(node):
if not node.block:
return " * @param block The IR block the node belongs to.\n"
elif node.usesGraph:
return " * @param irg The IR graph the node belongs to.\n"
else:
return ""
def blockargument(node):
if not node.block:
return "block"
elif node.usesGraph:
return "irg"
else:
return ""
def blockassign(node):
if node.block:
return "ir_node *block = %s;" % node.block
else:
return ""
def irgassign(node):
if node.usesGraph:
return ""
else:
return "ir_graph *irg = get_irn_irg(block);\n"
def curblock(node):
if not node.block:
return "get_cur_block()"
elif node.usesGraph:
return "current_ir_graph"
else:
return ""
def insdecl(node):
arity = node.arity
if arity == "dynamic" or arity == "variable":
if len(node.ins) == 0:
return ""
insarity = len(node.ins)
res = "int r_arity = arity + " + repr(insarity) + ";"
res += "\n\tir_node **r_in= ALLOCAN(ir_node*, r_arity);"
i = 0
for input in node.ins:
res += "\n\tr_in[" + repr(i) + "] = irn_" + input.name + ";"
i += 1
res += "\n\tmemcpy(&r_in[" + repr(insarity) + "], in, sizeof(ir_node *) * arity);\n\t"
elif arity == 0:
return ""
else:
res = "ir_node *in[" + repr(arity) + "];"
i = 0
for input in node.ins:
res += "\n\tin[" + repr(i) + "] = irn_" + input.name + ";"
i += 1
return res
def arity_and_ins(node):
arity = node.arity