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/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"