-
Notifications
You must be signed in to change notification settings - Fork 3
/
simdspec.py
191 lines (159 loc) · 6.37 KB
/
simdspec.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#
# Represent portable SIMD spec objects
#
import re
from typing import List, Tuple, Dict # noqa
class Interpretation(object):
'''One of the SIMD types or interpretations'''
def __init__(self, name: str) -> None:
self.name = name
self.parent = None # type: Interpretation
self.children = list() # type: List[Interpretation]
# Operations defined directly on this interpretation.
self.operations = list() # type: List[Operation]
def __repr__(self) -> str:
return 'Interpretation({})'.format(self.name)
def __str__(self) -> str:
return self.name
def pre(self) -> Tuple['Interpretation', ...]:
'''
Get a tuple containing a pre-order of all the children, starting with
self.
'''
return sum([c.pre() for c in self.children], (self,))
class Operation(object):
'''
A SIMD operation as identified by name only.
The 'add' operation is represented by one `Operation` object covering
`i32x4.add`, `i8x16.add`, ...
'''
def __init__(self, name: str) -> None:
self.name = name
self.signatures = dict() # type: Dict[Interpretation, Signature]
def __str__(self) -> str:
return self.name
def add_signature(self, interp: Interpretation, sig: 'Signature') -> None:
assert interp not in self.signatures, "Duplicate signature"
self.signatures[interp] = sig
def get_definition(self, interp: Interpretation) -> Interpretation:
'''
Get the Interpretation where this operation is defined for
`interp`.
This can be either `interp` itself or one of its parents.
'''
while interp:
if interp in self.signatures:
return interp
interp = interp.parent
return None
class Signature(object):
'''
A specific SIMD operation signature.
For the 'add'` operation, there are signatures for `i32x4.add`,
`i8x16.add`, etc. The signature ties operations and interpretations
together and stores the arguments and results too.
The `anchor` argument refers to the section of the spec where the Signature
is defined.
'''
def __init__(
self,
interpretation: Interpretation,
operation: Operation,
args: str,
result: str,
anchor: str
) -> None:
self.interpretation = interpretation
self.operation = operation
self.args = args
self.result = result
self.anchor = anchor
def with_result(self, new_result: str) -> 'Signature':
'''Return a new signature with a new result type'''
return Signature(
self.interpretation, self.operation, self.args, new_result,
self.anchor)
def mdlink(self, ext: str = 'md') -> str:
'''Get a Markdown link to this specification.'''
return '[{}.{}](portable-simd.{}{})'.format(
self.interpretation, self.operation, ext, self.anchor)
class Specification(object):
'''Collection of SIMD specification objects'''
def __init__(self) -> None:
# List of types/interpretations in order of appearance.
self.interpretations = list() # type: List[Interpretation]
self.interpretations_byname = dict() # type: Dict[str, Interpretation]
self.operations = list() # type: List[Operation]
self.operations_byname = dict() # type: Dict[str, Operation]
def interpretations_pre(self) -> Tuple[Interpretation, ...]:
'''
Get a tuple containing a pre-order of all the interpretations.
'''
return sum(
[it.pre() for it in self.interpretations
if it.parent is None], ())
def add_interpretation(self, interp: Interpretation) -> None:
'''Register a new Interpretation object'''
assert interp.name not in self.interpretations_byname, "Duplicate"
self.interpretations.append(interp)
self.interpretations_byname[interp.name] = interp
def get_operation(self, name: str) -> Operation:
'''
Get an `Operation` object with the requested name.
Create a new object if thisis the first time `name` is seen
'''
if name in self.operations_byname:
return self.operations_byname[name]
op = Operation(name)
self.operations.append(op)
self.operations_byname[name] = op
return op
def extract_interpretations(self, text: str) -> None:
'''
Find new `Interpretation` declarations in the text, add them to spec.
'''
# Definitions look like:
#
# * `i32x4 : v32x4`: ...
#
for m in re.finditer(
r'^\* `([visufb][0-9x]+)( : ([visufb][0-9x]+))?`', text,
re.MULTILINE):
interp = Interpretation(m.group(1))
pname = m.group(3)
if pname:
interp.parent = self.interpretations_byname[pname]
interp.parent.children.append(interp)
self.add_interpretation(interp)
def extract_operations(
self, text: str
) -> List[Tuple[Interpretation, Operation]]:
'''Find new `Operation` declarations in the text.'''
# Operations look like:
#
# * `i32x4.add(a : v128, b : v128) -> v128`
#
found = list() # type: List[Tuple[Interpretation, Operation]]
anchor = None
for m in re.finditer(
r'^#+\s*(.*)|' +
r'^\* `(?P<it>[visufb][0-9x]+)\.' +
r'(?P<op>\w+)\((?P<args>[^)]*)\)\s*(->\s*(?P<res>.*))?`', text,
re.MULTILINE):
if m.group(0).startswith('#'):
# This is a section header.
anchor = '#' + '-'.join(m.group(1).lower().split())
continue
interp = self.interpretations_byname[m.group('it')]
op = self.get_operation(m.group('op'))
args = m.group('args')
result = m.group('res')
op.add_signature(
interp, Signature(interp, op, args, result, anchor))
interp.operations.append(op)
found.append((interp, op))
return found
def parse(self, text: str) -> None:
'''Parse the spec text and add all definitions to self'''
self.extract_interpretations(text)
self.extract_operations(text)