(root)/
Python-3.12.0/
Tools/
build/
generate_opcode_h.py
       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])