Skip to content

Commit 7580ee0

Browse files
committed
Update the how to guides section with the bytecode specialization steps
1 parent f489bdd commit 7580ee0

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

development-tools/clinic.rst

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2213,3 +2213,90 @@ and update your unit tests to reflect the new behaviour.
22132213
If you forget to update your input block during the alpha and beta phases,
22142214
the compiler warning will turn into a compiler error when the
22152215
release candidate phase begins.
2216+
2217+
How to add a new bytecode specialization
2218+
----------------------------------------
2219+
2220+
Bytecode specialization is a performance optimization technique in CPython.
2221+
It involves dynamically replacing general-purpose bytecode instructions with
2222+
specialized versions tailored to specific runtime contexts. This guide explains
2223+
how to add a new bytecode specialization, using ``CONTAINS_OP`` as an example.
2224+
2225+
Steps:
2226+
2227+
1. Update ``Python/bytecodes.c``
2228+
2229+
- Convert ``CONTAINS_OP`` to a micro-operation (uop) by renaming
2230+
it to ``_CONTAINS_OP`` and changing the instruction definition
2231+
from ``inst`` to ``op``.
2232+
2233+
.. code-block:: c
2234+
2235+
// Before
2236+
inst(CONTAINS_OP, ...);
2237+
2238+
// After
2239+
op(_CONTAINS_OP, ...);
2240+
2241+
- Add a uop that calls the specializing function
2242+
``_SPECIALIZE_CONTAINS_OP``.
2243+
2244+
.. code-block:: c
2245+
2246+
specializing op(_SPECIALIZE_CONTAINS_OP, (counter/1, left, right -- left, right)) {
2247+
#if ENABLE_SPECIALIZATION
2248+
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
2249+
next_instr = this_instr;
2250+
_Py_Specialize_ContainsOp(right, next_instr);
2251+
DISPATCH_SAME_OPARG();
2252+
}
2253+
STAT_INC(CONTAINS_OP, deferred);
2254+
DECREMENT_ADAPTIVE_COUNTER(this_instr[1].cache);
2255+
#endif /* ENABLE_SPECIALIZATION */
2256+
}
2257+
2258+
- The original ``CONTAINS_OP`` is now a new macro consisting of
2259+
``_SPECIALIZE_CONTAINS_OP`` and ``_CONTAINS_OP``.
2260+
2261+
2. Define the cache structure
2262+
2263+
- In ``Include/internal/pycore_code.h``, define a cache structure with
2264+
at least a 16-bit counter.
2265+
2266+
.. code-block:: c
2267+
2268+
typedef struct {
2269+
uint16_t counter;
2270+
} _PyContainsOpCache;
2271+
2272+
3. Write the specializing function
2273+
2274+
- Implement the specializing function in ``Python/specialize.c``.
2275+
Refer to existing functions in the file for the standard format.
2276+
- Update operation stats by calling ``add_stat_dict`` in
2277+
``Python/specialize.c``.
2278+
2279+
4. Add the cache layout to ``Lib/opcode.py``
2280+
2281+
- Define the cache layout in ``Lib/opcode.py`` so that Python's ``dis``
2282+
module correctly represents the specialization.
2283+
2284+
5. Bump the magic number
2285+
2286+
- Update ``Include/internal/pycore_magic_number.h`` to bump the magic
2287+
number so the interpreter recognizes the new bytecode format.
2288+
2289+
6. Regenerate build artifacts
2290+
2291+
- Run the appropriate build regeneration commands:
2292+
2293+
- *Unix/macOS:*
2294+
``make regen-all``
2295+
- *Windows:*
2296+
``build.bat --regen``
2297+
2298+
2299+
Additional Resources:
2300+
2301+
- :pep:`659`
2302+
- `Reference PR for CONTAINS_OP <https://github.com/python/cpython/pull/116385/files>`_

0 commit comments

Comments
 (0)