gisel 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gisel/__init__.py +3 -0
- gisel/__main__.py +6 -0
- gisel/backend/__init__.py +0 -0
- gisel/backend/check_json.py +57 -0
- gisel/backend/core_json.py +192 -0
- gisel/backend/llvm_inc.py +495 -0
- gisel/backend/table.py +617 -0
- gisel/cli.py +238 -0
- gisel/data/generic_opcodes.json +290 -0
- gisel/dsl.py +1469 -0
- gisel/eval.py +1008 -0
- gisel/td.py +915 -0
- gisel/vocab.py +28 -0
- gisel-0.2.0.dist-info/METADATA +379 -0
- gisel-0.2.0.dist-info/RECORD +19 -0
- gisel-0.2.0.dist-info/WHEEL +5 -0
- gisel-0.2.0.dist-info/entry_points.txt +2 -0
- gisel-0.2.0.dist-info/licenses/LICENSE +279 -0
- gisel-0.2.0.dist-info/top_level.txt +1 -0
gisel/backend/table.py
ADDED
|
@@ -0,0 +1,617 @@
|
|
|
1
|
+
"""Type classes for the ``-gen-legalizer-table`` backend.
|
|
2
|
+
|
|
3
|
+
M3 step 1: ``resolve`` and ``collectClasses``/``collectMemClasses``
|
|
4
|
+
(LegalizerInfoEmitter.cpp:5157-5400). The rule translation, the descriptors
|
|
5
|
+
and the per-rule-set evaluators come next; this module is what they index
|
|
6
|
+
into, so it is verified against the artifact's class tables before any of that
|
|
7
|
+
is written.
|
|
8
|
+
|
|
9
|
+
Classes are keyed by ``(kind, element bits, lanes)`` and ordered by
|
|
10
|
+
``lessTypeClass``: kind rank, then element bits, then lanes. The ``root`` of a
|
|
11
|
+
class is the first named type (in declaration order) that produced it, which
|
|
12
|
+
is what the generated ``// X86_s16`` comments record.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from collections import namedtuple
|
|
16
|
+
|
|
17
|
+
TableType = namedtuple("TableType", "kind bits lanes root")
|
|
18
|
+
|
|
19
|
+
# typeRank, LegalizerInfoEmitter.cpp:5323
|
|
20
|
+
RANK = {
|
|
21
|
+
"Pointer": 0,
|
|
22
|
+
"Scalar": 1,
|
|
23
|
+
"Integer": 2,
|
|
24
|
+
"Float": 3,
|
|
25
|
+
"BFloat": 4,
|
|
26
|
+
"Vector": 5,
|
|
27
|
+
"PtrVector": 6,
|
|
28
|
+
"ScalableVector": 7,
|
|
29
|
+
"ScalablePtrVector": 8,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# tableTypeKindName, :5372
|
|
33
|
+
KIND_NAME = {
|
|
34
|
+
"Pointer": "Kind_Pointer",
|
|
35
|
+
"Scalar": "Kind_Scalar",
|
|
36
|
+
"Integer": "Kind_Integer",
|
|
37
|
+
"Float": "Kind_Float",
|
|
38
|
+
"BFloat": "Kind_BFloat",
|
|
39
|
+
"Vector": "Kind_Vector",
|
|
40
|
+
"PtrVector": "Kind_PtrVector",
|
|
41
|
+
"ScalableVector": "Kind_ScalableVector",
|
|
42
|
+
"ScalablePtrVector": "Kind_ScalablePtrVector",
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
SCALARS = ("Scalar", "Integer", "Float", "BFloat")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def strip_parens(s):
|
|
49
|
+
s = s.strip()
|
|
50
|
+
while s.startswith("(") and s.endswith(")"):
|
|
51
|
+
depth = 0
|
|
52
|
+
for i, ch in enumerate(s):
|
|
53
|
+
if ch == "(":
|
|
54
|
+
depth += 1
|
|
55
|
+
elif ch == ")":
|
|
56
|
+
depth -= 1
|
|
57
|
+
if depth == 0 and i != len(s) - 1:
|
|
58
|
+
return s # the leading '(' closes before the end
|
|
59
|
+
s = s[1:-1].strip()
|
|
60
|
+
return s
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def split_conditional(s):
|
|
64
|
+
"""`Cond ? Then : Else` at depth 0 -> (Then, Else), else None."""
|
|
65
|
+
depth = 0
|
|
66
|
+
q = -1
|
|
67
|
+
for i, ch in enumerate(s):
|
|
68
|
+
if ch in "([":
|
|
69
|
+
depth += 1
|
|
70
|
+
elif ch in ")]":
|
|
71
|
+
depth -= 1
|
|
72
|
+
elif ch == "?" and depth == 0:
|
|
73
|
+
q = i
|
|
74
|
+
break
|
|
75
|
+
if q < 0:
|
|
76
|
+
return None
|
|
77
|
+
depth = 0
|
|
78
|
+
for i in range(q + 1, len(s)):
|
|
79
|
+
ch = s[i]
|
|
80
|
+
if ch in "([":
|
|
81
|
+
depth += 1
|
|
82
|
+
elif ch in ")]":
|
|
83
|
+
depth -= 1
|
|
84
|
+
elif ch == ":" and depth == 0:
|
|
85
|
+
return s[q + 1:i].strip(), s[i + 1:].strip()
|
|
86
|
+
return None
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _arg_of(expr, prefix):
|
|
90
|
+
if expr.startswith(prefix) and expr.endswith(")"):
|
|
91
|
+
return expr[len(prefix):-1].strip()
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _split_lanes(arg):
|
|
96
|
+
depth = 0
|
|
97
|
+
for i, ch in enumerate(arg):
|
|
98
|
+
if ch in "([":
|
|
99
|
+
depth += 1
|
|
100
|
+
elif ch in ")]":
|
|
101
|
+
depth -= 1
|
|
102
|
+
elif ch == "," and depth == 0:
|
|
103
|
+
return arg[:i].strip(), arg[i + 1:].strip()
|
|
104
|
+
return None, None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class Resolver:
|
|
108
|
+
def __init__(self, gs):
|
|
109
|
+
# A select type names a condition, not a class; its branches are
|
|
110
|
+
# named types in their own right and are collected when reached.
|
|
111
|
+
self.named = {n: p for k, n, p in gs["decls"] if k == "type"}
|
|
112
|
+
|
|
113
|
+
def resolve(self, expr, root, depth=0):
|
|
114
|
+
expr = strip_parens(expr)
|
|
115
|
+
if depth > 16:
|
|
116
|
+
raise ValueError("type expression nests too deep: %r" % expr)
|
|
117
|
+
|
|
118
|
+
split = split_conditional(expr)
|
|
119
|
+
if split:
|
|
120
|
+
return (self.resolve(split[0], root, depth) +
|
|
121
|
+
self.resolve(split[1], root, depth))
|
|
122
|
+
|
|
123
|
+
arg = _arg_of(expr, "LLT::scalar(")
|
|
124
|
+
if arg is not None:
|
|
125
|
+
return [TableType("Scalar", int(arg), 1, root)]
|
|
126
|
+
if _arg_of(expr, "LLT::pointer(") is not None:
|
|
127
|
+
return [TableType("Pointer", 0, 1, root)]
|
|
128
|
+
arg = _arg_of(expr, "LLT::integer(")
|
|
129
|
+
if arg is not None:
|
|
130
|
+
return [TableType("Integer", int(arg), 1, root)]
|
|
131
|
+
|
|
132
|
+
for name, bits in (("float16", 16), ("float32", 32), ("float64", 64),
|
|
133
|
+
("float128", 128)):
|
|
134
|
+
if expr == "LLT::%s()" % name:
|
|
135
|
+
return [TableType("Float", bits, 1, root)]
|
|
136
|
+
if expr == "LLT::bfloat16()":
|
|
137
|
+
return [TableType("BFloat", 16, 1, root)]
|
|
138
|
+
|
|
139
|
+
for prefix, kind, ptr_kind in (
|
|
140
|
+
("LLT::scalable_vector(", "ScalableVector",
|
|
141
|
+
"ScalablePtrVector"),
|
|
142
|
+
("LLT::fixed_vector(", "Vector", "PtrVector")):
|
|
143
|
+
arg = _arg_of(expr, prefix)
|
|
144
|
+
if arg is None:
|
|
145
|
+
continue
|
|
146
|
+
lanes, elem = _split_lanes(arg)
|
|
147
|
+
if lanes is None:
|
|
148
|
+
raise ValueError("malformed vector type %r" % expr)
|
|
149
|
+
lanes = int(lanes)
|
|
150
|
+
if elem.isdigit():
|
|
151
|
+
return [TableType(kind, int(elem), lanes, root)]
|
|
152
|
+
out = []
|
|
153
|
+
for e in self.resolve(elem, root, depth + 1):
|
|
154
|
+
if e.kind in SCALARS:
|
|
155
|
+
out.append(TableType(kind, e.bits, lanes, root))
|
|
156
|
+
elif e.kind == "Pointer":
|
|
157
|
+
out.append(TableType(ptr_kind, 0, lanes, root))
|
|
158
|
+
else:
|
|
159
|
+
raise ValueError("unsupported vector element in %r" % expr)
|
|
160
|
+
return out
|
|
161
|
+
|
|
162
|
+
if expr and (expr[0].isalpha() or expr[0] == "_") and \
|
|
163
|
+
all(c.isalnum() or c == "_" for c in expr):
|
|
164
|
+
if expr not in self.named:
|
|
165
|
+
raise ValueError("unknown named type %r" % expr)
|
|
166
|
+
return self.resolve(self.named[expr], root, depth + 1)
|
|
167
|
+
|
|
168
|
+
raise ValueError("cannot derive a table type class from %r" % expr)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def less_type_class(t):
|
|
172
|
+
return (RANK[t.kind], t.bits, t.lanes)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def collect_classes(gs):
|
|
176
|
+
r = Resolver(gs)
|
|
177
|
+
types = [(n, p) for k, n, p in gs["decls"] if k == "type"]
|
|
178
|
+
seen, out = set(), []
|
|
179
|
+
for name, expr in types:
|
|
180
|
+
for t in r.resolve(expr, name):
|
|
181
|
+
key = (t.kind, t.bits, t.lanes)
|
|
182
|
+
if key in seen:
|
|
183
|
+
continue
|
|
184
|
+
seen.add(key)
|
|
185
|
+
out.append(t)
|
|
186
|
+
out.sort(key=less_type_class)
|
|
187
|
+
if not out or out[0].kind != "Pointer":
|
|
188
|
+
raise ValueError("a legalizer table needs a pointer type class")
|
|
189
|
+
return out
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def collect_mem_classes(gs, classes=None):
|
|
193
|
+
r = Resolver(gs)
|
|
194
|
+
classes = classes if classes is not None else collect_classes(gs)
|
|
195
|
+
types = [(n, p) for k, n, p in gs["decls"] if k == "type"]
|
|
196
|
+
seen, out = set(), []
|
|
197
|
+
for name, expr in types:
|
|
198
|
+
for t in r.resolve(expr, name):
|
|
199
|
+
key = (t.kind, t.bits, t.lanes)
|
|
200
|
+
if key in seen:
|
|
201
|
+
continue
|
|
202
|
+
seen.add(key)
|
|
203
|
+
out.append(t)
|
|
204
|
+
# The pointer class is the one width the .td leaves to the subtarget, and
|
|
205
|
+
# it is also the self-check probe for a memdesc rule set.
|
|
206
|
+
if ("Pointer", 0, 1) not in seen:
|
|
207
|
+
out.append(TableType("Pointer", 0, 1, "p0"))
|
|
208
|
+
out.sort(key=less_type_class)
|
|
209
|
+
return out or [classes[0]]
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def dump(gs):
|
|
213
|
+
"""A text rendering close to the artifact, for diffing by eye."""
|
|
214
|
+
lines = []
|
|
215
|
+
for label, items in (("TypeClasses", collect_classes(gs)),
|
|
216
|
+
("MemClasses", collect_mem_classes(gs))):
|
|
217
|
+
lines.append("%s (%d):" % (label, len(items)))
|
|
218
|
+
for i, t in enumerate(items):
|
|
219
|
+
lines.append(" /*%d*/ {%s, %d, %d}, // %s"
|
|
220
|
+
% (i, KIND_NAME[t.kind], t.bits, t.lanes, t.root))
|
|
221
|
+
return "\n".join(lines) + "\n"
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
# ---- sections 1-3 of the artifact ----------------------------------------
|
|
225
|
+
|
|
226
|
+
HEADER = """\
|
|
227
|
+
//===-- {P}LegalizerTable.inc - generated table data -----*- C++ -*-===//
|
|
228
|
+
//
|
|
229
|
+
// Generated by llvm-tblgen -gen-legalizer-table. Do not edit.
|
|
230
|
+
// Type classes, per-opcode descriptors and the per-rule-set evaluators.
|
|
231
|
+
//
|
|
232
|
+
//===----------------------------------------------------------------------===//
|
|
233
|
+
"""
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def _walk(node, pred):
|
|
237
|
+
if isinstance(node, dict):
|
|
238
|
+
if pred(node):
|
|
239
|
+
return True
|
|
240
|
+
return any(_walk(v, pred) for v in node.values())
|
|
241
|
+
if isinstance(node, list):
|
|
242
|
+
return any(_walk(v, pred) for v in node)
|
|
243
|
+
return False
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def reads_mem_desc(rule):
|
|
247
|
+
"""True when the rule reads a memory descriptor (needsMemDesc, :5540)."""
|
|
248
|
+
return any(_walk(part, lambda n: n.get("kind") in ("memSlot", "inMemDesc"))
|
|
249
|
+
for part in (rule.get("on"), rule.get("to"), rule.get("predicate")))
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def mem_desc_aligns(rule):
|
|
253
|
+
"""The alignment thresholds a rule's memdesc sets name (:5580)."""
|
|
254
|
+
out = set()
|
|
255
|
+
|
|
256
|
+
def visit(node):
|
|
257
|
+
if isinstance(node, dict):
|
|
258
|
+
if node.get("kind") in ("inMemDesc", "set") and node.get("arity") == 2:
|
|
259
|
+
for e in node.get("elems", []):
|
|
260
|
+
if len(e) == 4:
|
|
261
|
+
out.add(e[3])
|
|
262
|
+
for v in node.values():
|
|
263
|
+
visit(v)
|
|
264
|
+
elif isinstance(node, list):
|
|
265
|
+
for v in node:
|
|
266
|
+
visit(v)
|
|
267
|
+
|
|
268
|
+
for part in (rule.get("on"), rule.get("to"), rule.get("predicate")):
|
|
269
|
+
visit(part)
|
|
270
|
+
return out
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def needs_mem_desc(ruleset):
|
|
274
|
+
return any(reads_mem_desc(r) for r in ruleset["rules"])
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def align_thresholds(gs):
|
|
278
|
+
out = set()
|
|
279
|
+
for rs in gs["rulesets"]:
|
|
280
|
+
if not needs_mem_desc(rs):
|
|
281
|
+
continue
|
|
282
|
+
for r in rs["rules"]:
|
|
283
|
+
out |= mem_desc_aligns(r)
|
|
284
|
+
return sorted(out)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def emit_feature_signature(gs, P):
|
|
288
|
+
feats = [(n, p) for k, n, p in gs["decls"] if k == "feature"]
|
|
289
|
+
if len(feats) > 32:
|
|
290
|
+
raise ValueError("feature signature needs more than 32 bits")
|
|
291
|
+
out = ["// Environment signature: one bit per LegalizeFeature, in .td order.",
|
|
292
|
+
"// A shared table cache keys on this, so equal signatures must mean equal",
|
|
293
|
+
"// answers.",
|
|
294
|
+
"enum : uint32_t {"]
|
|
295
|
+
for i, (name, cond) in enumerate(feats):
|
|
296
|
+
out.append(" %sFeatureBit_%s = 1u << %d," % (P, name, i))
|
|
297
|
+
out += ["};", "",
|
|
298
|
+
"static uint32_t %sFeatureSignature(const %sSubtarget &Subtarget) {"
|
|
299
|
+
% (P, P),
|
|
300
|
+
" uint32_t S = 0;"]
|
|
301
|
+
for name, cond in feats:
|
|
302
|
+
out.append(" S |= (%s) ? %sFeatureBit_%s : 0u;" % (cond, P, name))
|
|
303
|
+
out += [" return S;", "}", ""]
|
|
304
|
+
return out
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def _class_lines(name, items):
|
|
308
|
+
out = ["static constexpr LegalizerTypeClass %s[] = {" % name]
|
|
309
|
+
for i, t in enumerate(items):
|
|
310
|
+
out.append(" /*%d*/ {%s, %d, %d}, // %s"
|
|
311
|
+
% (i, KIND_NAME[t.kind], t.bits, t.lanes, t.root))
|
|
312
|
+
out.append("};")
|
|
313
|
+
return out
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def emit_head(gs, P):
|
|
317
|
+
"""Everything before the per-rule-set evaluators."""
|
|
318
|
+
classes = collect_classes(gs)
|
|
319
|
+
mem = collect_mem_classes(gs, classes)
|
|
320
|
+
aligns = align_thresholds(gs)
|
|
321
|
+
|
|
322
|
+
out = HEADER.format(P=P).splitlines()
|
|
323
|
+
out.append("")
|
|
324
|
+
out += emit_feature_signature(gs, P)
|
|
325
|
+
out += _class_lines(P + "TypeClasses", classes)
|
|
326
|
+
out.append("static constexpr unsigned %sNumTypeClasses = sizeof(%sTypeClasses)"
|
|
327
|
+
" / sizeof(%sTypeClasses[0]);" % (P, P, P))
|
|
328
|
+
out.append("")
|
|
329
|
+
out.append("// Classes of the memory-descriptor axis (the descriptor's LLT).")
|
|
330
|
+
out += _class_lines(P + "MemClasses", mem)
|
|
331
|
+
out.append("static constexpr unsigned %sNumMemClasses = sizeof(%sMemClasses)"
|
|
332
|
+
" / sizeof(%sMemClasses[0]);" % (P, P, P))
|
|
333
|
+
out.append("")
|
|
334
|
+
out.append("// Alignment classes for the memory-descriptor axis: a query meets a")
|
|
335
|
+
out.append("// prefix of the thresholds, because TypePairAndMemDesc only asks")
|
|
336
|
+
out.append("// Align >= Entry.Align.")
|
|
337
|
+
out.append("static constexpr unsigned %sAlignThresholds[] = {%s};"
|
|
338
|
+
% (P, ", ".join(str(a) for a in aligns)))
|
|
339
|
+
out.append("static constexpr unsigned %sNumAlignClasses = sizeof(%sAlignThresholds)"
|
|
340
|
+
" / sizeof(%sAlignThresholds[0]) + 1;" % (P, P, P))
|
|
341
|
+
out.append("")
|
|
342
|
+
out.append("// Slots 0 and 1, partitioned by the full class list; a rule set that")
|
|
343
|
+
out.append("// reads a memory descriptor adds the descriptor axis. A rule set")
|
|
344
|
+
out.append("// that needs anything else is not in this table (see the emitter).")
|
|
345
|
+
out.append("static constexpr LegalizerTableDesc %sTables[] = {" % P)
|
|
346
|
+
for i, rs in enumerate(gs["rulesets"]):
|
|
347
|
+
has_mem = needs_mem_desc(rs)
|
|
348
|
+
out.append(" /*%d*/ {{0, 1}, {%d, %d}, %s, %s}, // %s"
|
|
349
|
+
% (i, len(classes), len(classes),
|
|
350
|
+
"0" if has_mem else "kNoMemDesc",
|
|
351
|
+
("%sNumMemClasses * %sNumAlignClasses" % (P, P))
|
|
352
|
+
if has_mem else "0",
|
|
353
|
+
rs["def"]))
|
|
354
|
+
out.append("};")
|
|
355
|
+
out.append("static constexpr unsigned %sNumTables = sizeof(%sTables)"
|
|
356
|
+
" / sizeof(%sTables[0]);" % (P, P, P))
|
|
357
|
+
out.append("")
|
|
358
|
+
lower = P[:1].lower() + P[1:]
|
|
359
|
+
out.append("static inline int %sTableForOpcode(unsigned Opcode) {" % lower)
|
|
360
|
+
out.append(" switch (Opcode) {")
|
|
361
|
+
for i, rs in enumerate(gs["rulesets"]):
|
|
362
|
+
for op in rs["opcodes"]:
|
|
363
|
+
out.append(" case TargetOpcode::%s: return %d;" % (op, i))
|
|
364
|
+
out += [" default: return -1;", " }", "}", ""]
|
|
365
|
+
return out
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
# ---- rule translation -----------------------------------------------------
|
|
369
|
+
|
|
370
|
+
# CoreTableTranslation per shim row, LegalizerInfoEmitter.cpp:2747-2815.
|
|
371
|
+
# Kept beside the shim table rather than inside it so the .inc backend stays
|
|
372
|
+
# the single owner of the C++ spelling; a test asserts the key sets agree.
|
|
373
|
+
TRANSLATION = {
|
|
374
|
+
("widen", "slot", "pow2"): "ScalarPow2",
|
|
375
|
+
("widen", "slot", "pow2Min"): "ScalarPow2",
|
|
376
|
+
("widen", "slot", "multipleOf"): "ScalarMultipleOf",
|
|
377
|
+
("widen", "slot", "ty"): "MinScalar",
|
|
378
|
+
("widen", "slot", "sameAs"): "MinScalarSameAs",
|
|
379
|
+
("widen", "elem", "pow2"): "ScalarOrEltPow2",
|
|
380
|
+
("widen", "elem", "pow2Min"): "ScalarOrEltPow2",
|
|
381
|
+
("widen", "elem", "multipleOf"): "ScalarMultipleOf",
|
|
382
|
+
("widen", "elem", "ty"): "MinScalarOrElt",
|
|
383
|
+
("widen", "elem", "sameAs"): "MinScalarSameAs",
|
|
384
|
+
("widen", "elem", "minVectorSize"): "WidenVectorMinSize",
|
|
385
|
+
("widen", "slot", "select"): "WidenPow2OrMinSize",
|
|
386
|
+
("widen", "slot", "int"): "WidenPow2OrMinSize",
|
|
387
|
+
("narrow", "slot", "ty"): "MaxScalar",
|
|
388
|
+
("narrow", "slot", "sameAs"): "MaxScalarSameAs",
|
|
389
|
+
("narrow", "elem", "ty"): "MaxScalarOrElt",
|
|
390
|
+
("more", "slot", "pow2"): "MorePow2",
|
|
391
|
+
("fewer", "slot", "ty"): "FewerToType",
|
|
392
|
+
("bitcast", "slot", "ty"): "BitcastToType",
|
|
393
|
+
("widen", "slot", "replace"): "WholeTypeMutation",
|
|
394
|
+
("narrow", "slot", "replace"): "WholeTypeMutation",
|
|
395
|
+
("more", "slot", "replace"): "WholeTypeMutation",
|
|
396
|
+
("fewer", "slot", "replace"): "WholeTypeMutation",
|
|
397
|
+
("bitcast", "slot", "replace"): "WholeTypeMutation",
|
|
398
|
+
("legal", "", ""): "GuardedAction",
|
|
399
|
+
("custom", "", ""): "GuardedAction",
|
|
400
|
+
("lower", "", ""): "GuardedAction",
|
|
401
|
+
("unsupported", "", ""): "GuardedAction",
|
|
402
|
+
("libcall", "", ""): "GuardedAction",
|
|
403
|
+
("scalarize", "slot", ""): "Scalarize",
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def conjunction(a, b):
|
|
408
|
+
"""conjunction(), :6133."""
|
|
409
|
+
if not a:
|
|
410
|
+
return b
|
|
411
|
+
if not b:
|
|
412
|
+
return a
|
|
413
|
+
return "(%s) && (%s)" % (a, b)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def emit_step(action, indent, mutation="", typed=None):
|
|
417
|
+
"""emitStep()/emitTypedStep(), :6149."""
|
|
418
|
+
if typed is not None:
|
|
419
|
+
return [indent + "return {LegalizeActions::%s, %s, %s};" % (action, typed[0], typed[1])]
|
|
420
|
+
if not mutation:
|
|
421
|
+
return [indent + "return {LegalizeActions::%s, 0, LLT{}};" % action]
|
|
422
|
+
return [indent + "auto M = (%s)(Q);" % mutation,
|
|
423
|
+
indent + "return {LegalizeActions::%s, M.first, M.second};" % action]
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def translate_core_rule(rule, cxx):
|
|
427
|
+
"""translateCoreRule(), :6859. Returns (statements, reason)."""
|
|
428
|
+
on = rule.get("on")
|
|
429
|
+
to = rule.get("to")
|
|
430
|
+
on_form = {"elemOf": "elem"}.get(on["kind"], on["kind"]) if on else ""
|
|
431
|
+
to_form = to["kind"] if to else ""
|
|
432
|
+
key = (rule["op"], on_form, to_form)
|
|
433
|
+
tr = TRANSLATION.get(key)
|
|
434
|
+
if tr is None:
|
|
435
|
+
return None, "no table translation for %s/%s/%s" % key
|
|
436
|
+
|
|
437
|
+
idx = str(rule["type_idx"])
|
|
438
|
+
v = "Q.Types[%s]" % idx
|
|
439
|
+
guard = rule["predicate"]
|
|
440
|
+
if guard.get("kind") == "leaf" and guard.get("name") == "true":
|
|
441
|
+
p = ""
|
|
442
|
+
else:
|
|
443
|
+
p = cxx.boolean(guard)
|
|
444
|
+
|
|
445
|
+
cond = ""
|
|
446
|
+
mut = ""
|
|
447
|
+
|
|
448
|
+
if tr == "WidenVectorMinSize":
|
|
449
|
+
size = str(to["args"][0]["value"])
|
|
450
|
+
cond = "(%s.isFixedVector() && %s.getSizeInBits() < %s)" % (v, v, size)
|
|
451
|
+
mut = ("[](const LegalityQuery &Q) { const LLT VecTy = Q.Types[%s]; "
|
|
452
|
+
"const unsigned NumElts = VecTy.getNumElements(); "
|
|
453
|
+
"const unsigned MinSize = %s / NumElts; "
|
|
454
|
+
"return std::make_pair(unsigned(%s), LLT::fixed_vector(NumElts, "
|
|
455
|
+
"VecTy.getElementType().changeElementSize(MinSize))); }"
|
|
456
|
+
% (idx, size, idx))
|
|
457
|
+
elif tr == "GuardedAction":
|
|
458
|
+
pass
|
|
459
|
+
elif tr == "Scalarize":
|
|
460
|
+
cond = "isVector(%s)(Q)" % idx
|
|
461
|
+
mut = "LegalizeMutations::scalarize(%s)" % idx
|
|
462
|
+
elif tr == "MinScalarOrElt":
|
|
463
|
+
ty = cxx.value(to)
|
|
464
|
+
cond = "scalarOrEltNarrowerThan(%s, (%s).getScalarSizeInBits())(Q)" % (idx, ty)
|
|
465
|
+
mut = "LegalizeMutations::changeElementSizeTo(%s, %s)" % (idx, ty)
|
|
466
|
+
elif tr in ("ScalarPow2", "ScalarOrEltPow2"):
|
|
467
|
+
kids = to.get("args") or []
|
|
468
|
+
minimum = str(kids[0]["value"]) if kids else "0"
|
|
469
|
+
cond = ("sizeNotPow2(%s)(Q)" if tr == "ScalarPow2"
|
|
470
|
+
else "scalarOrEltSizeNotPow2(%s)(Q)") % idx
|
|
471
|
+
mut = "LegalizeMutations::widenScalarOrEltToNextPow2(%s, %s)" % (idx, minimum)
|
|
472
|
+
elif tr == "ScalarMultipleOf":
|
|
473
|
+
size = str(to["args"][0]["value"])
|
|
474
|
+
cond = "(Q.Types[%s].getScalarSizeInBits() %% %s != 0)" % (idx, size)
|
|
475
|
+
mut = "LegalizeMutations::widenScalarOrEltToNextMultipleOf(%s, %s)" % (idx, size)
|
|
476
|
+
elif tr in ("MinScalar", "MaxScalar"):
|
|
477
|
+
ty = cxx.value(to)
|
|
478
|
+
pred = "scalarNarrowerThan" if tr == "MinScalar" else "scalarWiderThan"
|
|
479
|
+
cond = "%s(%s, (%s).getSizeInBits())(Q)" % (pred, idx, ty)
|
|
480
|
+
mut = "LegalizeMutations::changeElementSizeTo(%s, %s)" % (idx, ty)
|
|
481
|
+
elif tr in ("MinScalarOrElt", "MaxScalarOrElt"):
|
|
482
|
+
ty = cxx.value(to)
|
|
483
|
+
pred = ("scalarOrEltNarrowerThan" if tr == "MinScalarOrElt"
|
|
484
|
+
else "scalarOrEltWiderThan")
|
|
485
|
+
cond = "%s(%s, (%s).getScalarSizeInBits())(Q)" % (pred, idx, ty)
|
|
486
|
+
mut = "LegalizeMutations::changeElementSizeTo(%s, %s)" % (idx, ty)
|
|
487
|
+
elif tr in ("MinScalarSameAs", "MaxScalarSameAs"):
|
|
488
|
+
other = str(to["args"][0]["value"])
|
|
489
|
+
op = ">" if tr == "MinScalarSameAs" else "<"
|
|
490
|
+
cond = ("(Q.Types[%s].getScalarSizeInBits() %s Q.Types[%s]"
|
|
491
|
+
".getScalarSizeInBits())" % (other, op, idx))
|
|
492
|
+
mut = "LegalizeMutations::changeElementSizeTo(%s, %s)" % (idx, other)
|
|
493
|
+
elif tr == "MorePow2":
|
|
494
|
+
cond = "numElementsNotPow2(%s)(Q)" % idx
|
|
495
|
+
mut = "LegalizeMutations::moreElementsToNextPow2(%s)" % idx
|
|
496
|
+
elif tr == "FewerToType":
|
|
497
|
+
ty = cxx.value(to)
|
|
498
|
+
cond = "(%s.isVector() && %s.getSizeInBits() > (%s).getSizeInBits())" % (v, v, ty)
|
|
499
|
+
mut = "LegalizeMutations::changeElementTo(%s, %s)" % (idx, ty)
|
|
500
|
+
elif tr == "BitcastToType":
|
|
501
|
+
ty = cxx.value(to)
|
|
502
|
+
mut = "LegalizeMutations::changeElementTo(%s, %s)" % (idx, ty)
|
|
503
|
+
elif tr == "WholeTypeMutation":
|
|
504
|
+
mut = ("[=](const LegalityQuery &Q) { return std::make_pair(unsigned(%s), %s); }"
|
|
505
|
+
% (idx, cxx.value(to["args"][0])))
|
|
506
|
+
elif tr == "WidenPow2OrMinSize":
|
|
507
|
+
minimum = cxx.value(to)
|
|
508
|
+
cond = ("(scalarOrEltNarrowerThan(%s, %s)(Q) || scalarOrEltSizeNotPow2(%s)(Q))"
|
|
509
|
+
% (idx, minimum, idx))
|
|
510
|
+
mut = "LegalizeMutations::widenScalarOrEltToNextPow2(%s, %s)" % (idx, minimum)
|
|
511
|
+
else:
|
|
512
|
+
return None, "no table translation for %s" % tr
|
|
513
|
+
|
|
514
|
+
cond = conjunction(p, cond)
|
|
515
|
+
action = rule["action"]
|
|
516
|
+
out = []
|
|
517
|
+
if not cond:
|
|
518
|
+
# An unconditional action ends the rule set; a mutation declares
|
|
519
|
+
# `auto M`, so it is scoped to keep later `M`s distinct.
|
|
520
|
+
if not mut:
|
|
521
|
+
out += emit_step(action, " ")
|
|
522
|
+
else:
|
|
523
|
+
out.append(" {")
|
|
524
|
+
out += emit_step(action, " ", mut)
|
|
525
|
+
out.append(" }")
|
|
526
|
+
else:
|
|
527
|
+
out.append(" if (%s) {" % cond)
|
|
528
|
+
out += emit_step(action, " ", mut)
|
|
529
|
+
out.append(" }")
|
|
530
|
+
return out, None
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
def emit_prologue(gs):
|
|
534
|
+
"""EmitPrologue(), :7560: every feature, type and type list, maybe_unused."""
|
|
535
|
+
out = []
|
|
536
|
+
for k, name, cond in gs["decls"]:
|
|
537
|
+
if k == "feature":
|
|
538
|
+
out.append(" [[maybe_unused]] const bool %s = %s;" % (name, cond))
|
|
539
|
+
cxx = None
|
|
540
|
+
from .llvm_inc import IncEmitter
|
|
541
|
+
cxx = IncEmitter(gs, qvar="Q")
|
|
542
|
+
for k, name, payload in gs["decls"]:
|
|
543
|
+
if k == "type":
|
|
544
|
+
out.append(" [[maybe_unused]] const LLT %s = %s;" % (name, payload))
|
|
545
|
+
elif k == "select":
|
|
546
|
+
out.append(" [[maybe_unused]] const LLT %s = %s;"
|
|
547
|
+
% (name, cxx._select_text(payload)))
|
|
548
|
+
for k, name, payload in gs["decls"]:
|
|
549
|
+
if k == "type_list":
|
|
550
|
+
out.append(" [[maybe_unused]] const std::initializer_list<LLT> %s = {%s};"
|
|
551
|
+
% (name, ", ".join(payload)))
|
|
552
|
+
out.append("")
|
|
553
|
+
return out
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
EVAL_NOTE = [
|
|
557
|
+
"// One evaluator per tabulated rule set. Each begins with the same prologue",
|
|
558
|
+
"// -gen-legalizer emits: the feature bools and LLT constants the .td rules",
|
|
559
|
+
"// are written in terms of, so the table cannot disagree with the chain",
|
|
560
|
+
"// about what a type or a feature means.",
|
|
561
|
+
]
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
def emit_evaluators(gs, P):
|
|
565
|
+
from .llvm_inc import IncEmitter
|
|
566
|
+
cxx = IncEmitter(gs, qvar="Q")
|
|
567
|
+
prologue = emit_prologue(gs)
|
|
568
|
+
out = list(EVAL_NOTE)
|
|
569
|
+
opaque = []
|
|
570
|
+
for i, rs in enumerate(gs["rulesets"]):
|
|
571
|
+
out.append("")
|
|
572
|
+
body, why = [], None
|
|
573
|
+
for rule in rs["rules"]:
|
|
574
|
+
text, reason = translate_core_rule(rule, cxx)
|
|
575
|
+
if text is None:
|
|
576
|
+
why = reason
|
|
577
|
+
break
|
|
578
|
+
body += text
|
|
579
|
+
opaque.append(why)
|
|
580
|
+
if why is not None:
|
|
581
|
+
out.append("// %s is opaque: %s." % (rs["def"], why))
|
|
582
|
+
out.append("// The reader falls back to the rule chain for this rule set.")
|
|
583
|
+
continue
|
|
584
|
+
out.append("static LegalizeActionStep %sEval%d(" % (P, i))
|
|
585
|
+
out.append(" const %sSubtarget &Subtarget, const LegalityQuery &Q) {" % P)
|
|
586
|
+
out += prologue
|
|
587
|
+
out += body
|
|
588
|
+
# endsUnconditional() is false for every core rule, so the tail is
|
|
589
|
+
# always emitted.
|
|
590
|
+
out.append(" return {LegalizeActions::Unsupported, 0, LLT{}};")
|
|
591
|
+
out.append("}")
|
|
592
|
+
|
|
593
|
+
lower = P[:1].lower() + P[1:]
|
|
594
|
+
out.append("")
|
|
595
|
+
out.append("/// Answer one query from a tabulated rule set. False means the rule set")
|
|
596
|
+
out.append("/// is opaque, and the caller uses the rule chain instead.")
|
|
597
|
+
out.append("static std::optional<LegalizeActionStep> %sEvalTable(unsigned Table, "
|
|
598
|
+
"const %sSubtarget &Subtarget," % (P, P))
|
|
599
|
+
out.append(" const LegalityQuery &Q) {")
|
|
600
|
+
out.append(" switch (Table) {")
|
|
601
|
+
for i, rs in enumerate(gs["rulesets"]):
|
|
602
|
+
out.append(" case %d: // %s" % (i, rs["def"]))
|
|
603
|
+
if opaque[i] is not None:
|
|
604
|
+
out.append(" return std::nullopt;")
|
|
605
|
+
else:
|
|
606
|
+
out.append(" return %sEval%d(Subtarget, Q);" % (P, i))
|
|
607
|
+
out.append(" default:")
|
|
608
|
+
out.append(" return std::nullopt;")
|
|
609
|
+
out.append(" }")
|
|
610
|
+
out.append("}")
|
|
611
|
+
return out
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
def emit_table(gs, P):
|
|
615
|
+
out = emit_head(gs, P)
|
|
616
|
+
out += emit_evaluators(gs, P)
|
|
617
|
+
return "\n".join(out) + "\n"
|