Skip to content

Add attributes to the JIT optimizer DSL #132967

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Fidget-Spinner opened this issue Apr 25, 2025 · 3 comments
Open

Add attributes to the JIT optimizer DSL #132967

Fidget-Spinner opened this issue Apr 25, 2025 · 3 comments
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) topic-JIT type-feature A feature request or enhancement

Comments

@Fidget-Spinner
Copy link
Member

Fidget-Spinner commented Apr 25, 2025

Feature or enhancement

Proposal:

Partially discussed here: faster-cpython/ideas#728

We want to teach the JIT types optimizer the types of its stack variables. This, when combined with pure operations, will allow us to shift more things to the DSL. There are numerous benefits to moving things to the DSL:

  1. Less error prone.
  2. The DSL can work with more information. Right now the pure operations don't check for their types before executing them. In a simple uop format, this is safe, but it's not robust if we change the uop format or project more advanced uops.

The implementation will only affect optimizer_bytecodes.c. There has been some discussion about the growing complexity of bytecodes.c. Since this is also specific to the types specializer, we should keep it out of bytecodes.c.

Consider the following:
Current:

    op(_GUARD_NOS_UNICODE, (nos, unused -- nos, unused)) {
        if (sym_matches_type(nos, &PyUnicode_Type)) {
            REPLACE_OP(this_instr, _NOP, 0, 0);
        }
        sym_set_type(nos, &PyUnicode_Type);
    }

New:

    op(_GUARD_NOS_UNICODE, (nos, unused -- type(&PyUnicode_Type) nos, unused)) {
        if (sym_matches_type(nos, &PyUnicode_Type)) {
            REPLACE_OP(this_instr, _NOP, 0, 0);
        }
    }

This isn't very powerful on it's own, but when combined with the pure optimization, it will allow us to validate properly advanced pure uops before evaluating them.

Consider the following code right now:

    op(_BINARY_OP_ADD_INT, (left, right -- res)) {
        if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) {
            assert(PyLong_CheckExact(sym_get_const(ctx, left)));
            assert(PyLong_CheckExact(sym_get_const(ctx, right)));
            PyObject *temp = _PyLong_Add((PyLongObject *)sym_get_const(ctx, left),
                                         (PyLongObject *)sym_get_const(ctx, right));
            if (temp == NULL) {
                goto error;
            }
            res = sym_new_const(ctx, temp);
            Py_DECREF(temp);
            // TODO gh-115506:
            // replace opcode with constant propagated one and add tests!
        }
        else {
            res = sym_new_type(ctx, &PyLong_Type);
        }
    }

The constant eval part doesn't check for matching types first. This is currently safe as _BINARY_OP_ADD_INT always follows a guard in tier 1. However, it's not safe once we do things like combining specialization passes (#128939), reorganizing them, or introducing more advanced pure uops. it would be tedious and error-prone to handwrite these checks ourselves. When the pure optimization is combined with the type attributes, or with const attributes, they will be able to automatically validate themselves.

Has this already been discussed elsewhere?

No response given

Links to previous discussion of this feature:

No response

Linked PRs

@Fidget-Spinner Fidget-Spinner added the type-feature A feature request or enhancement label Apr 25, 2025
@picnixz picnixz added the interpreter-core (Objects, Python, Grammar, and Parser dirs) label Apr 28, 2025
@markshannon
Copy link
Member

This looks promising.

I'd be inclined to use Python names for the types:
op(_GUARD_NOS_UNICODE, (nos, unused -- type(str) nos, unused))
instead of
op(_GUARD_NOS_UNICODE, (nos, unused -- type(&PyUnicode_Type) nos, unused))
not only for readability, but to give better checking for when optimizations are safe to apply.

@Fidget-Spinner
Copy link
Member Author

but to give better checking for when optimizations are safe to apply.

Could you give an example of how the Python type will make checking safer? I'm not too clear about it at the moment.

@markshannon
Copy link
Member

Having a fixed set of legal names will make it safer by enabling more checking. It doesn't matter whether the name is int or &PyLong_Type.

If we are going to have a fixed set of names and require the code generator to understand them, we might as well use the nicer Python names.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) topic-JIT type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

3 participants