Commit 6989e004 authored by Mark Florisson's avatar Mark Florisson Committed by Dag Sverre Seljebotn

Initiliaze private variables to maximum values or NaNs

parent 4a11afa6
......@@ -499,8 +499,19 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
#define DL_EXPORT(t) t
#endif
#ifndef PY_LONG_LONG
#ifdef PY_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
#if PY_VERSION_HEX < 0x02040000
......@@ -637,7 +648,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
#define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t
#endif
""")
""" % vars(Naming))
code.put("""
#if PY_MAJOR_VERSION >= 3
......@@ -699,10 +710,52 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("")
self.generate_extern_c_macro_definition(code)
code.putln("")
code.putln("#if defined(WIN32) || defined(MS_WINDOWS)")
code.putln("#define _USE_MATH_DEFINES")
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.api_guard_prefix + self.api_name(env))
self.generate_includes(env, cimported_modules, code)
......@@ -711,6 +764,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("#define CYTHON_WITHOUT_ASSERTIONS")
code.putln("#endif")
code.putln("")
if env.directives['ccomplex']:
code.putln("")
code.putln("#if !defined(CYTHON_CCOMPLEX)")
......
......@@ -116,5 +116,10 @@ h_guard_prefix = "__PYX_HAVE__"
api_guard_prefix = "__PYX_HAVE_API__"
api_func_guard = "__PYX_HAVE_API_FUNC_"
NAN = "__PYX_NAN"
HUGE_VAL = "Py_HUGE_VAL"
LONG_LONG_MAX = "__PYX_LONG_LONG_MAX"
ULONG_LONG_MAX = "__PYX_ULONG_LONG_MAX"
def py_version_hex(major, minor=0, micro=0, release_level=0, release_serial=0):
return (major << 24) | (minor << 16) | (micro << 8) | (release_level << 4) | (release_serial)
......@@ -6007,6 +6007,9 @@ class ParallelStatNode(StatNode, ParallelNode):
for i in prange(10, nogil=True):
var = x # error, x is private and read before assigned
x = i
Fortunately, it doesn't need to be perfect, as we still initialize
private variables to maximum values, NULL or NaN whenever possible.
"""
from Cython.Compiler import ParseTreeTransforms
......@@ -6022,6 +6025,17 @@ class ParallelStatNode(StatNode, ParallelNode):
if not op and pos < assignment_pos:
error(pos, "Private variable referenced before assignment")
def initialize_privates_to_nan(self, code, exclude=None):
code.putln("/* Initialize private variables to invalid values */")
for entry, op in self.privates.iteritems():
if not op and (not exclude or entry != exclude):
max_value = entry.type.max_value()
if max_value:
code.putln("%s = %s;" % (entry.cname,
entry.type.cast_code(max_value)))
def declare_closure_privates(self, code):
"""
Set self.privates to a dict mapping C variable names that are to be
......@@ -6075,6 +6089,7 @@ class ParallelWithBlockNode(ParallelStatNode):
code.putln("#endif /* _OPENMP */")
code.begin_block()
self.initialize_privates_to_nan(code)
self.body.generate_execution_code(code)
code.end_block()
......@@ -6334,6 +6349,9 @@ class ParallelRangeNode(ParallelStatNode):
code.put("for (%(i)s = 0; %(i)s < %(nsteps)s; %(i)s++)" % fmt_dict)
code.begin_block()
code.putln("%(target)s = %(start)s + %(step)s * %(i)s;" % fmt_dict)
self.initialize_privates_to_nan(code, exclude=self.target.entry)
self.body.generate_execution_code(code)
code.end_block()
......
......@@ -27,6 +27,12 @@ class BaseType(object):
else:
return base_code
def max_value(self):
"""
Returns the maximum or most invalid value an object of this type can
assume as a C expression string. Returns None if no such value exists.
"""
class PyrexType(BaseType):
#
# Base class for all Pyrex types.
......@@ -378,6 +384,10 @@ class PyObjectType(PyrexType):
else:
return cname
def max_value(self):
return "NULL"
class BuiltinObjectType(PyObjectType):
# objstruct_cname string Name of PyObject struct
......@@ -902,6 +912,8 @@ class CIntType(CNumericType):
def assignable_from_resolved_type(self, src_type):
return src_type.is_int or src_type.is_enum or src_type is error_type
def max_value(self):
return typename_to_maxval[rank_to_type_name[self.rank]][not self.signed]
class CAnonEnumType(CIntType):
......@@ -1109,6 +1121,8 @@ class CFloatType(CNumericType):
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
def max_value(self):
return Naming.NAN
class CComplexType(CNumericType):
......@@ -1622,6 +1636,8 @@ class CPtrType(CType):
else:
return CPtrType(base_type)
def max_value(self):
return "NULL"
class CNullPtrType(CPtrType):
......@@ -2353,6 +2369,15 @@ rank_to_type_name = (
"long double", # 7
)
typename_to_maxval = {
"char" : ("CHAR_MAX", "UCHAR_MAX"),
"short": ("SHRT_MAX", "USHRT_MAX"),
"int" : ("INT_MAX", "UINT_MAX"),
"long" : ("LONG_MAX", "ULONG_MAX"),
"PY_LONG_LONG" : (Naming.LONG_LONG_MAX, Naming.ULONG_LONG_MAX),
# CFloatType overrides max_value
}
RANK_INT = list(rank_to_type_name).index('int')
RANK_LONG = list(rank_to_type_name).index('long')
UNSIGNED = 0
......
......@@ -288,7 +288,8 @@ class CythonDotParallel(object):
__all__ = ['parallel', 'prange', 'threadid']
parallel = nogil
def parallel(self, num_threads=None):
return nogil
def prange(self, start=0, stop=None, step=1, schedule=None, nogil=False):
if stop is None:
......
......@@ -171,6 +171,53 @@ def test_pure_mode():
for i in pure_parallel.prange(4, -1, -1, schedule='dynamic', nogil=True):
print i
with pure_parallel.parallel:
with pure_parallel.parallel():
print pure_parallel.threadid()
def test_nan_init():
"""
>>> test_nan_init()
"""
cdef int mybool = 0
cdef int err = 0
cdef int *errp = &err
cdef signed char a1 = 10
cdef unsigned char a2 = 10
cdef short b1 = 10
cdef unsigned short b2 = 10
cdef int c1 = 10
cdef unsigned int c2 = 10
cdef long d1 = 10
cdef unsigned long d2 = 10
cdef long long e1 = 10
cdef unsigned long long e2 = 10
cdef float f = 10.0
cdef double g = 10.0
cdef long double h = 10.0
cdef void *p = <void *> 10
with nogil, cython.parallel.parallel():
# First, trick the error checking to make it believe these variables
# are initialized after this if
if mybool: # mybool is always false!
a1 = a2 = b1 = b2 = c1 = c2 = d1 = d2 = e1 = e2 = 0
f = g = h = 0.0
p = NULL
if (a1 == 10 or a2 == 10 or
b1 == 10 or b2 == 10 or
c1 == 10 or c2 == 10 or
d1 == 10 or d2 == 10 or
e1 == 10 or e2 == 10 or
f == 10.0 or g == 10.0 or h == 10.0 or
p != NULL):
errp[0] = 1
if err:
raise Exception("One of the values was not initiazed to a maximum "
"or NaN value")
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