Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Tools/build/generate_opcode_h.py
12 views
1
# This script generates the opcode.h header file.
2
3
import sys
4
import tokenize
5
6
SCRIPT_NAME = "Tools/build/generate_opcode_h.py"
7
PYTHON_OPCODE = "Lib/opcode.py"
8
9
header = f"""
10
// Auto-generated by {SCRIPT_NAME} from {PYTHON_OPCODE}
11
12
#ifndef Py_OPCODE_H
13
#define Py_OPCODE_H
14
#ifdef __cplusplus
15
extern "C" {{
16
#endif
17
18
19
/* Instruction opcodes for compiled code */
20
""".lstrip()
21
22
footer = """
23
24
#ifdef __cplusplus
25
}
26
#endif
27
#endif /* !Py_OPCODE_H */
28
"""
29
30
internal_header = f"""
31
// Auto-generated by {SCRIPT_NAME} from {PYTHON_OPCODE}
32
33
#ifndef Py_INTERNAL_OPCODE_H
34
#define Py_INTERNAL_OPCODE_H
35
#ifdef __cplusplus
36
extern "C" {{
37
#endif
38
39
#ifndef Py_BUILD_CORE
40
# error "this header requires Py_BUILD_CORE define"
41
#endif
42
43
#include "opcode.h"
44
""".lstrip()
45
46
internal_footer = """
47
#ifdef __cplusplus
48
}
49
#endif
50
#endif // !Py_INTERNAL_OPCODE_H
51
"""
52
53
intrinsic_header = f"""
54
// Auto-generated by {SCRIPT_NAME} from {PYTHON_OPCODE}
55
56
""".lstrip()
57
58
intrinsic_footer = """
59
typedef PyObject *(*instrinsic_func1)(PyThreadState* tstate, PyObject *value);
60
typedef PyObject *(*instrinsic_func2)(PyThreadState* tstate, PyObject *value1, PyObject *value2);
61
extern const instrinsic_func1 _PyIntrinsics_UnaryFunctions[];
62
extern const instrinsic_func2 _PyIntrinsics_BinaryFunctions[];
63
"""
64
65
DEFINE = "#define {:<38} {:>3}\n"
66
67
UINT32_MASK = (1<<32)-1
68
69
def get_python_module_dict(filename):
70
mod = {}
71
with tokenize.open(filename) as fp:
72
code = fp.read()
73
exec(code, mod)
74
return mod
75
76
def main(opcode_py,
77
_opcode_metadata_py='Lib/_opcode_metadata.py',
78
outfile='Include/opcode.h',
79
internaloutfile='Include/internal/pycore_opcode.h',
80
intrinsicoutfile='Include/internal/pycore_intrinsics.h'):
81
82
_opcode_metadata = get_python_module_dict(_opcode_metadata_py)
83
84
opcode = get_python_module_dict(opcode_py)
85
opmap = opcode['opmap']
86
opname = opcode['opname']
87
hasarg = opcode['hasarg']
88
hasconst = opcode['hasconst']
89
hasjrel = opcode['hasjrel']
90
hasjabs = opcode['hasjabs']
91
is_pseudo = opcode['is_pseudo']
92
_pseudo_ops = opcode['_pseudo_ops']
93
94
95
ENABLE_SPECIALIZATION = opcode["ENABLE_SPECIALIZATION"]
96
MIN_PSEUDO_OPCODE = opcode["MIN_PSEUDO_OPCODE"]
97
MAX_PSEUDO_OPCODE = opcode["MAX_PSEUDO_OPCODE"]
98
MIN_INSTRUMENTED_OPCODE = opcode["MIN_INSTRUMENTED_OPCODE"]
99
100
NUM_OPCODES = len(opname)
101
used = [ False ] * len(opname)
102
next_op = 1
103
104
for name, op in opmap.items():
105
used[op] = True
106
107
specialized_opmap = {}
108
opname_including_specialized = opname.copy()
109
for name in _opcode_metadata['_specialized_instructions']:
110
while used[next_op]:
111
next_op += 1
112
specialized_opmap[name] = next_op
113
opname_including_specialized[next_op] = name
114
used[next_op] = True
115
116
with open(outfile, 'w') as fobj, open(internaloutfile, 'w') as iobj, open(
117
intrinsicoutfile, "w") as nobj:
118
fobj.write(header)
119
iobj.write(internal_header)
120
nobj.write(intrinsic_header)
121
122
for name in opname:
123
if name in opmap:
124
op = opmap[name]
125
if op == MIN_PSEUDO_OPCODE:
126
fobj.write(DEFINE.format("MIN_PSEUDO_OPCODE", MIN_PSEUDO_OPCODE))
127
if op == MIN_INSTRUMENTED_OPCODE:
128
fobj.write(DEFINE.format("MIN_INSTRUMENTED_OPCODE", MIN_INSTRUMENTED_OPCODE))
129
130
fobj.write(DEFINE.format(name, op))
131
132
if op == MAX_PSEUDO_OPCODE:
133
fobj.write(DEFINE.format("MAX_PSEUDO_OPCODE", MAX_PSEUDO_OPCODE))
134
135
136
for name, op in specialized_opmap.items():
137
fobj.write(DEFINE.format(name, op))
138
139
iobj.write("\nextern const uint8_t _PyOpcode_Caches[256];\n")
140
iobj.write("\nextern const uint8_t _PyOpcode_Deopt[256];\n")
141
iobj.write("\n#ifdef NEED_OPCODE_TABLES\n")
142
143
iobj.write("\nconst uint8_t _PyOpcode_Caches[256] = {\n")
144
for i, entries in enumerate(opcode["_inline_cache_entries"]):
145
if entries:
146
iobj.write(f" [{opname[i]}] = {entries},\n")
147
iobj.write("};\n")
148
149
deoptcodes = {}
150
for basic, op in opmap.items():
151
if not is_pseudo(op):
152
deoptcodes[basic] = basic
153
for basic, family in _opcode_metadata["_specializations"].items():
154
for specialized in family:
155
deoptcodes[specialized] = basic
156
iobj.write("\nconst uint8_t _PyOpcode_Deopt[256] = {\n")
157
for opt, deopt in sorted(deoptcodes.items()):
158
iobj.write(f" [{opt}] = {deopt},\n")
159
iobj.write("};\n")
160
iobj.write("#endif // NEED_OPCODE_TABLES\n")
161
162
fobj.write("\n")
163
for i, (op, _) in enumerate(opcode["_nb_ops"]):
164
fobj.write(DEFINE.format(op, i))
165
166
nobj.write("/* Unary Functions: */")
167
nobj.write("\n")
168
for i, op in enumerate(opcode["_intrinsic_1_descs"]):
169
nobj.write(DEFINE.format(op, i))
170
nobj.write("\n")
171
nobj.write(DEFINE.format("MAX_INTRINSIC_1", i))
172
173
nobj.write("\n\n")
174
nobj.write("/* Binary Functions: */\n")
175
for i, op in enumerate(opcode["_intrinsic_2_descs"]):
176
nobj.write(DEFINE.format(op, i))
177
nobj.write("\n")
178
nobj.write(DEFINE.format("MAX_INTRINSIC_2", i))
179
180
nobj.write(intrinsic_footer)
181
182
fobj.write("\n")
183
fobj.write("/* Defined in Lib/opcode.py */\n")
184
fobj.write(f"#define ENABLE_SPECIALIZATION {int(ENABLE_SPECIALIZATION)}")
185
186
iobj.write("\n")
187
iobj.write("#ifdef Py_DEBUG\n")
188
iobj.write(f"static const char *const _PyOpcode_OpName[{NUM_OPCODES}] = {{\n")
189
for op, name in enumerate(opname_including_specialized):
190
if name[0] != "<":
191
op = name
192
iobj.write(f''' [{op}] = "{name}",\n''')
193
iobj.write("};\n")
194
iobj.write("#endif\n")
195
196
iobj.write("\n")
197
iobj.write("#define EXTRA_CASES \\\n")
198
for i, flag in enumerate(used):
199
if not flag:
200
iobj.write(f" case {i}: \\\n")
201
iobj.write(" ;\n")
202
203
fobj.write(footer)
204
iobj.write(internal_footer)
205
206
207
print(f"{outfile} regenerated from {opcode_py}")
208
209
210
if __name__ == '__main__':
211
main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5])
212
213