Skip to content
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

Numba support for Python 3.10 #7562

Closed
esc opened this issue Nov 15, 2021 · 2 comments
Closed

Numba support for Python 3.10 #7562

esc opened this issue Nov 15, 2021 · 2 comments

Comments

@esc
Copy link
Member

esc commented Nov 15, 2021

Dear all,

as you may know, we encountered some serious issues when attempting to port
Numba to Python 3.10. This issue will serve as a summary of existing challenges
and also as a central reference issue with links to all existing branches and
PRs.

The story so far

Supporting new Python versions for Numba is always somewhat involved. The main
reason for this is that Numba interfaces to Python via the bytecode, which is
not a stable interface/contract. In the 3.10 case, the change that caused the
most headaches was:

https://bugs.python.org/issue44626

Specifically, the part of that change that now causes the CPython bytecode
optimizer to inline return statements. I.e. the following feature:

/* If this block ends with an unconditional jump to an exit block,
 * then remove the jump and extend this block with the target.
 */
static int
extend_block(basicblock *bb) {
    if (bb->b_iused == 0) {
        return 0;
    }
    struct instr *last = &bb->b_instr[bb->b_iused-1];
    if (last->i_opcode != JUMP_ABSOLUTE && last->i_opcode != JUMP_FORWARD) {
        return 0;
    }
    if (last->i_target->b_exit && last->i_target->b_iused <= MAX_COPY_SIZE) {
        basicblock *to_copy = last->i_target;
        last->i_opcode = NOP;
        for (int i = 0; i < to_copy->b_iused; i++) {
            int index = compiler_next_instr(bb);
            if (index < 0) {
                return -1;
            }
            bb->b_instr[index] = to_copy->b_instr[i];
        }
        bb->b_exit = 1;
    }
    return 0;
}

Ref: https://github.com/python/cpython/blob/d41abe8/Python/compile.c#L7533-L7558

This change was noticed early during the porting process. It turned out to
cause the most headaches for the with objmode context manager:

https://numba.readthedocs.io/en/stable/user/withobjmode.html?highlight=objmode#the-objmode-context-manager

Perhaps the easiest way to think about this is with the following Python source
example (importantly: note that CPython optimizes this at the Bytecode level, not at the
syntax or AST levels! This is for illustration only):

with objmode:
    if a == 1:
      b = 1
    elif a == 2:
      b = 2
    else a == 3:
      b = 3
return b
with objmode:
    if a == 1:
      b = 1
      return b
    elif a == 2:
      b = 2
      return b
    else a == 3:
      b = 3
      return b

Unfortunately, in the with objmode we can not allow return statements,
since the code within the statement will be lifted out and executed in
object-mode so as to get access to interpreter features. So this bytecode
optimization renders this Numba feature useless, since the return will be
inlined! Worse yet: there is no way for Numba to tell if this was a bytecode
optimizer action or something the user intended! Incidentally, there is a way
to defeat this optimization, by making the return block big enough (see the
code snippet above for MAX_COPY_SIZE) however this is too rudimentary and can
probably only be used to adapt a few failing tests.

Effectively, Numba needed a way to undo the optimization caused by CPython and
as a precursor to that, would need to understand where a with-context begins
and where it ends. However much of this logic was based on heuristics and so
had to be overhauled to facilitate better control flow analysis.

Running the tests

Anaconda provides (at the time of writing) a Python 3.10 binary and associated
compilers on at least Linux and OSX so that can be used for testing.

Compiling Numba requires Numpy. However, the only Numpy's available (at the
time of writing) for 3.10 were 1.21.3 and 1.21.4 via conda-forge. Note however,
that both of these releases do appear buggy:

numpy/numpy#20376

Live branches

At the time of writing the following branches were live:

Dead branches

@numba numba locked and limited conversation to collaborators Nov 15, 2021
@esc esc added this to the Numba 0.55 RC milestone Nov 15, 2021
@esc
Copy link
Member Author

esc commented Nov 15, 2021

Latest test run is at: #7563

@esc
Copy link
Member Author

esc commented Dec 10, 2021

All relevant branches merged, Python 3.10 is available from master at the time of writing! Thank you all for your patience and patches! EOM

@esc esc closed this as completed Dec 10, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant