Repository: Theano/Theano

Issue:
integer division regression
After commit https://github.com/Theano/Theano/commit/318dd6af2187e5afe8a4d3fe3d84385cb29cac42 which adds debug info for division by zero errors, the compilation of modules using integer division fails when using openmp backend.

Reason: 
c++ [code](https://github.com/Theano/Theano/blob/80a1e8e04f31631ae29936811f3e42d47025542b/theano/gof/cc.py#L112) chunk in theano.gof.cc.failure_code uses `goto` statement, which breaks compilation when passing `-fopenmp` flag to g++ (`theano.elemwise.Elemwise` enables this flag by default), being derived from OpenMPOp.

Code to reproduces issue:
```python
import theano
arr_shape = theano.shared(numpy.zeros((3, 3))).shape
t = arr_shape // numpy.array([2, 2], dtype=numpy.int64)
t.eval()
```

Note that the openmp code is called on array's shape, even if gpuarray backend is available, i.e., if
```python
arr_shape = K.variable(numpy.array([3, 3], dtype=numpy.int64), dtype=numpy.int64)
```
is used, instead, the crash is not reproduced.

gcc error message:
error: jump to label '__label_7' from here exits OpenMP structured block; invalid branch to/from OpenMP structured block

If more info required, please let me know.





Discussion:
thanks for the report, here is the fix:

https://github.com/Theano/Theano/pull/5876

Resolving patch:
diff --git a/theano/gof/cc.py b/theano/gof/cc.py
--- a/theano/gof/cc.py
+++ b/theano/gof/cc.py
@@ -94,22 +94,36 @@ def __init__(self, declare, behavior, cleanup, sub):
                         "\ndouble __DUMMY_%(id)i;\n" % sub)  # % sub
 
 
-def failure_code(sub):
+def failure_code(sub, use_goto=True):
     """
     Code contained in sub['fail'], usually substituted for %(fail)s.
 
     It sets information about current error, then goto the code
     actually handling the failure, which is defined in struct_gen().
 
+    Parameters
+    ----------
+    sub: dict
+        Contains other code snippets that can be substituted,
+        in particular 'failure_var' and 'id'.
+    use_goto: bool, True by default
+        Include a "goto" statement to the failure label.
+        Passing False is sometimes required, in which cases we have to
+        be careful to avoid executing incorrect code.
+
     """
+    if use_goto:
+        goto_statement = 'goto __label_%(id)i;' % sub
+    else:
+        goto_statement = ''
     return '''{
-        %(failure_var)s = %(id)s;
+        %(failure_var)s = %(id)i;
         if (!PyErr_Occurred()) {
             PyErr_SetString(PyExc_RuntimeError,
                 "Unexpected error in an Op's C code. "
                 "No Python exception was set.");
-            }
-        goto __label_%(id)i;}''' % sub
+        }
+        %(goto_statement)s}''' % dict(sub, goto_statement=goto_statement)
 
 
 def failure_code_init(sub):
diff --git a/theano/scalar/basic.py b/theano/scalar/basic.py
--- a/theano/scalar/basic.py
+++ b/theano/scalar/basic.py
@@ -1928,22 +1928,24 @@ def c_code(self, node, name, inputs, outputs, sub):
 
         t = node.inputs[0].type.upcast(*[i.type for i in node.inputs[1:]])
         if t in imap(str, discrete_types):
+            x_div_y_pp = '(%(x)s / %(y)s)' % locals()
+            x_div_y_mp = '((-%(x)s) / %(y)s)' % locals()
+            x_mod_y_mp = 'THEANO_MACRO_MOD((-%(x)s), %(y)s)' % locals()
+            x_div_y_pm = '(%(x)s / (-%(y)s))' % locals()
+            x_mod_y_pm = 'THEANO_MACRO_MOD(%(x)s, (-%(y)s))' % locals()
+            x_div_y_mm = '((-%(x)s) / (-%(y)s))' % locals()
             # If we are in a gpuarray kernel, %(fail)s exits the kernel,
             # and we do not have any error report, and we cannot set
             # Python error messages either, so for now we just call the
             # cuda function, which return a binary pattern of all 1s.
-            check = dedent('''
-                #ifndef KERNEL
+            div_zero = dedent('''
+                #ifdef KERNEL
+                    %(z)s = %(x_div_y_pp)s;
+                #else
                     PyErr_SetString(PyExc_ZeroDivisionError, "integer division by zero");
                     %(fail)s
                 #endif
                 ''') % locals()
-            x_div_y_pp = '(%(x)s / %(y)s)' % locals()
-            x_div_y_mp = '((-%(x)s) / %(y)s)' % locals()
-            x_mod_y_mp = 'THEANO_MACRO_MOD((-%(x)s), %(y)s)' % locals()
-            x_div_y_pm = '(%(x)s / (-%(y)s))' % locals()
-            x_mod_y_pm = 'THEANO_MACRO_MOD(%(x)s, (-%(y)s))' % locals()
-            x_div_y_mm = '((-%(x)s) / (-%(y)s))' % locals()
         elif t in imap(str, float_types):
             # We need to call different functions of math.h
             # depending on the type
@@ -1956,13 +1958,13 @@ def c_code(self, node, name, inputs, outputs, sub):
             else:
                 raise NotImplementedError('type not supported', t)
 
