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 #define IS_PSEUDO_OPCODE(op) (((op) >= MIN_PSEUDO_OPCODE) && ((op) <= MAX_PSEUDO_OPCODE))
25
26 #ifdef __cplusplus
27 }
28 #endif
29 #endif /* !Py_OPCODE_H */
30 """
31
32 internal_header = f"""
33 // Auto-generated by {SCRIPT_NAME} from {PYTHON_OPCODE}
34
35 #ifndef Py_INTERNAL_OPCODE_H
36 #define Py_INTERNAL_OPCODE_H
37 #ifdef __cplusplus
38 extern "C" {{
39 #endif
40
41 #ifndef Py_BUILD_CORE
42 # error "this header requires Py_BUILD_CORE define"
43 #endif
44
45 #include "opcode.h"
46 """.lstrip()
47
48 internal_footer = """
49 #ifdef __cplusplus
50 }
51 #endif
52 #endif // !Py_INTERNAL_OPCODE_H
53 """
54
55 intrinsic_header = f"""
56 // Auto-generated by {SCRIPT_NAME} from {PYTHON_OPCODE}
57
58 """.lstrip()
59
60 intrinsic_footer = """
61 typedef PyObject *(*instrinsic_func1)(PyThreadState* tstate, PyObject *value);
62 typedef PyObject *(*instrinsic_func2)(PyThreadState* tstate, PyObject *value1, PyObject *value2);
63 extern const instrinsic_func1 _PyIntrinsics_UnaryFunctions[];
64 extern const instrinsic_func2 _PyIntrinsics_BinaryFunctions[];
65 """
66
67 DEFINE = "#define {:<38} {:>3}\n"
68
69 UINT32_MASK = (1<<32)-1
70
71 def write_int_array_from_ops(name, ops, out):
72 bits = 0
73 for op in ops:
74 bits |= 1<<op
75 out.write(f"const uint32_t {name}[9] = {{\n")
76 for i in range(9):
77 out.write(f" {bits & UINT32_MASK}U,\n")
78 bits >>= 32
79 assert bits == 0
80 out.write(f"}};\n")
81
82 def main(opcode_py, outfile='Include/opcode.h',
83 internaloutfile='Include/internal/pycore_opcode.h',
84 intrinsicoutfile='Include/internal/pycore_intrinsics.h'):
85 opcode = {}
86 if hasattr(tokenize, 'open'):
87 fp = tokenize.open(opcode_py) # Python 3.2+
88 else:
89 fp = open(opcode_py) # Python 2.7
90 with fp:
91 code = fp.read()
92 exec(code, opcode)
93 opmap = opcode['opmap']
94 opname = opcode['opname']
95 hasarg = opcode['hasarg']
96 hasconst = opcode['hasconst']
97 hasjrel = opcode['hasjrel']
98 hasjabs = opcode['hasjabs']
99 is_pseudo = opcode['is_pseudo']
100 _pseudo_ops = opcode['_pseudo_ops']
101
102 ENABLE_SPECIALIZATION = opcode["ENABLE_SPECIALIZATION"]
103 HAVE_ARGUMENT = opcode["HAVE_ARGUMENT"]
104 MIN_PSEUDO_OPCODE = opcode["MIN_PSEUDO_OPCODE"]
105 MAX_PSEUDO_OPCODE = opcode["MAX_PSEUDO_OPCODE"]
106 MIN_INSTRUMENTED_OPCODE = opcode["MIN_INSTRUMENTED_OPCODE"]
107
108 NUM_OPCODES = len(opname)
109 used = [ False ] * len(opname)
110 next_op = 1
111
112 for name, op in opmap.items():
113 used[op] = True
114
115 specialized_opmap = {}
116 opname_including_specialized = opname.copy()
117 for name in opcode['_specialized_instructions']:
118 while used[next_op]:
119 next_op += 1
120 specialized_opmap[name] = next_op
121 opname_including_specialized[next_op] = name
122 used[next_op] = True
123
124 with open(outfile, 'w') as fobj, open(internaloutfile, 'w') as iobj, open(
125 intrinsicoutfile, "w") as nobj:
126 fobj.write(header)
127 iobj.write(internal_header)
128 nobj.write(intrinsic_header)
129
130 for name in opname:
131 if name in opmap:
132 op = opmap[name]
133 if op == HAVE_ARGUMENT:
134 fobj.write(DEFINE.format("HAVE_ARGUMENT", HAVE_ARGUMENT))
135 if op == MIN_PSEUDO_OPCODE:
136 fobj.write(DEFINE.format("MIN_PSEUDO_OPCODE", MIN_PSEUDO_OPCODE))
137 if op == MIN_INSTRUMENTED_OPCODE:
138 fobj.write(DEFINE.format("MIN_INSTRUMENTED_OPCODE", MIN_INSTRUMENTED_OPCODE))
139
140 fobj.write(DEFINE.format(name, op))
141
142 if op == MAX_PSEUDO_OPCODE:
143 fobj.write(DEFINE.format("MAX_PSEUDO_OPCODE", MAX_PSEUDO_OPCODE))
144
145
146 for name, op in specialized_opmap.items():
147 fobj.write(DEFINE.format(name, op))
148
149 iobj.write("\nextern const uint32_t _PyOpcode_Jump[9];\n")
150 iobj.write("\nextern const uint8_t _PyOpcode_Caches[256];\n")
151 iobj.write("\nextern const uint8_t _PyOpcode_Deopt[256];\n")
152 iobj.write("\n#ifdef NEED_OPCODE_TABLES\n")
153 write_int_array_from_ops("_PyOpcode_Jump", opcode['hasjrel'] + opcode['hasjabs'], iobj)
154
155 iobj.write("\nconst uint8_t _PyOpcode_Caches[256] = {\n")
156 for i, entries in enumerate(opcode["_inline_cache_entries"]):
157 if entries:
158 iobj.write(f" [{opname[i]}] = {entries},\n")
159 iobj.write("};\n")
160
161 deoptcodes = {}
162 for basic, op in opmap.items():
163 if not is_pseudo(op):
164 deoptcodes[basic] = basic
165 for basic, family in opcode["_specializations"].items():
166 for specialized in family:
167 deoptcodes[specialized] = basic
168 iobj.write("\nconst uint8_t _PyOpcode_Deopt[256] = {\n")
169 for opt, deopt in sorted(deoptcodes.items()):
170 iobj.write(f" [{opt}] = {deopt},\n")
171 iobj.write("};\n")
172 iobj.write("#endif // NEED_OPCODE_TABLES\n")
173
174 fobj.write("\n")
175 fobj.write("#define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\\")
176 for op in _pseudo_ops:
177 if opmap[op] in hasarg:
178 fobj.write(f"\n || ((op) == {op}) \\")
179 fobj.write("\n )\n")
180
181 fobj.write("\n")
182 fobj.write("#define HAS_CONST(op) (false\\")
183 for op in hasconst:
184 fobj.write(f"\n || ((op) == {opname[op]}) \\")
185 fobj.write("\n )\n")
186
187 fobj.write("\n")
188 for i, (op, _) in enumerate(opcode["_nb_ops"]):
189 fobj.write(DEFINE.format(op, i))
190
191 nobj.write("/* Unary Functions: */")
192 nobj.write("\n")
193 for i, op in enumerate(opcode["_intrinsic_1_descs"]):
194 nobj.write(DEFINE.format(op, i))
195 nobj.write("\n")
196 nobj.write(DEFINE.format("MAX_INTRINSIC_1", i))
197
198 nobj.write("\n\n")
199 nobj.write("/* Binary Functions: */\n")
200 for i, op in enumerate(opcode["_intrinsic_2_descs"]):
201 nobj.write(DEFINE.format(op, i))
202 nobj.write("\n")
203 nobj.write(DEFINE.format("MAX_INTRINSIC_2", i))
204
205 nobj.write(intrinsic_footer)
206
207 fobj.write("\n")
208 fobj.write("/* Defined in Lib/opcode.py */\n")
209 fobj.write(f"#define ENABLE_SPECIALIZATION {int(ENABLE_SPECIALIZATION)}")
210
211 iobj.write("\n")
212 iobj.write("#ifdef Py_DEBUG\n")
213 iobj.write(f"static const char *const _PyOpcode_OpName[{NUM_OPCODES}] = {{\n")
214 for op, name in enumerate(opname_including_specialized):
215 if name[0] != "<":
216 op = name
217 iobj.write(f''' [{op}] = "{name}",\n''')
218 iobj.write("};\n")
219 iobj.write("#endif\n")
220
221 iobj.write("\n")
222 iobj.write("#define EXTRA_CASES \\\n")
223 for i, flag in enumerate(used):
224 if not flag:
225 iobj.write(f" case {i}: \\\n")
226 iobj.write(" ;\n")
227
228 fobj.write(footer)
229 iobj.write(internal_footer)
230
231
232 print(f"{outfile} regenerated from {opcode_py}")
233
234
235 if __name__ == '__main__':
236 main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])