From: Siu Kwan Lam <1929845+sklam@users.noreply.github.com>
Origin: https://github.com/numba/numba/pull/8545
Date: Wed, 24 Aug 2022 17:58:30 -0500
Subject: Minimal changes to get a basic integer sum reduction for loop
 working in py3.11

---
 numba/core/bytecode.py    |  3 +++
 numba/core/byteflow.py    | 48 ++++++++++++++++++++++++++++++++++++++++++-----
 numba/core/interpreter.py | 39 +++++++++++++++++++++++++++++++++-----
 3 files changed, 80 insertions(+), 10 deletions(-)

diff --git a/numba/core/bytecode.py b/numba/core/bytecode.py
index 13516cd..5bdd0be 100644
--- a/numba/core/bytecode.py
+++ b/numba/core/bytecode.py
@@ -90,6 +90,9 @@ class ByteCodeInst(object):
         # https://bugs.python.org/issue27129
         # https://github.com/python/cpython/pull/25069
         assert self.is_jump
+        if PYVERSION >= (3, 11):
+            if self.opcode == dis.opmap["JUMP_BACKWARD"]:
+                return self.offset - self.arg * 2
         if PYVERSION >= (3, 10):
             if self.opcode in JREL_OPS:
                 return self.next + self.arg * 2
diff --git a/numba/core/byteflow.py b/numba/core/byteflow.py
index 5c7ebfd..981fc45 100644
--- a/numba/core/byteflow.py
+++ b/numba/core/byteflow.py
@@ -1,7 +1,7 @@
 """
 Implement python 3.8+ bytecode analysis
 """
-
+import dis
 from pprint import pformat
 import logging
 from collections import namedtuple, defaultdict, deque
@@ -290,6 +290,12 @@ class TraceRunner(object):
     def op_RESUME(self, state, inst):
         state.append(inst)
 
+    def op_CACHE(self, state, inst):
+        state.append(inst)
+
+    def op_PRECALL(self, state, inst):
+        state.append(inst)
+
     def op_FORMAT_VALUE(self, state, inst):
         """
         FORMAT_VALUE(flags): flags argument specifies format spec which is
@@ -327,10 +333,19 @@ class TraceRunner(object):
     def op_POP_TOP(self, state, inst):
         state.pop()
 
-    def op_LOAD_GLOBAL(self, state, inst):
-        res = state.make_temp()
-        state.append(inst, res=res)
-        state.push(res)
+    if PYVERSION == (3, 11):
+        def op_LOAD_GLOBAL(self, state, inst):
+            res = state.make_temp()
+            idx = inst.arg >> 1
+            state.append(inst, idx=idx, res=res)
+            if inst.arg & 1:
+                state.push(state.make_temp())
+            state.push(res)
+    else:
+        def op_LOAD_GLOBAL(self, state, inst):
+            res = state.make_temp()
+            state.append(inst, res=res)
+            state.push(res)
 
     def op_LOAD_DEREF(self, state, inst):
         res = state.make_temp()
@@ -633,6 +648,11 @@ class TraceRunner(object):
         state.append(inst)
         state.fork(pc=inst.get_jump_target())
 
+    def op_JUMP_BACKWARD(self, state, inst):
+        state.append(inst)
+        print(inst)
+        state.fork(pc=inst.get_jump_target())
+
     def op_JUMP_ABSOLUTE(self, state, inst):
         state.append(inst)
         state.fork(pc=inst.get_jump_target())
@@ -810,6 +830,16 @@ class TraceRunner(object):
         target = state.pop()
         state.append(inst, target=target, index=index)
 
+
+    def op_CALL(self, state, inst):
+        narg = inst.arg
+        args = list(reversed([state.pop() for _ in range(narg)]))
+        func = state.pop()
+
+        res = state.make_temp()
+        state.append(inst, func=func, args=args, res=res)
+        state.push(res)
+
     def op_CALL_FUNCTION(self, state, inst):
         narg = inst.arg
         args = list(reversed([state.pop() for _ in range(narg)]))
@@ -1049,6 +1079,14 @@ class TraceRunner(object):
         # no-op in Numba
         pass
 
+    def op_BINARY_OP(self, state, inst):
+        op = dis._nb_ops[inst.arg][1]
+        rhs = state.pop()
+        lhs = state.pop()
+        res = state.make_temp()
+        state.append(inst, op=op, lhs=lhs, rhs=rhs, res=res)
+        state.push(res)
+
     def _unaryop(self, state, inst):
         val = state.pop()
         res = state.make_temp()
diff --git a/numba/core/interpreter.py b/numba/core/interpreter.py
index 0df5dbf..16c2b4e 100644
--- a/numba/core/interpreter.py
+++ b/numba/core/interpreter.py
@@ -1712,6 +1712,12 @@ class Interpreter(object):
     def op_RESUME(self, inst):
         pass
 
+    def op_CACHE(self, inst):
+        pass
+
+    def op_PRECALL(self, inst):
+        pass
+
     def op_PRINT_ITEM(self, inst, item, printvar, res):
         item = self.get(item)
         printgv = ir.Global("print", print, loc=self.loc)
@@ -2054,11 +2060,18 @@ class Interpreter(object):
             const = ir.Const(value, loc=self.loc)
         self.store(const, res)
 
-    def op_LOAD_GLOBAL(self, inst, res):
-        name = self.code_names[inst.arg]
-        value = self.get_global_value(name)
-        gl = ir.Global(name, value, loc=self.loc)
-        self.store(gl, res)
+    if PYVERSION == (3, 11):
+        def op_LOAD_GLOBAL(self, inst, idx, res):
+            name = self.code_names[idx]
+            value = self.get_global_value(name)
+            gl = ir.Global(name, value, loc=self.loc)
+            self.store(gl, res)
+    else:
+        def op_LOAD_GLOBAL(self, inst, res):
+            name = self.code_names[inst.arg]
+            value = self.get_global_value(name)
+            gl = ir.Global(name, value, loc=self.loc)
+            self.store(gl, res)
 
     def op_LOAD_DEREF(self, inst, res):
         n_cellvars = len(self.code_cellvars)
@@ -2128,6 +2141,12 @@ class Interpreter(object):
             self.store(const_none, name=tmp)
             self._exception_vars.add(tmp)
 
+    def op_CALL(self, inst, func, args, res):
+        func = self.get(func)
+        args = [self.get(x) for x in args]
+        expr = ir.Expr.call(func, args, (), loc=self.loc)
+        self.store(expr, res)
+
     if PYVERSION < (3, 6):
 
         def op_CALL_FUNCTION(self, inst, func, args, kws, res, vararg):
@@ -2487,6 +2506,12 @@ class Interpreter(object):
                                      loc=self.loc)
         self.store(expr, res)
 
+    def op_BINARY_OP(self, inst, op, lhs, rhs, res):
+        if "=" in op:
+            self._inplace_binop(op[:1], lhs, rhs, res)
+        else:
+            self._binop(op, lhs, rhs, res)
+
     def op_BINARY_ADD(self, inst, lhs, rhs, res):
         self._binop('+', lhs, rhs, res)
 
@@ -2579,6 +2604,10 @@ class Interpreter(object):
         jmp = ir.Jump(inst.get_jump_target(), loc=self.loc)
         self.current_block.append(jmp)
 
+    def op_JUMP_BACKWARD(self, inst):
+        jmp = ir.Jump(inst.get_jump_target(), loc=self.loc)
+        self.current_block.append(jmp)
+
     def op_POP_BLOCK(self, inst, kind=None):
         if kind is None:
             self.syntax_blocks.pop()
