-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathannotator.py
167 lines (145 loc) · 5.07 KB
/
annotator.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
# Annotator needs to find the least generic type for everything.
# To do that, it needs to hold a model of our types.
class Annotator(object):
def __init__(self, unit):
self.unit = unit
self.stack = []
def update(self, func):
for block in func:
for op in block.ops:
if not op.queued:
self.stack.append(op)
op.queued = True
def run(self):
while len(self.stack) > 0:
op = self.stack.pop()
op.queued = False
if op.name == 'call':
print 'annotate', op
elif op.name == 'return':
a = union(op.block.func.annotation.restype, op.args[0].annotation)
op.args[0].annotation = a
op.block.func.annotation.restype = a
op.annotation = a
print 'return update', op, a
# bit incorrect, should push uses of argument in too.
else:
assert False
# Should annotate here, if some of the fields change,
# should reschedule the used fields.
# SPIR-V annotation may need much simpler rules than specified here.
# Anything -annotation in translation unit most likely means
# that the translation failed.
class Anything(object):
specificity = 0
parametric = False
def __repr__(self):
return 'anything'
# The next most specific type after 'Unbound'.
class Constant(object):
def __init__(self, type, value):
self.type = type
self.value = value
def __repr__(self):
return 'Constant({}, {})'.format(self.type, self.value)
class FuncType(object):
def __init__(self, restype, argtypes):
self.restype = restype
self.argtypes = argtypes
def __getitem__(self, index):
return self.argtypes[index]
def __len__(self):
return len(self.argtypes)
def __repr__(self):
return '({}) ->'.format(', '.join(map(repr, self.argtypes)), self.restype)
class Type(object):
def __call__(self, parameter):
assert self.parametric
return Parametric(self, parameter)
def __init__(self, name, generic, parametric=False):
self.name = name
self.generic = generic
self.parametric = parametric
self.specificity = generic.specificity+1
def __repr__(self):
return self.name
class Parametric(object):
def __init__(self, func, parameter):
self.func = func
self.parameter = parameter
def __repr__(self):
return "{}({})".format(self.func, self.parameter)
# Types are treated as notation. They should be uniquely identified.
anything = Anything()
# not sure whether these belong here.
t_int = Type('int', anything)
t_uint = Type('uint', t_int)
t_bool = Type('bool', t_uint)
t_float = Type('float', anything)
t_vec2 = Type('vec2', anything, parametric=True)
t_vec3 = Type('vec3', anything, parametric=True)
t_vec4 = Type('vec4', anything, parametric=True)
# Thought about doing them this way, but realized types
# would require unification by their type hierarchies.
# # nullable = Type('nullable', anything, parametric=True)
# # instance = Type('instance', nullable, parametric=True)
# # t_null = Type('null', nullable)
# I don't want parametric types to leak from
# their parametric container.
def union(a, b):
c = union_raw(a, b)
while isinstance(c, Type) and c.parametric:
c = c.generic
return c
# But we still may use unification results which
# return parametric types.
def union_raw(a, b):
if a is b:
return a
if a is None:
return b
if b is None:
return a
if isinstance(a, Constant) and isinstance(b, Constant):
if a.value == b.value:
return a
else:
return union_raw(a.type, b.type)
elif isinstance(a, Constant):
return union_raw(a.type, b)
elif isinstance(b, Constant):
return union_raw(a, b.type)
if isinstance(a, Type) and isinstance(b, Type):
specificity = min(a.specificity, b.specificity)
while a.specificity > specificity:
a = a.generic
while b.specificity > specificity:
b = b.generic
while a is not b:
a = a.generic
b = b.generic
assert a is not None
return a
elif isinstance(a, Parametric) and isinstance(b, Parametric):
tp = union_raw(a.func, b.func)
if tp.parametric:
return Parametric(tp, union(a.parameter, b.parameter))
else:
return tp
elif isinstance(a, Parametric):
tp = union_raw(a.func, b)
if tp.parametric:
return Parametric(tp, a.parameter)
else:
return tp
elif isinstance(b, Parametric):
tp = union_raw(b.func, a)
if tp.parametric:
return Parametric(tp, b.parameter)
else:
return tp
elif isinstance(a, FuncType) and isinstance(b, FuncType) and len(a) == len(b):
return FuncType(
union(a.restype, b.restype),
[union(c, d) for c, d in zip(a, b)])
return anything