spec_util.py 5.56 KB
Newer Older
1
2
# This file is part of libFirm.
# Copyright (C) 2012 Karlsruhe Institute of Technology.
Matthias Braun's avatar
Matthias Braun committed
3
import sys
Matthias Braun's avatar
Matthias Braun committed
4
import imp
Matthias Braun's avatar
Matthias Braun committed
5

6
7
8
9
10
11
12
abstracts = set()
def abstract(cls):
	abstracts.add(cls)
	return cls
def isAbstract(nodetype):
	return nodetype in abstracts

Matthias Braun's avatar
Matthias Braun committed
13
14
15
16
17
18
def op(cls):
	cls.__is_firm_op = True
	return cls
def isOp(nodetype):
	return hasattr(nodetype, "__is_firm_op")

19
20
21
22
23
24
25
26
27
28
29
30
class Attribute(object):
	def __init__(self, name, type, comment="", init=None, to_flags=None, noprop=False, fqname=None):
		self.type     = type
		self.name     = name
		self.comment  = comment
		self.init     = init
		self.to_flags = to_flags
		self.noprop   = noprop
		if fqname is None:
			fqname = name
		self.fqname = fqname

31
def is_dynamic_pinned(node):
32
	return node.pinned == "exception"
33

34
35
36
def is_fragile(node):
	return hasattr(node, "flags") and "fragile" in node.flags

Matthias Braun's avatar
Matthias Braun committed
37
38
def inout_contains(l, name):
	for entry in l:
39
		if entry.name == name:
Matthias Braun's avatar
Matthias Braun committed
40
41
42
			return True
	return False

43
def verify_node(node):
44
	if node.pinned not in ["yes", "no", "exception"]:
45
		print("%s: UNKNOWN PINNED MODE: %s" % (node.name, node.pinned))
46

Matthias Braun's avatar
Matthias Braun committed
47
48
	if not hasattr(node, "flags"):
		if not isAbstract(node):
49
			print("WARNING: no flags specified for %s\n" % node.name)
50
	elif type(node.flags) != list:
51
		print("ERROR: flags of %s not a list" % node.name)
Matthias Braun's avatar
Matthias Braun committed
52

53
	if hasattr(node, "pinned_init") and not is_dynamic_pinned(node):
54
		print("ERROR: node %s has pinned_init attribute but is not marked as dynamically pinned" % node.name)
55
56
	if hasattr(node, "flags") and "uses_memory" in node.flags:
		if not inout_contains(node.ins, "mem"):
57
			print("ERROR: memory op %s needs an input named 'mem'" % node.name)
58
59
	if is_fragile(node):
		if not is_dynamic_pinned(node):
60
			print("ERROR: fragile node %s must be dynamically pinned" % node.name)
61
		if not hasattr(node, "throws_init"):
62
			print("ERROR: fragile node %s needs a throws_init attribute" % node.name)
63
		if not inout_contains(node.outs, "X_regular"):
64
			print("ERROR: fragile node %s needs an output named 'X_regular'" % node.name)
65
		if not inout_contains(node.outs, "X_except"):
66
			print("ERROR: fragile node %s needs an output named 'X_except'" % node.name)
67
68
	else:
		if hasattr(node, "throws_init"):
69
			print("ERROR: throws_init only makes sense for fragile nodes")
70

71
72
73
74
75
76
77
78
79
80
81

def setldefault(node, attr, val):
	# Don't use hasattr, as these things should not be inherited
	if attr not in node.__dict__:
		setattr(node, attr, val)

def setdefault(node, attr, val):
	# Don't use hasattr, as these things should not be inherited
	if not hasattr(node, attr):
		setattr(node, attr, val)

82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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

97
98
def setnodedefaults(node):
	setldefault(node, "name", node.__name__)
99
	setdefault(node, "pinned", "no")
100
101
	if isAbstract(node):
		return
102

103
104
105
106
	setdefault(node, "ins", [])
	setdefault(node, "arity", len(node.ins))
	setdefault(node, "attrs", [])
	setdefault(node, "constructor_args", [])
107
	setdefault(node, "customSerializer", False)
108
	setdefault(node, "block", None)
Matthias Braun's avatar
Matthias Braun committed
109
110
111
112
	if hasattr(node, "__doc__"):
		node.doc = trim_docstring(node.__doc__)
	else:
		node.doc = ""
113
	if hasattr(node, "outs") and len(node.outs) > 1:
114
		node.mode = "mode_T"
115
116
117
	if "start_block" in node.flags:
		node.block = "get_irg_start_block(irg)"
	setdefault(node, "usesGraph", node.block != None)
Matthias Braun's avatar
Matthias Braun committed
118

119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
	# 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
	new_ins = []
	for i in node.ins:
		if isinstance(i, basestring):
			i = Input(i)
		elif isinstance(i, tuple):
			i = Input(name=i[0], comment=i[1])
		new_ins.append(i)
	node.ins = new_ins
	if hasattr(node, "outs"):
		new_outs = []
		for o in node.outs:
			if isinstance(o, basestring):
				o = Output(o)
			elif isinstance(o, tuple):
				o = Output(name=o[0], comment=o[1])
			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")

Matthias Braun's avatar
Matthias Braun committed
153
154
155
156
157
158
159
160
161
162
163
164
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:
165
		print("Warning: No nodes found in spec file '%s'" % filename)
Matthias Braun's avatar
Matthias Braun committed
166
	if not hasattr(module, "name"):
167
		print("Warning: No name specified in file '%s'" % filename)
Matthias Braun's avatar
Matthias Braun committed
168
169
	return module

Matthias Braun's avatar
Matthias Braun committed
170
171
172
173
174
175
176
def trim_docstring(docstring):
    if not docstring:
        return ''
    # Convert tabs to spaces (following the normal Python rules)
    # and split into a list of lines:
    lines = docstring.expandtabs().splitlines()
    # Determine minimum indentation (first line doesn't count):
Matthias Braun's avatar
Matthias Braun committed
177
    indent = sys.maxsize
Matthias Braun's avatar
Matthias Braun committed
178
179
180
181
182
183
    for line in lines[1:]:
        stripped = line.lstrip()
        if stripped:
            indent = min(indent, len(line) - len(stripped))
    # Remove indentation (first line is special):
    trimmed = [lines[0].strip()]
Matthias Braun's avatar
Matthias Braun committed
184
    if indent < sys.maxsize:
Matthias Braun's avatar
Matthias Braun committed
185
186
187
188
189
190
191
192
193
        for line in lines[1:]:
            trimmed.append(line[indent:].rstrip())
    # Strip off trailing and leading blank lines:
    while trimmed and not trimmed[-1]:
        trimmed.pop()
    while trimmed and not trimmed[0]:
        trimmed.pop(0)
    # Return a single string:
    return '\n'.join(trimmed)