-            check = ''
             x_div_y_pp = '%(floor)s(%(x)s / %(y)s)' % locals()
             x_div_y_mp = '%(floor)s((-%(x)s) / %(y)s)' % locals()
             x_mod_y_mp = '%(fmod)s((-%(x)s), %(y)s)' % locals()
             x_div_y_pm = '%(floor)s(%(x)s / (-%(y)s))' % locals()
             x_mod_y_pm = '%(fmod)s(%(x)s, (-%(y)s))' % locals()
             x_div_y_mm = '%(floor)s((-%(x)s) / (-%(y)s))' % locals()
+            div_zero = '%(z)s = %(x_div_y_pp)s;' % locals()
         elif t in complex_types:
             raise self.complex_error
         else:
@@ -1970,8 +1972,7 @@ def c_code(self, node, name, inputs, outputs, sub):
 
         return dedent("""
             if (%(y)s == 0) {
-                %(check)s
-                %(z)s = %(x_div_y_pp)s;
+                %(div_zero)s;
             } else if (%(y)s < 0) {
                 if (%(x)s < 0) {
                     %(z)s = %(x_div_y_mm)s;
@@ -1988,7 +1989,7 @@ def c_code(self, node, name, inputs, outputs, sub):
             """) % locals()
 
     def c_code_cache_version(self):
-        return (5,)
+        return (6,)
 
     def grad(self, inputs, g_output):
         return [inp.zeros_like(dtype=theano.config.floatX)
@@ -2020,7 +2021,7 @@ def impl(self, x, y):
         return x % y
 
     def c_code_cache_version(self):
-        return (8,)
+        return (9,)
 
     def c_support_code(self):
         # We use a macro as python use % as a special string character,
@@ -2046,20 +2047,22 @@ def c_code(self, node, name, inputs, outputs, sub):
             # keep them out of safety, and verify they are useless with an
             # assert.
             assert str(t) in imap(str, discrete_types)
+            x_mod_y = "THEANO_MACRO_MOD(%(x)s, %(y)s)" % locals()
+            x_mod_ymm = "THEANO_MACRO_MOD(-%(x)s, -%(y)s)" % locals()
+            x_mod_ypm = "THEANO_MACRO_MOD(%(x)s, -%(y)s)" % locals()
+            x_mod_ymp = "THEANO_MACRO_MOD(-%(x)s, %(y)s)" % locals()
             # If we are in a gpuarray kernel, %(fail)s exits the kernel,
             # and we do not have any error report, and we cannot set
             # Python error messages either, so for now we just call the
             # cuda function, returning a binary pattern depending on dtype
-            check = dedent('''
-                #ifndef KERNEL
+            mod_zero = dedent('''
+                #ifdef KERNEL
+                    %(z)s = %(x_mod_y)s;
+                #else
                     PyErr_SetString(PyExc_ZeroDivisionError, "integer modulo by zero");
                     %(fail)s
                 #endif
                 ''') % locals()
-            x_mod_y = "THEANO_MACRO_MOD(%(x)s, %(y)s)" % locals()
-            x_mod_ymm = "THEANO_MACRO_MOD(-%(x)s, -%(y)s)" % locals()
-            x_mod_ypm = "THEANO_MACRO_MOD(%(x)s, -%(y)s)" % locals()
-            x_mod_ymp = "THEANO_MACRO_MOD(-%(x)s, %(y)s)" % locals()
         elif (str(t) in imap(str, float_types) or
               t in ['float32', 'float64'] or
               t in float_types):
@@ -2067,11 +2070,11 @@ def c_code(self, node, name, inputs, outputs, sub):
             # keep them out of safety, and verify they are useless with an
             # assert.
             assert str(t) in imap(str, float_types)
-            check = ''
             x_mod_y = "fmod(%(x)s, %(y)s)" % locals()
             x_mod_ymm = "fmod(-%(x)s, -%(y)s)" % locals()
             x_mod_ypm = "fmod(%(x)s, -%(y)s)" % locals()
             x_mod_ymp = "fmod(-%(x)s, %(y)s)" % locals()
+            mod_zero = "%(z)s = %(x_mod_y)s;" % locals()
         elif str(t) in imap(str, complex_types):
             raise self.complex_error
         else:
@@ -2079,8 +2082,7 @@ def c_code(self, node, name, inputs, outputs, sub):
 
         return dedent("""
             if (%(y)s == 0) {
-                %(check)s
-                %(z)s = %(x_mod_y)s;
+                %(mod_zero)s;
             } else if (%(y)s < 0){
                 if (%(x)s < 0){
                     %(z)s = -(%(x_mod_ymm)s);
diff --git a/theano/tensor/elemwise.py b/theano/tensor/elemwise.py
--- a/theano/tensor/elemwise.py
+++ b/theano/tensor/elemwise.py
@@ -1037,12 +1037,18 @@ def _c_all(self, node, nodename, inames, onames, sub):
         # the index of the last of these aliased outputs.
 
         # We generate the C code of the inner loop using the scalar op
+        if self.openmp:
+            # If we are using openmp, we need to get rid of the "goto"
+            # statement in sub['fail']. For now we recreate it here.
+            fail = gof.cc.failure_code(sub, use_goto=False)
+        else:
+            fail = sub['fail']
         task_code = self.scalar_op.c_code(
             node.tag.fake_node,
             nodename + '_scalar_',
             ["%s_i" % s for s in _inames],
             ["%s_i" % s for s in onames],
-            sub)
+            dict(sub, fail=fail))
         code = """
         {
             %(defines)s


Test patch: