Repository: numba/numba

Issue:
Invalid IR generated in Parfors
<!--

Thanks for opening an issue! To help the Numba team handle your information
efficiently, please first ensure that there is no other issue present that
already describes the issue you have
(search at https://github.com/numba/numba/issues?&q=is%3Aissue).

For more general "how do I do X?" type questions, please speak to us in real
time on https://gitter.im/numba/numba or post to the Numba mailing list
https://groups.google.com/a/continuum.io/forum/#!forum/numba-users.

-->

## Reporting a bug

<!--

Before submitting a bug report please ensure that you can check off these boxes:

-->

- [x] I am using the latest released version of Numba (most recent is visible in
 the change log (https://github.com/numba/numba/blob/master/CHANGE_LOG).
- [x] I have included below a minimal working reproducer (if you are unsure how
 to write one see http://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports).

<!--

Please include details of the bug here, including, if applicable, what you
expected to happen!

-->


(from gitter https://gitter.im/numba/numba?at=5e9dfde285b01628f066677f)

reproducer:

```python
from numba import njit, prange
import numpy as np

@njit(parallel=True)
def qdraw_estimation(eta1,t,taus,alphas,len_sim,nrep):
    tot_len = np.sum(len_sim)
    tau = np.random.random((tot_len,nrep))
    sim = np.empty((tot_len,nrep))
    pos = 0
    for i in range(len(len_sim)) :
        sim[pos,:] = eta1[i]
        pos = pos+len_sim[i]
    pos = 0
    for i in range(len(eta1)):
        for j in range(len_sim[i]-1):
            for k in prange(nrep):
                l= np.searchsorted(taus,tau[pos,k])
                l = l-1+np.abs(taus[l-1:l+1] - tau[pos,k]).argmin() #Correction to find the nearest
                qs = alphas[l,:] @ np.array([1.0,t[i],t[i]**2,sim[pos,k]])
                sim[pos+1,k] = qs
            t[i] = t[i]+2.0/9.61279653940348
            pos = pos + 1
        pos = pos + 1
    return sim

tau = np.random.random(10)
eta_lag = np.random.random(10)
t = np.random.random(10)
taus = np.random.random(20)
alphas = np.random.random((20, 4))
qdraw_estimation(eta_lag,t,taus,alphas,np.asarray([4,4,4,4,4,4,4,4,4,4]),2)

```

the error
```pytb

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
./numba/core/errors.py in new_error_context(fmt_, *args, **kwargs)
    800     try:
--> 801         yield
    802     except NumbaError as e:

./numba/core/lowering.py in lower_block(self, block)
    266                                    loc=self.loc, errcls_=defaulterrcls):
--> 267                 self.lower_inst(inst)
    268         self.post_block(block)

./numba/core/lowering.py in lower_inst(self, inst)
    479                 if isinstance(inst, _class):
--> 480                     func(self, inst)
    481                     return

./numba/parfors/parfor_lowering.py in _lower_parfor_parallel(lowerer, parfor)
    239             lowerer, parfor, typemap, typingctx, targetctx, flags, {},
--> 240             bool(alias_map), index_var_typ, parfor.races)
    241     finally:

./numba/parfors/parfor_lowering.py in _create_gufunc_for_parfor_body(lowerer, parfor, typemap, typingctx, targetctx, flags, locals, has_aliases, index_var_typ, races)
    933         warnings.warn(NumbaParallelSafetyWarning(msg, loc))
--> 934     replace_var_with_array(races, loop_body, typemap, lowerer.fndesc.calltypes)
    935

./numba/parfors/parfor_lowering.py in replace_var_with_array(vars, loop_body, typemap, calltypes)
   1363 def replace_var_with_array(vars, loop_body, typemap, calltypes):
-> 1364     replace_var_with_array_internal(vars, loop_body, typemap, calltypes)
   1365     for v in vars:

./numba/parfors/parfor_lowering.py in replace_var_with_array_internal(vars, loop_body, typemap, calltypes)
   1360     for label, block in loop_body.items():
-> 1361         block.body = replace_var_with_array_in_block(vars, block, typemap, calltypes)
   1362

./numba/parfors/parfor_lowering.py in replace_var_with_array_in_block(vars, block, typemap, calltypes)
   1346
-> 1347             setitem_node = ir.SetItem(inst.target, const_var, inst.value, inst.loc)
   1348             calltypes[setitem_node] = signature(

./numba/core/ir.py in __init__(self, target, index, value, loc)
    590         assert isinstance(index, Var)
--> 591         assert isinstance(value, Var)
    592         assert isinstance(loc, Loc)

AssertionError:

```

And a related problem, in 0.48.0, the above code will work the second time it is compiled. But it would trigger the following code to fail:

```python

@njit(parallel=True)
def qdraw(tau,eta_lag,t,taus,alphas):
    sim = np.zeros(tau.shape[0])
    for i in prange(tau.shape[0]):
        j = np.searchsorted(taus,tau[i])
        j = j-1+np.abs(taus[j-1:j+1] - tau[i]).argmin() #Correction to find the nearest
        qs = alphas[j,:] @ np.array([1.0,t[i],t[i]**2,eta_lag[i]])
        sim[i] = qs
    return sim

tau = np.random.random(1)
eta_lag = np.random.random(1)
t = np.random.random(1)
taus = np.random.random(1)
alphas = np.random.random((1, 4))
qdraw(tau,eta_lag,t,taus,alphas)
```

When the first problem is resolved, we should check if the second snippet would continue to fail.

(CC @DrTodd13)


Discussion:

Resolving patch:
diff --git a/numba/parfors/parfor.py b/numba/parfors/parfor.py
--- a/numba/parfors/parfor.py
+++ b/numba/parfors/parfor.py
@@ -3517,7 +3517,7 @@ def parfor_defs(parfor, use_set=None, def_set=None):
     loop_vars |= {
         l.step.name for l in parfor.loop_nests if isinstance(
             l.step, ir.Var)}
-    use_set.update(loop_vars)
+    use_set.update(loop_vars - def_set)
     use_set |= get_parfor_pattern_vars(parfor)
 
     return analysis._use_defs_result(usemap=use_set, defmap=def_set)


Test patch:
diff --git a/numba/tests/test_parfors.py b/numba/tests/test_parfors.py
--- a/numba/tests/test_parfors.py
+++ b/numba/tests/test_parfors.py
@@ -2187,6 +2187,24 @@ def test_impl(A):
         self.prange_tester(test_impl, A, scheduler_type='unsigned',
                            check_fastmath=True, check_fastmath_result=True)
 
+    @skip_parfors_unsupported
+    def test_prange27(self):
+        # issue5597: usedef error in parfor
+        def test_impl(a, b, c):
+            for j in range(b[0]-1):
+                for k in range(2):
+                    z = np.abs(a[c-1:c+1])
+            return 0
+
+        # patch inner loop to 'prange'
+        self.prange_tester(test_impl,
+                           np.arange(20),
+                           np.asarray([4,4,4,4,4,4,4,4,4,4]),
+                           0,
+                           patch_instance=[1],
+                           scheduler_type='unsigned',
+                           check_fastmath=True)
+
     @skip_parfors_unsupported
     def test_prange_two_instances_same_reduction_var(self):
         # issue4922 - multiple uses of same reduction variable