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
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
"""Emit the ``-gen-legalizer`` C++ fragment from the schema-0.4 normal form.
|
|
2
|
+
|
|
3
|
+
This is a from-scratch reimplementation of the parts of
|
|
4
|
+
``llvm/utils/TableGen/LegalizerInfoEmitter.cpp`` (LLVM commit d48f5512a162)
|
|
5
|
+
that turn a rule set into the ``.inc`` the target's LegalizerInfo consumes:
|
|
6
|
+
|
|
7
|
+
emitFeatures :266
|
|
8
|
+
selectText :385
|
|
9
|
+
emitTypes :412
|
|
10
|
+
emitArg / emitArgList :753 / :840
|
|
11
|
+
emitRuleSet :853
|
|
12
|
+
CoreShimTable :2747
|
|
13
|
+
CoreCxxEmitter :2974 (value :2983, boolean :2984)
|
|
14
|
+
emitCoreRule :3689
|
|
15
|
+
|
|
16
|
+
It consumes the same normal form the ``td`` backend consumes, so the two
|
|
17
|
+
backends cannot disagree about what a rule means: they only disagree about
|
|
18
|
+
how it is spelled.
|
|
19
|
+
|
|
20
|
+
Ported logic keeps the LLVM license header and names its source commit.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
from .. import td as T
|
|
26
|
+
|
|
27
|
+
LICENSE_HEADER = """\
|
|
28
|
+
/*===- TableGen'erated file -------------------------------------*- C++ -*-===*\\
|
|
29
|
+
|* *|
|
|
30
|
+
|* GlobalISel legalizer rule fragments *|
|
|
31
|
+
|* *|
|
|
32
|
+
|* Automatically generated file, do not edit! *|
|
|
33
|
+
|* *|
|
|
34
|
+
\\*===----------------------------------------------------------------------===*/
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class Shim:
|
|
39
|
+
"""One row of ``CoreShimTable`` (LegalizerInfoEmitter.cpp:2747)."""
|
|
40
|
+
|
|
41
|
+
__slots__ = ("method", "takes_type_idx", "unguarded", "type_payload",
|
|
42
|
+
"has_payload")
|
|
43
|
+
|
|
44
|
+
def __init__(self, method, payload, takes_type_idx=True, unguarded="",
|
|
45
|
+
type_payload=False):
|
|
46
|
+
self.method = method
|
|
47
|
+
self.takes_type_idx = takes_type_idx
|
|
48
|
+
self.unguarded = unguarded
|
|
49
|
+
self.type_payload = type_payload
|
|
50
|
+
# `payload` is the C++ column of the table: 0 means "the call stops at
|
|
51
|
+
# the type index", 1 means "one more argument follows".
|
|
52
|
+
self.has_payload = bool(payload)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# (operator, observation form, target form) -> how the C++ chain spells it.
|
|
56
|
+
# The observation form is coreObservationForm(): ElemOf is spelled "elem".
|
|
57
|
+
SHIM_TABLE = {
|
|
58
|
+
("widen", "slot", "pow2"): Shim("coreWidenScalarToNextPow2", 0),
|
|
59
|
+
("widen", "slot", "pow2Min"): Shim("coreWidenScalarToNextPow2", 1),
|
|
60
|
+
("widen", "slot", "multipleOf"): Shim("coreWidenScalarToNextMultipleOf", 1),
|
|
61
|
+
("widen", "slot", "ty"): Shim("coreMinScalar", 1),
|
|
62
|
+
("widen", "slot", "sameAs"): Shim("coreMinScalarSameAs", 1),
|
|
63
|
+
("widen", "elem", "pow2"): Shim("coreWidenScalarOrEltToNextPow2", 0),
|
|
64
|
+
("widen", "elem", "pow2Min"): Shim("coreWidenScalarOrEltToNextPow2", 1),
|
|
65
|
+
("widen", "elem", "multipleOf"): Shim("coreWidenScalarOrEltToNextMultipleOf", 1),
|
|
66
|
+
("widen", "elem", "ty"): Shim("coreMinScalarOrElt", 1),
|
|
67
|
+
("widen", "elem", "sameAs"): Shim("coreMinScalarSameAs", 1),
|
|
68
|
+
("widen", "elem", "minVectorSize"): Shim("coreWidenVectorEltsToVectorMinSize", 1),
|
|
69
|
+
("widen", "slot", "select"): Shim("coreWidenScalarOrEltToNextPow2OrMinSize", 1),
|
|
70
|
+
("widen", "slot", "int"): Shim("coreWidenScalarOrEltToNextPow2OrMinSize", 1),
|
|
71
|
+
("narrow", "slot", "ty"): Shim("coreMaxScalar", 1),
|
|
72
|
+
("narrow", "slot", "sameAs"): Shim("coreMaxScalarSameAs", 1),
|
|
73
|
+
("narrow", "elem", "ty"): Shim("coreMaxScalarOrElt", 1),
|
|
74
|
+
("more", "slot", "pow2"): Shim("coreMoreElementsToNextPow2", 0),
|
|
75
|
+
("fewer", "slot", "ty"): Shim("coreFewerElementsToType", 1),
|
|
76
|
+
("bitcast", "slot", "ty"): Shim("coreBitcastTo", 1),
|
|
77
|
+
("widen", "slot", "replace"): Shim("coreWidenTo", 1, type_payload=True),
|
|
78
|
+
("narrow", "slot", "replace"): Shim("coreNarrowTo", 1, type_payload=True),
|
|
79
|
+
("more", "slot", "replace"): Shim("coreMoreTo", 1, type_payload=True),
|
|
80
|
+
("fewer", "slot", "replace"): Shim("coreFewerTo", 1, type_payload=True),
|
|
81
|
+
("bitcast", "slot", "replace"): Shim("coreBitcastToType", 1, type_payload=True),
|
|
82
|
+
("legal", "", ""): Shim("coreLegalIf", 0, takes_type_idx=False,
|
|
83
|
+
unguarded="alwaysLegal"),
|
|
84
|
+
("custom", "", ""): Shim("coreCustomIf", 0, takes_type_idx=False,
|
|
85
|
+
unguarded="custom"),
|
|
86
|
+
("lower", "", ""): Shim("coreLowerIf", 0, takes_type_idx=False,
|
|
87
|
+
unguarded="lower"),
|
|
88
|
+
("unsupported", "", ""): Shim("coreUnsupportedIf", 0, takes_type_idx=False,
|
|
89
|
+
unguarded="unsupported"),
|
|
90
|
+
("libcall", "", ""): Shim("coreLibcallIf", 0, takes_type_idx=False,
|
|
91
|
+
unguarded="libcall"),
|
|
92
|
+
("scalarize", "slot", ""): Shim("coreScalarizeIf", 0, unguarded="scalarize"),
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
# coreObservationForm(): only the forms the corpora use, plus the identity.
|
|
96
|
+
ONSERVATION_FORM = {"elemOf": "elem"}
|
|
97
|
+
|
|
98
|
+
# The three predicates whose C++ is a `LegalityPredicates::` call on the query.
|
|
99
|
+
QUERY_PREDICATES = {"in", "inPairs", "inTriples", "inMemDesc"}
|
|
100
|
+
|
|
101
|
+
KIND_PREDICATE = {
|
|
102
|
+
"kindVector": "isVector",
|
|
103
|
+
"kindScalableVector": "isScalableVector",
|
|
104
|
+
"kindScalar": "isScalar",
|
|
105
|
+
"kindPointer": "isPointer",
|
|
106
|
+
"kindPointerVector": "isPointerVector",
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
ORDERING = {
|
|
110
|
+
"orderingUnordered": "AtomicOrdering::Unordered",
|
|
111
|
+
"orderingMonotonic": "AtomicOrdering::Monotonic",
|
|
112
|
+
"orderingAcquire": "AtomicOrdering::Acquire",
|
|
113
|
+
"orderingRelease": "AtomicOrdering::Release",
|
|
114
|
+
"orderingAcquireRelease": "AtomicOrdering::AcquireRelease",
|
|
115
|
+
"orderingSequentiallyConsistent": "AtomicOrdering::SequentiallyConsistent",
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
CMP_OP = {"eq": "==", "ne": "!=", "lt": "<", "le": "<=", "gt": ">", "ge": ">="}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class IncEmitter:
|
|
122
|
+
def __init__(self, gs, qvar="Query"):
|
|
123
|
+
self.gs = gs
|
|
124
|
+
self.qvar = qvar
|
|
125
|
+
self.names = T.build_names(gs["decls"])
|
|
126
|
+
self.feat_of = {n: p for k, n, p in gs["decls"] if k == "feature"}
|
|
127
|
+
self.preds = {n: p for k, n, p in gs["decls"] if k == "pred"}
|
|
128
|
+
self.used_features = set()
|
|
129
|
+
self.sets = T.collect_named_sets(gs["decls"])
|
|
130
|
+
|
|
131
|
+
# ---- names ----------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
def _type(self, name):
|
|
134
|
+
if name in self.names.type:
|
|
135
|
+
return self.names.type[name]
|
|
136
|
+
if name in self.names.records:
|
|
137
|
+
return name
|
|
138
|
+
raise KeyError(f"unknown type name {name!r}")
|
|
139
|
+
|
|
140
|
+
def _type_value(self, v):
|
|
141
|
+
if isinstance(v, str):
|
|
142
|
+
return self._type(v)
|
|
143
|
+
name = self.names.select_value(v)
|
|
144
|
+
if name is None:
|
|
145
|
+
raise KeyError(f"no named select for {v!r}")
|
|
146
|
+
return name
|
|
147
|
+
|
|
148
|
+
def _feature(self, expr):
|
|
149
|
+
name = self.names.feature.get(expr)
|
|
150
|
+
if name is None:
|
|
151
|
+
raise KeyError(f"undeclared feature expression {expr!r}")
|
|
152
|
+
self.used_features.add(name)
|
|
153
|
+
return name
|
|
154
|
+
|
|
155
|
+
# ---- C++ values (CoreCxxEmitter::value, :2834) -----------------------
|
|
156
|
+
|
|
157
|
+
def value(self, n):
|
|
158
|
+
k = n.get("kind")
|
|
159
|
+
if k == "int":
|
|
160
|
+
return str(n["value"])
|
|
161
|
+
if k == "type":
|
|
162
|
+
return self._type_value(n["value"])
|
|
163
|
+
if k == "slot":
|
|
164
|
+
return "%s.Types[%d]" % (self.qvar, n["index"])
|
|
165
|
+
if k == "memSlot":
|
|
166
|
+
return "%s.MMODescrs[%d]" % (self.qvar, n["args"][0]["value"])
|
|
167
|
+
if k == "sameAs":
|
|
168
|
+
return "%s.Types[%d]" % (self.qvar, n["args"][0]["value"])
|
|
169
|
+
if k == "ty":
|
|
170
|
+
return self.value(n["args"][0])
|
|
171
|
+
if k == "replace":
|
|
172
|
+
return self.value(n["args"][0])
|
|
173
|
+
if k == "select":
|
|
174
|
+
a = n["args"]
|
|
175
|
+
return "(%s ? %s : %s)" % (self.boolean(a[0]), self.value(a[1]),
|
|
176
|
+
self.value(a[2]))
|
|
177
|
+
if k in ("elemOf", "scalarOf", "numElems", "bitsOf", "sizeInBytesOf"):
|
|
178
|
+
method = {"elemOf": "getElementType", "scalarOf": "getScalarType",
|
|
179
|
+
"numElems": "getNumElements", "bitsOf": "getScalarSizeInBits",
|
|
180
|
+
"sizeInBytesOf": "getSizeInBytes"}[k]
|
|
181
|
+
return "(%s).%s()" % (self.value(n["args"][0]), method)
|
|
182
|
+
if k == "isByteSized":
|
|
183
|
+
return "(%s).isByteSized()" % self.value(n["args"][0])
|
|
184
|
+
if k == "isBFloat16":
|
|
185
|
+
return "(%s).isBFloat16()" % self.value(n["args"][0])
|
|
186
|
+
if k == "isFloat16":
|
|
187
|
+
return "(%s).isFloat16()" % self.value(n["args"][0])
|
|
188
|
+
if k == "isPow2":
|
|
189
|
+
return "llvm::isPowerOf2_32(%s)" % self.value(n["args"][0])
|
|
190
|
+
if k == "sizeOf":
|
|
191
|
+
inner = n["args"][0]
|
|
192
|
+
if inner.get("kind") == "memSlot":
|
|
193
|
+
# MemDesc::AlignInBits is an alignment, not a size.
|
|
194
|
+
return "(%s).MemoryTy.getSizeInBits()" % self.value(inner)
|
|
195
|
+
return "(%s).getSizeInBits()" % self.value(inner)
|
|
196
|
+
if k == "alignOf":
|
|
197
|
+
return "(%s).AlignInBits" % self.value(n["args"][0])
|
|
198
|
+
if k == "addrSpace":
|
|
199
|
+
return "(%s).getAddressSpace()" % self.value(n["args"][0])
|
|
200
|
+
if k == "memTy":
|
|
201
|
+
return "(%s).MemoryTy" % self.value(n["args"][0])
|
|
202
|
+
if k == "memOrdering":
|
|
203
|
+
return "(%s).Ordering" % self.value(n["args"][0])
|
|
204
|
+
if k == "memFailureOrdering":
|
|
205
|
+
return "(%s).FailureOrdering" % self.value(n["args"][0])
|
|
206
|
+
if k == "pow2Ceil":
|
|
207
|
+
return "llvm::PowerOf2Ceil(%s)" % self.value(n["args"][0])
|
|
208
|
+
if k == "mul":
|
|
209
|
+
return "(%s * %s)" % tuple(self.value(a) for a in n["args"])
|
|
210
|
+
if k == "urem":
|
|
211
|
+
return "(%s %% %s)" % tuple(self.value(a) for a in n["args"])
|
|
212
|
+
if k == "udiv":
|
|
213
|
+
return "(%s / %s)" % tuple(self.value(a) for a in n["args"])
|
|
214
|
+
if k == "intOfSize":
|
|
215
|
+
return "LLT::integer(%s)" % self.value(n["args"][0])
|
|
216
|
+
if k == "vecOf":
|
|
217
|
+
return "LLT::fixed_vector(%s, %s)" % tuple(
|
|
218
|
+
self.value(a) for a in n["args"])
|
|
219
|
+
if k == "scalarOrVecOf":
|
|
220
|
+
return "LLT::scalarOrVector(ElementCount::getFixed(%s), %s)" % tuple(
|
|
221
|
+
self.value(a) for a in n["args"])
|
|
222
|
+
if k == "eltTypeTo":
|
|
223
|
+
return "(%s).changeElementType(%s)" % tuple(
|
|
224
|
+
self.value(a) for a in n["args"])
|
|
225
|
+
if k == "eltSizeTo":
|
|
226
|
+
return "(%s).changeElementSize(%s)" % tuple(
|
|
227
|
+
self.value(a) for a in n["args"])
|
|
228
|
+
if k == "divLanes":
|
|
229
|
+
ty = self.value(n["args"][0])
|
|
230
|
+
return ("(%s).changeElementCount((%s).getElementCount()"
|
|
231
|
+
".divideCoefficientBy(%s))"
|
|
232
|
+
% (ty, ty, self.value(n["args"][1])))
|
|
233
|
+
raise ValueError(f"no C++ value for node {n!r}")
|
|
234
|
+
|
|
235
|
+
# ---- C++ booleans (CoreCxxEmitter::boolean, :2921) -------------------
|
|
236
|
+
|
|
237
|
+
def boolean(self, n):
|
|
238
|
+
k = n.get("kind")
|
|
239
|
+
if k == "leaf":
|
|
240
|
+
if n["name"] == "true":
|
|
241
|
+
return "true"
|
|
242
|
+
if n["name"] == "hasFeature":
|
|
243
|
+
# A guard that names a LegalizeFeature record emits the record
|
|
244
|
+
# name bare; emitCoreRule's junction adds the parentheses.
|
|
245
|
+
return self._feature(n["args"][0])
|
|
246
|
+
raise ValueError(f"unknown leaf predicate {n['name']!r}")
|
|
247
|
+
if k in ("all", "any"):
|
|
248
|
+
sep = " && " if k == "all" else " || "
|
|
249
|
+
return sep.join("(%s)" % self.boolean(a) for a in n["args"])
|
|
250
|
+
if k == "not":
|
|
251
|
+
return "!(%s)" % self.boolean(n["args"][0])
|
|
252
|
+
if k in QUERY_PREDICATES:
|
|
253
|
+
return self._membership(n)
|
|
254
|
+
if k in CMP_OP:
|
|
255
|
+
return self._compare(n)
|
|
256
|
+
if k in ("isPow2", "isByteSized", "isBFloat16", "isFloat16"):
|
|
257
|
+
return self.value(n)
|
|
258
|
+
raise ValueError(f"no C++ boolean for node {n!r}")
|
|
259
|
+
|
|
260
|
+
def _set_entries(self, n):
|
|
261
|
+
"""Normal-form set literal -> list of [Type0, Type1, MemTy, Align]."""
|
|
262
|
+
if n.get("kind") == "type":
|
|
263
|
+
# A named set, or a one-member set spelled as the type itself
|
|
264
|
+
# (coreSetJson, :2820).
|
|
265
|
+
if n["value"] in self.sets:
|
|
266
|
+
return [[m] for m in self.sets[n["value"]]]
|
|
267
|
+
return [[self._type_value(n["value"])]]
|
|
268
|
+
elems = n["elems"]
|
|
269
|
+
arity = n.get("arity", 1)
|
|
270
|
+
if arity == 1:
|
|
271
|
+
return [[self._type_value(e)] for e in elems]
|
|
272
|
+
return elems
|
|
273
|
+
|
|
274
|
+
def _membership(self, n):
|
|
275
|
+
kind = n["kind"]
|
|
276
|
+
args = n["args"]
|
|
277
|
+
if kind == "inMemDesc":
|
|
278
|
+
slots = [a["args"][0]["value"] if a.get("kind") == "memSlot"
|
|
279
|
+
else a["index"] for a in args[:3]]
|
|
280
|
+
entries = self._set_entries(args[3])
|
|
281
|
+
rows = ", ".join("{%s, %s, %s, %d}" % (
|
|
282
|
+
self._type_value(e[0]), self._type_value(e[1]),
|
|
283
|
+
self._type_value(e[2]), e[3]) for e in entries)
|
|
284
|
+
return ("LegalityPredicates::typePairAndMemDescInSet(%d, %d, %d, {%s})"
|
|
285
|
+
"(%s)" % (slots[0], slots[1], slots[2], rows, self.qvar))
|
|
286
|
+
|
|
287
|
+
nslots = len(args) - 1
|
|
288
|
+
rhs, lhs = args[-1], args[0]
|
|
289
|
+
if nslots > 1:
|
|
290
|
+
idx = ", ".join(str(a["index"]) for a in args[:nslots])
|
|
291
|
+
entries = args[-1]["elems"]
|
|
292
|
+
rows = ", ".join("{%s}" % ", ".join(self._type_value(x) for x in e)
|
|
293
|
+
for e in entries)
|
|
294
|
+
fn = "typeTupleInSet" if nslots == 3 else "typePairInSet"
|
|
295
|
+
return "LegalityPredicates::%s(%s, {%s})(%s)" % (fn, idx, rows, self.qvar)
|
|
296
|
+
if rhs.get("kind") == "clamp":
|
|
297
|
+
v = self.value(lhs)
|
|
298
|
+
return "(%s >= %d && %s <= %d)" % (
|
|
299
|
+
v, rhs["args"][0]["value"], v, rhs["args"][1]["value"])
|
|
300
|
+
if rhs.get("kind") == "set" and rhs.get("of") == "Kind":
|
|
301
|
+
v = self.value(lhs["args"][0])
|
|
302
|
+
return "(" + " || ".join(
|
|
303
|
+
"%s.%s()" % (v, KIND_PREDICATE[e]) for e in rhs["elems"]) + ")"
|
|
304
|
+
v = self.value(lhs)
|
|
305
|
+
return "(" + " || ".join(
|
|
306
|
+
"%s == %s" % (v, self._type_value(e[0]))
|
|
307
|
+
for e in self._set_entries(rhs)) + ")"
|
|
308
|
+
|
|
309
|
+
def _compare(self, n):
|
|
310
|
+
lhs, rhs = n["args"]
|
|
311
|
+
op = CMP_OP[n["kind"]]
|
|
312
|
+
if lhs.get("kind") == "sortOf":
|
|
313
|
+
v = self.value(lhs["args"][0])
|
|
314
|
+
pred = KIND_PREDICATE[self._tag(rhs)]
|
|
315
|
+
if op == "!=":
|
|
316
|
+
return "!(%s.%s())" % (v, pred)
|
|
317
|
+
return "%s.%s()" % (v, pred)
|
|
318
|
+
if lhs.get("kind") in ("memOrdering", "memFailureOrdering"):
|
|
319
|
+
v = self.value(lhs)
|
|
320
|
+
o = ORDERING[self._tag(rhs)]
|
|
321
|
+
if op == "==":
|
|
322
|
+
return "(%s == %s)" % (v, o)
|
|
323
|
+
if op == "!=":
|
|
324
|
+
return "(%s != %s)" % (v, o)
|
|
325
|
+
if op == ">=":
|
|
326
|
+
return "isAtLeastOrStrongerThan(%s, %s)" % (v, o)
|
|
327
|
+
if op == ">":
|
|
328
|
+
return "isStrongerThan(%s, %s)" % (v, o)
|
|
329
|
+
if op == "<=":
|
|
330
|
+
return "(!isStrongerThan(%s, %s))" % (v, o)
|
|
331
|
+
return "(!isAtLeastOrStrongerThan(%s, %s))" % (v, o)
|
|
332
|
+
return "(%s %s %s)" % (self.value(lhs), op, self.value(rhs))
|
|
333
|
+
|
|
334
|
+
@staticmethod
|
|
335
|
+
def _tag(n):
|
|
336
|
+
"""A bare tag (`KindVector`) and `(KindVector)` carry the same name."""
|
|
337
|
+
k = n.get("kind", "")
|
|
338
|
+
if k in KIND_PREDICATE or k in ORDERING:
|
|
339
|
+
return k
|
|
340
|
+
return n.get("name", "")
|
|
341
|
+
|
|
342
|
+
# ---- prologue --------------------------------------------------------
|
|
343
|
+
|
|
344
|
+
def _select_text(self, payload):
|
|
345
|
+
conds, types, otherwise = payload
|
|
346
|
+
expr = otherwise
|
|
347
|
+
for i in range(len(conds) - 1, -1, -1):
|
|
348
|
+
expr = "(%s ? %s : %s)" % (self._pred_cxx(conds[i]), types[i], expr)
|
|
349
|
+
return expr
|
|
350
|
+
|
|
351
|
+
def _pred_cxx(self, name):
|
|
352
|
+
"""A select guard: a feature record name or a predicate-dag expression."""
|
|
353
|
+
if name in self.feat_of:
|
|
354
|
+
return self._feature(self.feat_of[name])
|
|
355
|
+
if name in self.preds:
|
|
356
|
+
return self._bool_dag_cxx(T._bool_node(T.parse_bool(self.preds[name]),
|
|
357
|
+
self.feat_of))
|
|
358
|
+
raise KeyError(f"unknown select guard {name!r}")
|
|
359
|
+
|
|
360
|
+
def _bool_dag_cxx(self, node, paren=False):
|
|
361
|
+
"""Mirror emitPredicateDag(ParenIfBinOp=false)."""
|
|
362
|
+
k = node["kind"]
|
|
363
|
+
if k == "leaf":
|
|
364
|
+
return self._feature(node["args"][0])
|
|
365
|
+
if k == "not":
|
|
366
|
+
inner = node["arg"] if "arg" in node else node["args"][0]
|
|
367
|
+
return "!(%s)" % self._bool_dag_cxx(inner)
|
|
368
|
+
if k in ("all", "any", "nary"):
|
|
369
|
+
op = node.get("op", "all_of" if k == "all" else "any_of")
|
|
370
|
+
sep = " && " if op == "all_of" else " || "
|
|
371
|
+
kids = node["args"]
|
|
372
|
+
out = sep.join(self._bool_dag_cxx(a, len(kids) > 1) for a in kids)
|
|
373
|
+
return "(" + out + ")" if paren and len(kids) > 1 else out
|
|
374
|
+
raise ValueError(f"unsupported predicate node {node!r}")
|
|
375
|
+
|
|
376
|
+
def _ruleset(self, rs):
|
|
377
|
+
out = []
|
|
378
|
+
for c in rs["comments"]:
|
|
379
|
+
out.append(" // " + c)
|
|
380
|
+
ops = rs["opcodes"]
|
|
381
|
+
if len(ops) == 1:
|
|
382
|
+
out.append(" getActionDefinitionsBuilder(%s)" % ops[0])
|
|
383
|
+
else:
|
|
384
|
+
out.append(" getActionDefinitionsBuilder({%s})" % ", ".join(ops))
|
|
385
|
+
rules = [self.rule(r) for r in rs["rules"]]
|
|
386
|
+
rules += [" .immIdx(%d)" % i for i in rs.get("legacy", [])]
|
|
387
|
+
if not rules:
|
|
388
|
+
raise ValueError("rule set %r has no rules" % rs["def"])
|
|
389
|
+
for i, r in enumerate(rules):
|
|
390
|
+
out.append(r + (";" if i + 1 == len(rules) else ""))
|
|
391
|
+
return out
|
|
392
|
+
|
|
393
|
+
# ---- one rule (emitCoreRule, :3689) ----------------------------------
|
|
394
|
+
|
|
395
|
+
def rule(self, r):
|
|
396
|
+
on = r.get("on")
|
|
397
|
+
to = r.get("to")
|
|
398
|
+
on_form = ONSERVATION_FORM.get(on["kind"], on["kind"]) if on else ""
|
|
399
|
+
to_form = to["kind"] if to else ""
|
|
400
|
+
shim = SHIM_TABLE.get((r["op"], on_form, to_form))
|
|
401
|
+
if shim is None:
|
|
402
|
+
raise ValueError(
|
|
403
|
+
"no C++ shim for operator '%s' over '%s' to '%s'"
|
|
404
|
+
% (r["op"], on_form, to_form))
|
|
405
|
+
|
|
406
|
+
guard = r["predicate"]
|
|
407
|
+
unguarded = guard.get("kind") == "leaf" and guard.get("name") == "true"
|
|
408
|
+
if unguarded and shim.unguarded:
|
|
409
|
+
return " .%s(%s)" % (
|
|
410
|
+
shim.unguarded, r["type_idx"] if shim.takes_type_idx else "")
|
|
411
|
+
|
|
412
|
+
args = []
|
|
413
|
+
if unguarded:
|
|
414
|
+
args.append("[](const LegalityQuery &) { return true; }")
|
|
415
|
+
else:
|
|
416
|
+
args.append("[=](const LegalityQuery &Query) { return %s; }"
|
|
417
|
+
% self.boolean(guard))
|
|
418
|
+
if shim.takes_type_idx:
|
|
419
|
+
args.append(str(r["type_idx"]))
|
|
420
|
+
if shim.has_payload:
|
|
421
|
+
args.append(self._payload(r, shim))
|
|
422
|
+
return " .%s(%s)" % (shim.method, ", ".join(args))
|
|
423
|
+
|
|
424
|
+
def _payload(self, r, shim):
|
|
425
|
+
to = r["to"]
|
|
426
|
+
if shim.type_payload:
|
|
427
|
+
return ("[=](const LegalityQuery &Query) { return std::make_pair(%d, %s); }"
|
|
428
|
+
% (r["type_idx"], self.value(to["args"][0])))
|
|
429
|
+
if to.get("kind") == "int":
|
|
430
|
+
return str(to["value"])
|
|
431
|
+
if to.get("kind") == "ty":
|
|
432
|
+
inner = to["args"][0]
|
|
433
|
+
if inner.get("kind") != "type":
|
|
434
|
+
raise ValueError("a Ty target must name a type record")
|
|
435
|
+
return self._type_value(inner["value"])
|
|
436
|
+
if to.get("kind") == "select":
|
|
437
|
+
return self.value(to)
|
|
438
|
+
return str(to["args"][0]["value"])
|
|
439
|
+
|
|
440
|
+
# ---- whole file ------------------------------------------------------
|
|
441
|
+
|
|
442
|
+
def emit(self):
|
|
443
|
+
body = []
|
|
444
|
+
for rs in self.gs["rulesets"]:
|
|
445
|
+
body += self._ruleset(rs)
|
|
446
|
+
|
|
447
|
+
types = []
|
|
448
|
+
for kind, name, payload in self.gs["decls"]:
|
|
449
|
+
if kind == "type":
|
|
450
|
+
types.append(" const LLT %s = %s;" % (name, payload))
|
|
451
|
+
elif kind == "select":
|
|
452
|
+
types.append(" const LLT %s = %s;" % (name, self._select_text(payload)))
|
|
453
|
+
lists = []
|
|
454
|
+
for kind, name, payload in self.gs["decls"]:
|
|
455
|
+
if kind == "type_list":
|
|
456
|
+
lists.append(" const std::initializer_list<LLT> %s = {%s};"
|
|
457
|
+
% (name, ", ".join(payload)))
|
|
458
|
+
|
|
459
|
+
features = [" bool %s = %s;" % (n, p) for k, n, p in self.gs["decls"]
|
|
460
|
+
if k == "feature" and n in self.used_features]
|
|
461
|
+
|
|
462
|
+
out = [LICENSE_HEADER.rstrip("\n"), ""]
|
|
463
|
+
if features:
|
|
464
|
+
out += features + [""]
|
|
465
|
+
if types:
|
|
466
|
+
out += types + [""]
|
|
467
|
+
if lists:
|
|
468
|
+
out += lists + [""]
|
|
469
|
+
out += body
|
|
470
|
+
return "\n".join(out) + "\n"
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def emit_inc(gs, source_name):
|
|
474
|
+
return IncEmitter(gs).emit()
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
def main(argv):
|
|
478
|
+
import argparse
|
|
479
|
+
import sys
|
|
480
|
+
|
|
481
|
+
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
482
|
+
ap.add_argument("gisel")
|
|
483
|
+
ap.add_argument("--out", required=True)
|
|
484
|
+
args = ap.parse_args(argv)
|
|
485
|
+
gs = T.parse_gisel(Path(args.gisel).read_text())
|
|
486
|
+
text = emit_inc(gs, args.gisel)
|
|
487
|
+
Path(args.out).write_text(text)
|
|
488
|
+
print(f"{args.out}: {len(text.splitlines())} lines")
|
|
489
|
+
return 0
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
if __name__ == "__main__":
|
|
493
|
+
import sys
|
|
494
|
+
|
|
495
|
+
sys.exit(main(sys.argv[1:]))
|