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/__init__.py
ADDED
gisel/__main__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Emit the ``-gen-legalizer-check`` JSON from the schema-0.4 normal form.
|
|
2
|
+
|
|
3
|
+
Mirrors ``LegalizerCheckEmitter::run`` (LegalizerInfoEmitter.cpp:8004) and the
|
|
4
|
+
counters it prints from ``verifyLoweringRegistry`` (:4568).
|
|
5
|
+
|
|
6
|
+
Two kinds of number appear in that JSON, and they must not be confused:
|
|
7
|
+
|
|
8
|
+
* per-target counts (``rule_sets``, ``rules``, ``core_rules``, ``coverage``)
|
|
9
|
+
are derived from the corpus. ``Rules`` counts every entry in a rule set's
|
|
10
|
+
``Rules`` list, including ``ImmIdx``; ``Coverage`` counts the ``immIdx``
|
|
11
|
+
markers, so ``rules == core_rules + legacy_rules + coverage``.
|
|
12
|
+
* vocabulary counts (``builders``, ``overloads``, ``entries``) describe the
|
|
13
|
+
TableGen compatibility layer itself -- 50 ``LegalizeBuilder`` records and 64
|
|
14
|
+
``LegalizeLowering`` entries, the same for every target. They are carried
|
|
15
|
+
as provenance-stamped constants in ``gisel/vocab.py`` because they are not a
|
|
16
|
+
property of the DSL; a target cannot change them.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from .. import td as T
|
|
20
|
+
from ..vocab import BUILDER_VOCABULARY, CORE_OPERATORS
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def counts(gs):
|
|
24
|
+
"""Per-target counters, in the shape ``LoweringStats`` uses."""
|
|
25
|
+
rule_sets = len(gs["rulesets"])
|
|
26
|
+
core = sum(len(rs["rules"]) for rs in gs["rulesets"])
|
|
27
|
+
imm = sum(len(rs.get("legacy", [])) for rs in gs["rulesets"])
|
|
28
|
+
return {
|
|
29
|
+
"rule_sets": rule_sets,
|
|
30
|
+
"rules": core + imm,
|
|
31
|
+
"core_rules": core,
|
|
32
|
+
"legacy_rules": 0,
|
|
33
|
+
"coverage": imm,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def emit_check(gs):
|
|
38
|
+
c = counts(gs)
|
|
39
|
+
v = BUILDER_VOCABULARY
|
|
40
|
+
out = [
|
|
41
|
+
"{",
|
|
42
|
+
' "builders": %d,' % v["builders"],
|
|
43
|
+
' "overloads": %d,' % v["overloads"],
|
|
44
|
+
' "entries": %d,' % v["entries"],
|
|
45
|
+
' "rule_sets": %d,' % c["rule_sets"],
|
|
46
|
+
' "rules": %d,' % c["rules"],
|
|
47
|
+
' "escapes": 0,',
|
|
48
|
+
' "entries_without_table_translation": 0,',
|
|
49
|
+
' "rule_sets_without_table_translation": 0,',
|
|
50
|
+
' "core_rules": %d,' % c["core_rules"],
|
|
51
|
+
' "legacy_rules": %d,' % c["legacy_rules"],
|
|
52
|
+
' "coverage": %d,' % c["coverage"],
|
|
53
|
+
' "core_operators": [' +
|
|
54
|
+
", ".join('"%s"' % op for op in CORE_OPERATORS) + "]",
|
|
55
|
+
"}",
|
|
56
|
+
]
|
|
57
|
+
return "\n".join(out) + "\n"
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"""Emit the ``-gen-legalizer-core`` JSON from the schema-0.4 normal form.
|
|
2
|
+
|
|
3
|
+
Mirrors ``LegalizerInfoEmitter::runCore`` (LegalizerInfoEmitter.cpp:4816),
|
|
4
|
+
``coreTypeValue`` (:1361) and ``coreSetJson`` (:2820).
|
|
5
|
+
|
|
6
|
+
The rule body is already the normal form; three things are re-spelled on the
|
|
7
|
+
way out:
|
|
8
|
+
|
|
9
|
+
* a type is named by its LLT, not by its record (``X86_s8`` -> ``s8``), and a
|
|
10
|
+
pointer whose width the configuration decides is written as a wildcard
|
|
11
|
+
(``p0:*``) inside a set but with its width (``p0:64``) in the domain;
|
|
12
|
+
* a select type becomes a nested ``{"select": {...}}`` value, because the
|
|
13
|
+
branch is a property of the subtarget, not of the document;
|
|
14
|
+
* the domain is the set of normalised named types with the wildcards dropped,
|
|
15
|
+
plus ``p0:<width>``, sorted and deduplicated (:4856).
|
|
16
|
+
|
|
17
|
+
``origin`` points at the ``.gisel`` source, not at the generated ``.td``, so
|
|
18
|
+
the gate compares documents after dropping it (plan AC5).
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import json
|
|
22
|
+
import re
|
|
23
|
+
|
|
24
|
+
from .. import td as T
|
|
25
|
+
|
|
26
|
+
SCHEMA = "legalizer-spec-core"
|
|
27
|
+
VERSION = "0.4"
|
|
28
|
+
POINTER_WIDTH = 64
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
_ORIGIN_RE = re.compile(r'"origin": \{[^{}]*\}')
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def strip_origin(text):
|
|
35
|
+
"""Drop the per-rule ``origin`` values, keeping the key.
|
|
36
|
+
|
|
37
|
+
``origin`` names the source file and line; ours point at ``.gisel`` and the
|
|
38
|
+
baseline at the generated ``.td``, so it is provenance, not semantics
|
|
39
|
+
(plan AC5). Both the golden test and ``gisel check --emit=core`` compare
|
|
40
|
+
documents with the values erased.
|
|
41
|
+
"""
|
|
42
|
+
return _ORIGIN_RE.sub('"origin": {}', text)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _compact(obj):
|
|
46
|
+
return json.dumps(obj, separators=(",", ":"), ensure_ascii=False)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _string(s):
|
|
50
|
+
return json.dumps(s, ensure_ascii=False)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class CoreJson:
|
|
54
|
+
def __init__(self, gs):
|
|
55
|
+
self.gs = gs
|
|
56
|
+
self.exprs = {n: p for k, n, p in gs["decls"] if k == "type"}
|
|
57
|
+
self.selects = {n: p for k, n, p in gs["decls"] if k == "select"}
|
|
58
|
+
self.sets = T.collect_named_sets(gs["decls"])
|
|
59
|
+
|
|
60
|
+
# ---- types -----------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
def type_name(self, name):
|
|
63
|
+
"""A record name -> its canonical LLT spelling (``s8``, ``p0:*``)."""
|
|
64
|
+
expr = self.exprs.get(name)
|
|
65
|
+
if expr is None:
|
|
66
|
+
raise KeyError("not a named type: %r" % name)
|
|
67
|
+
norm = T.normalize_llt(expr, self.exprs)
|
|
68
|
+
if not norm:
|
|
69
|
+
raise ValueError("cannot normalise type %r" % name)
|
|
70
|
+
return norm
|
|
71
|
+
|
|
72
|
+
def type_value(self, name):
|
|
73
|
+
"""A value in a rule: a string, or a nested select object."""
|
|
74
|
+
if name in self.selects:
|
|
75
|
+
return self.select_json(name)
|
|
76
|
+
return self.type_name(name)
|
|
77
|
+
|
|
78
|
+
def select_json(self, name):
|
|
79
|
+
conds, types, otherwise = self.selects[name]
|
|
80
|
+
value = self.type_value(otherwise)
|
|
81
|
+
for i in range(len(conds) - 1, -1, -1):
|
|
82
|
+
cond = self.pred_name(conds[i])
|
|
83
|
+
value = {"select": {"cond": cond, "then": self.type_value(types[i]),
|
|
84
|
+
"else": value}}
|
|
85
|
+
return value
|
|
86
|
+
|
|
87
|
+
def pred_name(self, name):
|
|
88
|
+
"""A select guard: a feature leaf, or an inline predicate dag."""
|
|
89
|
+
feats = {n: p for k, n, p in self.gs["decls"] if k == "feature"}
|
|
90
|
+
if name in feats:
|
|
91
|
+
return {"kind": "leaf", "name": "hasFeature", "args": [feats[name]]}
|
|
92
|
+
preds = {n: p for k, n, p in self.gs["decls"] if k == "pred"}
|
|
93
|
+
if name in preds:
|
|
94
|
+
return T._bool_node(T.parse_bool(preds[name]), feats)
|
|
95
|
+
raise KeyError("unknown select guard %r" % name)
|
|
96
|
+
|
|
97
|
+
# ---- nodes -----------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
def node(self, n):
|
|
100
|
+
if isinstance(n, list):
|
|
101
|
+
return [self.node(v) for v in n]
|
|
102
|
+
if not isinstance(n, dict):
|
|
103
|
+
return n
|
|
104
|
+
out = {}
|
|
105
|
+
for k, v in n.items():
|
|
106
|
+
if k == "value" and n.get("kind") == "type" and isinstance(v, str) \
|
|
107
|
+
and v in self.sets:
|
|
108
|
+
# A named set stays one object, expanded: one spelling, one
|
|
109
|
+
# normal form.
|
|
110
|
+
return {"kind": "set", "of": "Type",
|
|
111
|
+
"elems": [self.type_value(m) for m in self.sets[v]]}
|
|
112
|
+
if k == "value" and n.get("kind") == "type":
|
|
113
|
+
out[k] = self.type_value(v) if isinstance(v, str) else self.node(v)
|
|
114
|
+
elif k == "elems" and n.get("kind") == "set":
|
|
115
|
+
out[k] = [self.type_value(row) if isinstance(row, str)
|
|
116
|
+
else [self.type_value(x) if isinstance(x, str) else x
|
|
117
|
+
for x in row]
|
|
118
|
+
for row in v]
|
|
119
|
+
else:
|
|
120
|
+
out[k] = self.node(v)
|
|
121
|
+
return out
|
|
122
|
+
|
|
123
|
+
# ---- document --------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
def domain(self):
|
|
126
|
+
types = []
|
|
127
|
+
for k, name, expr in self.gs["decls"]:
|
|
128
|
+
if k != "type":
|
|
129
|
+
continue
|
|
130
|
+
norm = T.normalize_llt(expr, self.exprs)
|
|
131
|
+
if norm and ":*" not in norm:
|
|
132
|
+
types.append(norm)
|
|
133
|
+
types.append("p0:%d" % POINTER_WIDTH)
|
|
134
|
+
return sorted(set(types))
|
|
135
|
+
|
|
136
|
+
def rule(self, rule, ruleset, index, origin):
|
|
137
|
+
parts = ['"action":%s' % _string(rule["action"]),
|
|
138
|
+
'"type_idx":%d' % rule["type_idx"],
|
|
139
|
+
'"predicate":%s' % _compact(self.node(rule["predicate"])),
|
|
140
|
+
'"schema": "0.4"',
|
|
141
|
+
'"op": %s' % _string(rule["op"])]
|
|
142
|
+
if rule.get("on") is not None:
|
|
143
|
+
parts.append('"on": %s' % _compact(self.node(rule["on"])))
|
|
144
|
+
if rule.get("to") is not None:
|
|
145
|
+
parts.append('"to": %s' % _compact(self.node(rule["to"])))
|
|
146
|
+
parts += ['"ruleset": %s' % _string(ruleset),
|
|
147
|
+
'"rule_index": %d' % index,
|
|
148
|
+
'"origin": %s' % _compact(origin)]
|
|
149
|
+
return "{" + ", ".join(parts) + "}"
|
|
150
|
+
|
|
151
|
+
def emit(self, source_name, lines=None):
|
|
152
|
+
lines = lines or {}
|
|
153
|
+
out = ["{",
|
|
154
|
+
' "schema": %s,' % _string(SCHEMA),
|
|
155
|
+
' "version": %s,' % _string(VERSION),
|
|
156
|
+
' "config": {"triple": "unspecified", "cpu": "unspecified", '
|
|
157
|
+
'"features": [], "pointer_width": %d},' % POINTER_WIDTH,
|
|
158
|
+
' "domain": {"types": [%s], "imms": [], "mems": [], '
|
|
159
|
+
'"orderings": [], "q0": []},'
|
|
160
|
+
% ", ".join(_string(t) for t in self.domain()),
|
|
161
|
+
' "rulesets": [']
|
|
162
|
+
for si, rs in enumerate(self.gs["rulesets"]):
|
|
163
|
+
origin = {"source": source_name,
|
|
164
|
+
"line": lines.get(rs["def"], 0)}
|
|
165
|
+
out.append(' {"def": %s, "origin": %s,'
|
|
166
|
+
% (_string(rs["def"]), _compact(origin)))
|
|
167
|
+
out.append(' "opcodes": [%s],'
|
|
168
|
+
% ", ".join(_string(o) for o in rs["opcodes"]))
|
|
169
|
+
out.append(' "rules": [')
|
|
170
|
+
for ri, rule in enumerate(rs["rules"]):
|
|
171
|
+
text = self.rule(rule, rs["def"], ri, origin)
|
|
172
|
+
out.append(" " + text + ("," if ri + 1 < len(rs["rules"]) else ""))
|
|
173
|
+
out.append(" ]}" + ("," if si + 1 < len(self.gs["rulesets"]) else ""))
|
|
174
|
+
out += [" ],", ' "escapes": []', "}"]
|
|
175
|
+
return "\n".join(out) + "\n"
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def stage_lines(text):
|
|
179
|
+
"""`ruleset Name:` -> line number, for origin. Cheap and side-effect free."""
|
|
180
|
+
out = {}
|
|
181
|
+
for i, line in enumerate(text.splitlines(), 1):
|
|
182
|
+
s = line.strip()
|
|
183
|
+
if s.startswith("ruleset "):
|
|
184
|
+
rest = s[len("ruleset "):]
|
|
185
|
+
name = rest.split(":", 1)[0].strip()
|
|
186
|
+
out.setdefault(name, i)
|
|
187
|
+
return out
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def emit_core(gs, source_name, source_text=None):
|
|
191
|
+
lines = stage_lines(source_text) if source_text else {}
|
|
192
|
+
return CoreJson(gs).emit(source_name, lines)
|