Commit 8dcd1394 authored by Mark Florisson's avatar Mark Florisson Committed by Dag Sverre Seljebotn

Updated error messages & moved NaN to utility code

parent 6989e004
...@@ -499,19 +499,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -499,19 +499,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
#define DL_EXPORT(t) t #define DL_EXPORT(t) t
#endif #endif
#ifdef PY_LONG_LONG #ifndef PY_LONG_LONG
#define %(LONG_LONG_MAX)s PY_LLONG_MAX #define PY_LONG_LONG LONG_LONG
#define %(ULONG_LONG_MAX)s PY_ULLONG_MAX
#else
#define PY_LONG_LONG LONG_LONG
#if defined(LLONG_MAX)
#define %(LONG_LONG_MAX)s LLONG_MAX
#define %(ULONG_LONG_MAX)s ULLONG_MAX
#else
#define %(LONG_LONG_MAX)s LONG_MAX
#define %(ULONG_LONG_MAX)s ULONG_MAX
#endif
#endif #endif
#if PY_VERSION_HEX < 0x02040000 #if PY_VERSION_HEX < 0x02040000
...@@ -648,7 +637,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -648,7 +637,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
#define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t
#endif #endif
""" % vars(Naming)) """)
code.put(""" code.put("""
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
...@@ -714,47 +703,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -714,47 +703,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("#if defined(WIN32) || defined(MS_WINDOWS)") code.putln("#if defined(WIN32) || defined(MS_WINDOWS)")
code.putln("#define _USE_MATH_DEFINES") code.putln("#define _USE_MATH_DEFINES")
code.putln("#endif") code.putln("#endif")
code.putln("#include <math.h>")
code.putln("""
/* Define NAN */
#ifdef Py_NAN
#include <math.h>
#define %(pyx_nan)s Py_NAN
#else
#if defined(__GNUC__)
#define _GNU_SOURCE
#endif
#include <math.h>
#ifdef NAN
#define %(pyx_nan)s NAN
#else
#if defined(HUGE_VALL)
#define %(pyx_nan)s HUGE_VALL
#elif defined(__STDC__) && __STDC_VERSION__ >= 199901L
/* C99 or greater */
#include <float.h>
#define %(pyx_nan)s LDBL_MAX
#else
static PY_LONG_LONG __pyx__nan = PY_LLONG_MAX;
#define %(pyx_nan)s (*(double*) &__pyx__nan)
#endif
#endif
#endif
#ifdef PY_LONG_LONG
#define __PYX_LONG_LONG_MAX PY_LLONG_MAX
#define __PYX_ULONG_LONG_MAX PY_ULLONG_MAX
#elif defined(LLONG_MAX)
#define __PYX_LONG_LONG_MAX LLONG_MAX
#define __PYX_ULONG_LONG_MAX ULLONG_MAX
#else
/* This should probably suffice, even if not strictly the largest value */
#define __PYX_LONG_LONG_MAX LONG_MAX
#define __PYX_ULONG_LONG_MAX ULONG_MAX
#endif
""" % {'pyx_nan': Naming.NAN})
code.putln("#define %s" % Naming.h_guard_prefix + self.api_name(env)) code.putln("#define %s" % Naming.h_guard_prefix + self.api_name(env))
code.putln("#define %s" % Naming.api_guard_prefix + self.api_name(env)) code.putln("#define %s" % Naming.api_guard_prefix + self.api_name(env))
......
...@@ -116,7 +116,7 @@ h_guard_prefix = "__PYX_HAVE__" ...@@ -116,7 +116,7 @@ h_guard_prefix = "__PYX_HAVE__"
api_guard_prefix = "__PYX_HAVE_API__" api_guard_prefix = "__PYX_HAVE_API__"
api_func_guard = "__PYX_HAVE_API_FUNC_" api_func_guard = "__PYX_HAVE_API_FUNC_"
NAN = "__PYX_NAN" PYX_NAN = "__PYX_NAN"
HUGE_VAL = "Py_HUGE_VAL" HUGE_VAL = "Py_HUGE_VAL"
LONG_LONG_MAX = "__PYX_LONG_LONG_MAX" LONG_LONG_MAX = "__PYX_LONG_LONG_MAX"
ULONG_LONG_MAX = "__PYX_ULONG_LONG_MAX" ULONG_LONG_MAX = "__PYX_ULONG_LONG_MAX"
......
...@@ -5891,7 +5891,7 @@ class ParallelStatNode(StatNode, ParallelNode): ...@@ -5891,7 +5891,7 @@ class ParallelStatNode(StatNode, ParallelNode):
def analyse_expressions(self, env): def analyse_expressions(self, env):
self.body.analyse_expressions(env) self.body.analyse_expressions(env)
self.analyse_sharing_attributes(env) self.analyse_sharing_attributes(env)
self.check_use_unitialized_privates() self.check_independent_iterations()
def analyse_sharing_attributes(self, env): def analyse_sharing_attributes(self, env):
""" """
...@@ -5997,9 +5997,9 @@ class ParallelStatNode(StatNode, ParallelNode): ...@@ -5997,9 +5997,9 @@ class ParallelStatNode(StatNode, ParallelNode):
code.putln("%s = %s;" % (cname, entry.cname)) code.putln("%s = %s;" % (cname, entry.cname))
entry.cname = cname entry.cname = cname
def check_use_unitialized_privates(self): def check_independent_iterations(self):
""" """
This checks for uninitialized private variables, it's far from This checks for uninitialized thread-private variables, it's far from
fool-proof as it does not take control flow into account, nor fool-proof as it does not take control flow into account, nor
assignment to a variable as both the lhs and rhs. So it detects only assignment to a variable as both the lhs and rhs. So it detects only
cases like this: cases like this:
...@@ -6009,7 +6009,8 @@ class ParallelStatNode(StatNode, ParallelNode): ...@@ -6009,7 +6009,8 @@ class ParallelStatNode(StatNode, ParallelNode):
x = i x = i
Fortunately, it doesn't need to be perfect, as we still initialize Fortunately, it doesn't need to be perfect, as we still initialize
private variables to maximum values, NULL or NaN whenever possible. private variables to "invalid" values, such as NULL or NaN whenever
possible.
""" """
from Cython.Compiler import ParseTreeTransforms from Cython.Compiler import ParseTreeTransforms
...@@ -6023,18 +6024,25 @@ class ParallelStatNode(StatNode, ParallelNode): ...@@ -6023,18 +6024,25 @@ class ParallelStatNode(StatNode, ParallelNode):
# Reading reduction variables is valid (in fact necessary) # Reading reduction variables is valid (in fact necessary)
# before assignment # before assignment
if not op and pos < assignment_pos: if not op and pos < assignment_pos:
error(pos, "Private variable referenced before assignment") if self.is_prange:
error(pos, "Expression value depends on previous loop "
"iteration, cannot execute in parallel")
else:
error(pos, "Expression depends on an uninitialized "
"thread-private variable")
def initialize_privates_to_nan(self, code, exclude=None): def initialize_privates_to_nan(self, code, exclude=None):
code.putln("/* Initialize private variables to invalid values */") code.putln("/* Initialize private variables to invalid values */")
for entry, op in self.privates.iteritems(): for entry, op in self.privates.iteritems():
if not op and (not exclude or entry != exclude): if not op and (not exclude or entry != exclude):
max_value = entry.type.max_value() invalid_value = entry.type.invalid_value()
if max_value: if invalid_value:
code.globalstate.use_utility_code(
invalid_values_utility_code)
code.putln("%s = %s;" % (entry.cname, code.putln("%s = %s;" % (entry.cname,
entry.type.cast_code(max_value))) entry.type.cast_code(invalid_value)))
def declare_closure_privates(self, code): def declare_closure_privates(self, code):
""" """
...@@ -7553,3 +7561,39 @@ bad: ...@@ -7553,3 +7561,39 @@ bad:
'EMPTY_BYTES' : Naming.empty_bytes, 'EMPTY_BYTES' : Naming.empty_bytes,
"MODULE": Naming.module_cname, "MODULE": Naming.module_cname,
}) })
################ Utility code for cython.parallel stuff ################
invalid_values_utility_code = UtilityCode(proto="""
#ifdef HAVE_LONG_LONG
#define %(LONG_LONG_MAX)s PY_LLONG_MAX
#define %(ULONG_LONG_MAX)s PY_ULLONG_MAX
#else
#define PY_LONG_LONG LONG_LONG
#if defined(LLONG_MAX)
#define %(LONG_LONG_MAX)s LLONG_MAX
#define %(ULONG_LONG_MAX)s ULLONG_MAX
#else
#define %(LONG_LONG_MAX)s LONG_MAX
#define %(ULONG_LONG_MAX)s ULONG_MAX
#endif
#endif
/* Define NAN */
#ifdef Py_NAN
#define %(PYX_NAN)s Py_NAN
#elif defined(NAN)
#define %(PYX_NAN)s NAN
#elif defined(HUGE_VALL)
#define %(PYX_NAN)s HUGE_VALL
#elif defined(__STDC__) && __STDC_VERSION__ >= 199901L
/* C99 or greater */
#include <float.h>
#define %(PYX_NAN)s LDBL_MAX
#else
static PY_LONG_LONG __pyx__nan = %(LONG_LONG_MAX)s;
#define %(PYX_NAN)s (*(double*) &__pyx__nan)
#endif
""" % vars(Naming))
...@@ -27,10 +27,10 @@ class BaseType(object): ...@@ -27,10 +27,10 @@ class BaseType(object):
else: else:
return base_code return base_code
def max_value(self): def invalid_value(self):
""" """
Returns the maximum or most invalid value an object of this type can Returns the most invalid value an object of this type can assume as a
assume as a C expression string. Returns None if no such value exists. C expression string. Returns None if no such value exists.
""" """
class PyrexType(BaseType): class PyrexType(BaseType):
...@@ -384,8 +384,8 @@ class PyObjectType(PyrexType): ...@@ -384,8 +384,8 @@ class PyObjectType(PyrexType):
else: else:
return cname return cname
def max_value(self): def invalid_value(self):
return "NULL" return "1"
class BuiltinObjectType(PyObjectType): class BuiltinObjectType(PyObjectType):
...@@ -912,7 +912,7 @@ class CIntType(CNumericType): ...@@ -912,7 +912,7 @@ class CIntType(CNumericType):
def assignable_from_resolved_type(self, src_type): def assignable_from_resolved_type(self, src_type):
return src_type.is_int or src_type.is_enum or src_type is error_type return src_type.is_int or src_type.is_enum or src_type is error_type
def max_value(self): def invalid_value(self):
return typename_to_maxval[rank_to_type_name[self.rank]][not self.signed] return typename_to_maxval[rank_to_type_name[self.rank]][not self.signed]
class CAnonEnumType(CIntType): class CAnonEnumType(CIntType):
...@@ -1121,8 +1121,8 @@ class CFloatType(CNumericType): ...@@ -1121,8 +1121,8 @@ class CFloatType(CNumericType):
def assignable_from_resolved_type(self, src_type): def assignable_from_resolved_type(self, src_type):
return (src_type.is_numeric and not src_type.is_complex) or src_type is error_type return (src_type.is_numeric and not src_type.is_complex) or src_type is error_type
def max_value(self): def invalid_value(self):
return Naming.NAN return Naming.PYX_NAN
class CComplexType(CNumericType): class CComplexType(CNumericType):
...@@ -1636,8 +1636,8 @@ class CPtrType(CType): ...@@ -1636,8 +1636,8 @@ class CPtrType(CType):
else: else:
return CPtrType(base_type) return CPtrType(base_type)
def max_value(self): def invalid_value(self):
return "NULL" return "1"
class CNullPtrType(CPtrType): class CNullPtrType(CPtrType):
...@@ -2375,7 +2375,7 @@ typename_to_maxval = { ...@@ -2375,7 +2375,7 @@ typename_to_maxval = {
"int" : ("INT_MAX", "UINT_MAX"), "int" : ("INT_MAX", "UINT_MAX"),
"long" : ("LONG_MAX", "ULONG_MAX"), "long" : ("LONG_MAX", "ULONG_MAX"),
"PY_LONG_LONG" : (Naming.LONG_LONG_MAX, Naming.ULONG_LONG_MAX), "PY_LONG_LONG" : (Naming.LONG_LONG_MAX, Naming.ULONG_LONG_MAX),
# CFloatType overrides max_value # CFloatType overrides invalid_value
} }
RANK_INT = list(rank_to_type_name).index('int') RANK_INT = list(rank_to_type_name).index('int')
......
...@@ -73,7 +73,7 @@ e_cython_parallel.pyx:30:9: Can only iterate over an iteration variable ...@@ -73,7 +73,7 @@ e_cython_parallel.pyx:30:9: Can only iterate over an iteration variable
e_cython_parallel.pyx:33:10: Must be of numeric type, not int * e_cython_parallel.pyx:33:10: Must be of numeric type, not int *
e_cython_parallel.pyx:36:33: Closely nested 'with parallel:' blocks are disallowed e_cython_parallel.pyx:36:33: Closely nested 'with parallel:' blocks are disallowed
e_cython_parallel.pyx:39:12: The parallel directive must be called e_cython_parallel.pyx:39:12: The parallel directive must be called
e_cython_parallel.pyx:45:10: Private variable referenced before assignment e_cython_parallel.pyx:45:10: Expression value depends on previous loop iteration, cannot execute in parallel
e_cython_parallel.pyx:55:9: Private variable referenced before assignment e_cython_parallel.pyx:55:9: Expression depends on an uninitialized thread-private variable
e_cython_parallel.pyx:60:6: Reduction operator '*' is inconsistent with previous reduction operator '+' e_cython_parallel.pyx:60:6: Reduction operator '*' is inconsistent with previous reduction operator '+'
""" """
...@@ -214,7 +214,7 @@ def test_nan_init(): ...@@ -214,7 +214,7 @@ def test_nan_init():
d1 == 10 or d2 == 10 or d1 == 10 or d2 == 10 or
e1 == 10 or e2 == 10 or e1 == 10 or e2 == 10 or
f == 10.0 or g == 10.0 or h == 10.0 or f == 10.0 or g == 10.0 or h == 10.0 or
p != NULL): p == <void *> 10):
errp[0] = 1 errp[0] = 1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment