diff options
author | bviyer <bviyer@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-10-29 18:37:47 +0000 |
---|---|---|
committer | bviyer <bviyer@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-10-29 18:37:47 +0000 |
commit | 4710dd5101f8103638ffe082a220f701f592df36 (patch) | |
tree | 235d812c6202e962d45c0cce844b2afcc5a0596d /libcilkrts/include | |
parent | d037099fed7476ffedb6784a1f544132f258d792 (diff) | |
download | gcc-4710dd5101f8103638ffe082a220f701f592df36.tar.gz |
Added Cilk runtime library (libcilkrts) into GCC.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@204173 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libcilkrts/include')
31 files changed, 15456 insertions, 0 deletions
diff --git a/libcilkrts/include/cilk/cilk.h b/libcilkrts/include/cilk/cilk.h new file mode 100644 index 00000000000..2d0de0d293e --- /dev/null +++ b/libcilkrts/include/cilk/cilk.h @@ -0,0 +1,71 @@ +/* cilk.h -*-C++-*- + * + * @copyright + * Copyright (C) 2010-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file cilk.h + * + * @brief Provides convenient aliases for the Cilk language keywords. + * + * @details + * Since Cilk is a nonstandard extension to both C and C++, the Cilk + * language keywords all begin with “`_Cilk_`”, which guarantees that they + * will not conflict with user-defined identifiers in properly written + * programs, so that “standard” C and C++ programs can safely be + * compiled a Cilk-enabled C or C++ compiler. + * + * However, this means that the keywords _look_ like something grafted on to + * the base language. Therefore, you can include this header: + * + * #include "cilk/cilk.h" + * + * and then write the Cilk keywords with a “`cilk_`” prefix instead of + * “`_Cilk_`”. + * + * @ingroup language + */ + + +/** @defgroup language Language Keywords + * Definitions having to do with the Cilk language. + * @{ + */ + +#ifndef cilk_spawn +# define cilk_spawn _Cilk_spawn ///< Spawn a task that can execute in parallel. +# define cilk_sync _Cilk_sync ///< Wait for spawned tasks to complete. +# define cilk_for _Cilk_for ///< Execute iterations of a for loop in parallel. +#endif + +/// @} diff --git a/libcilkrts/include/cilk/cilk_api.h b/libcilkrts/include/cilk/cilk_api.h new file mode 100644 index 00000000000..a21687b7b32 --- /dev/null +++ b/libcilkrts/include/cilk/cilk_api.h @@ -0,0 +1,424 @@ +/* cilk_api.h + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file cilk_api.h + * + * @brief Defines the documented API exposed by the Cilk Plus for use + * by applications. + * + * @ingroup api + */ + +#ifndef INCLUDED_CILK_API_H +#define INCLUDED_CILK_API_H + +/** @defgroup api Runtime API + * API to allow user programs to interact with the Cilk runtime. + * @{ + */ + +#ifndef CILK_STUB /* Real (non-stub) definitions */ + +#if ! defined(__cilk) && ! defined(USE_CILK_API) +# ifdef _WIN32 +# error Cilk API is being used with non-Cilk compiler (or Cilk is disabled) +# else +# warning Cilk API is being used with non-Cilk compiler (or Cilk is disabled) +# endif +#endif + +#include <cilk/common.h> + +#ifdef __cplusplus +# include <cstddef> /* Defines size_t */ +#else +# include <stddef.h> /* Defines size_t */ +#endif + +#ifdef _WIN32 +# ifndef IN_CILK_RUNTIME +/* Ensure the library is brought if any of these functions are being called. */ +# pragma comment(lib, "cilkrts") +# endif + +# ifndef __cplusplus +# include <wchar.h> +# endif +#endif /* _WIN32 */ + +__CILKRTS_BEGIN_EXTERN_C + +/** Return values from __cilkrts_set_param() and __cilkrts_set_param_w() + */ +enum __cilkrts_set_param_status { + __CILKRTS_SET_PARAM_SUCCESS = 0, /**< Success - parameter set */ + __CILKRTS_SET_PARAM_UNIMP = 1, /**< Unimplemented parameter */ + __CILKRTS_SET_PARAM_XRANGE = 2, /**< Parameter value out of range */ + __CILKRTS_SET_PARAM_INVALID = 3, /**< Invalid parameter value */ + __CILKRTS_SET_PARAM_LATE = 4 /**< Too late to change parameter value */ +}; + +/** Set user controllable runtime parameters + * + * Call this function to set runtime parameters that control the behavior + * of the Cilk scheduler. + * + * @param param A string specifying the parameter to be set. One of: + * - `"nworkers"` + * - `"force reduce"` + * @param value A string specifying the parameter value. + * @returns A value from the @ref __cilkrts_set_param_status + * enumeration indicating the result of the operation. + * + * @par The "nworkers" parameter + * + * This parameter specifies the number of worker threads to be created by the + * Cilk runtime. @a Value must be a string of digits to be parsed by + * `strtol()`. + * + * The number of worker threads is: + * 1. the value set with `__cilkrts_set_param("nworkers")`, if it is + * positive; otherwise, + * 2. the value of the CILK_NWORKERS environment variable, if it is + * defined; otherwise + * 3. the number of cores available, as reported by the operating system. + * + * @note + * Technically, Cilk distinguishes between the _user thread_ (the thread that + * the user code was executing on when the Cilk runtime started), and + * _worker threads_ (new threads created by the Cilk runtime to support + * Cilk parallelism). `nworkers` actually includes both the user thread and + * the worker threads; that is, it is one greater than the number of true + * “worker threads”. + * + * @note + * Setting `nworkers = 1` produces serial behavior. Cilk spawns and syncs will + * be executed, but with only one worker, continuations will never be stolen, + * so all code will execute in serial. + * + * @warning + * The number of worker threads can only be set *before* the runtime has + * started. Attempting to set it when the runtime is running will have no + * effect, and will return an error code. You can call __cilkrts_end_cilk() + * to shut down the runtime to change the number of workers. + * + * @warning + * The default Cilk scheduler behavior is usually pretty good. The ability + * to override `nworkers` can be useful for experimentation, but it won’t + * usually be necessary for getting good performance. + * + * @par The "force reduce" parameter + * + * This parameter controls whether the runtime should allocate a new view + * for a reducer for every parallel strand that it is accessed on. (See + * @ref pagereducers.) @a Value must be `"1"` or `"true"` to enable the + * “force reduce” behavior, or `"0"` or `"false"` to disable it. + * + * “Force reduce” behavior will also be enabled if + * `__cilkrts_set_param("force reduce")` is not called, but the + * `CILK_FORCE_REDUCE` environment variable is defined. + * + * @warning + * When this option is enabled, `nworkers` should be set to `1`. Using “force + * reduce” with more than one worker may result in runtime errors. + * + * @warning + * Enabling this option can significantly reduce performance. It should + * _only_ be used as a debugging tool. + */ +CILK_API(int) __cilkrts_set_param(const char *param, const char *value); + +#ifdef _WIN32 +/** + * Set user controllable parameters using wide strings + * + * @note This variant of __cilkrts_set_param() is only available + * on Windows. + * + * @copydetails __cilkrts_set_param + */ +CILK_API(int) __cilkrts_set_param_w(const wchar_t *param, const wchar_t *value); +#endif + +/** Shut down and deallocate all Cilk state. The runtime will abort the + * application if Cilk is still in use by this thread. Otherwise the runtime + * will wait for all other threads using Cilk to exit. + */ +CILK_API(void) __cilkrts_end_cilk(void); + +/** Initialize the Cilk data structures and start the runtime. + */ +CILK_API(void) __cilkrts_init(void); + +/** Return the runtime `nworkers` parameter. (See the discussion of `nworkers` + * in the documentation for __cilkrts_set_param().) + */ +CILK_API(int) __cilkrts_get_nworkers(void); + +/** Return the number of thread data structures. + * + * This function returns the number of data structures that has been allocated + * allocated by the runtime to hold information about user and worker threads. + * + * If you don’t already know what this is good for, then you probably don’t + * need it. + */ +CILK_API(int) __cilkrts_get_total_workers(void); + +/** What thread is the function running on? + * + * Return a small integer identifying the current thread. Each worker thread + * started by the Cilk runtime library has a unique worker number in the range + * `1 .. nworkers - 1`. + * + * All _user_ threads (threads started by the user, or by other libraries) are + * identified as worker number 0. Therefore, the worker number is not unique + * across multiple user threads. + */ +CILK_API(int) __cilkrts_get_worker_number(void); + +/** Test whether “force reduce” behavior is enabled. + * + * @return Non-zero if force-reduce mode is on, zero if it is off. + */ +CILK_API(int) __cilkrts_get_force_reduce(void); + +/** Interact with tools + */ +CILK_API(void) + __cilkrts_metacall(unsigned int tool, unsigned int code, void *data); + +#ifdef _WIN32 +/// Windows exception description record. +typedef struct _EXCEPTION_RECORD _EXCEPTION_RECORD; + +/** Function signature for Windows exception notification callbacks. + */ +typedef void (*__cilkrts_pfn_seh_callback)(const _EXCEPTION_RECORD *exception); + +/** Specify a function to call when a non-C++ exception is caught. + * + * Cilk Plus parallelism plays nicely with C++ exception handling, but the + * Cilk Plus runtime has no way to unwind the stack across a strand boundary + * for Microsoft SEH (“Structured Exception Handling”) exceptions. Therefore, + * when the runtime catches such an exception, it must abort the application. + * + * If an SEH callback has been set, the runtime will call it before aborting. + * + * @param pfn A pointer to a callback function to be called before the + * runtime aborts the program because of an SEH exception. + */ +CILK_API(int) __cilkrts_set_seh_callback(__cilkrts_pfn_seh_callback pfn); +#endif /* _WIN32 */ + +#if __CILKRTS_ABI_VERSION >= 1 +/* Pedigree API is available only for compilers that use ABI version >= 1. */ + + +/** @name Pedigrees + */ +//@{ + +// @cond internal + +/** Support for __cilkrts_get_pedigree. + */ +CILK_API(__cilkrts_pedigree) +__cilkrts_get_pedigree_internal(__cilkrts_worker *w); + +/** Support for __cilkrts_bump_worker_rank. + */ +CILK_API(int) +__cilkrts_bump_worker_rank_internal(__cilkrts_worker* w); + +/// @endcond + + +/** Get the current pedigree, in a linked list representation. + * + * This routine returns a copy of the last node in the pedigree list. + * For example, if the current pedigree (in order) is <1, 2, 3, 4>, + * then this method returns a node with rank == 4, and whose parent + * field points to the node with rank of 3. In summary, following the + * nodes in the chain visits the terms of the pedigree in reverse. + * + * The returned node is guaranteed to be valid only until the caller + * of this routine has returned. + */ +__CILKRTS_INLINE +__cilkrts_pedigree __cilkrts_get_pedigree(void) +{ + return __cilkrts_get_pedigree_internal(__cilkrts_get_tls_worker()); +} + +/** Context used by __cilkrts_get_pedigree_info. + * + * @deprecated + * This data structure is only used by the deprecated + * __cilkrts_get_pedigree_info function. + * + * Callers should initialize the `data` array to NULL and set the `size` + * field to `sizeof(__cilkrts_pedigree_context_t)` before the first call + * to __cilkrts_get_pedigree_info(), and should not examine or modify it + * thereafter. + */ +typedef struct +{ + __STDNS size_t size; /**< Size of the struct in bytes */ + void *data[3]; /**< Opaque context data */ +} __cilkrts_pedigree_context_t; + +/** Get pedigree information. + * + * @deprecated + * Use __cilkrts_get_pedigree() instead. + * + * This routine allows code to walk up the stack of Cilk frames to gather + * the pedigree. + * + * Initialize the pedigree walk by filling the pedigree context with NULLs + * and setting the size field to sizeof(__cilkrts_pedigree_context). + * Other than initialization to NULL to start the walk, user coder should + * consider the pedigree context data opaque and should not examine or + * modify it. + * + * @returns 0 - Success - birthrank is valid + * @returns >0 - End of pedigree walk + * @returns -1 - Failure - No worker bound to thread + * @returns -2 - Failure - Sanity check failed, + * @returns -3 - Failure - Invalid context size + * @returns -4 - Failure - Internal error - walked off end of chain of frames + */ +CILK_API(int) +__cilkrts_get_pedigree_info(/* In/Out */ __cilkrts_pedigree_context_t *context, + /* Out */ uint64_t *sf_birthrank); + +/** Get the rank of the currently executing worker. + * + * @deprecated + * Use `__cilkrts_get_pedigree().rank` instead. + * + * @returns 0 - Success - *rank is valid + * @returns <0 - Failure - *rank is not changed + */ +CILK_EXPORT_AND_INLINE +int __cilkrts_get_worker_rank(uint64_t *rank) +{ + *rank = __cilkrts_get_pedigree().rank; + return 0; +} + +/** Increment the pedigree rank of the currently executing worker. + * + * @returns 0 - Success - rank was incremented + * @returns-1 - Failure + */ +CILK_EXPORT_AND_INLINE +int __cilkrts_bump_worker_rank(void) +{ + return __cilkrts_bump_worker_rank_internal(__cilkrts_get_tls_worker()); +} + +/** Increment the pedigree rank for a cilk_for loop. + * Obsolete. + * + * @deprecated + * This function was provided to allow the user to manipulate the pedigree + * rank of a `cilk_for` loop. The compiler now generates code to do that + * manipulation automatically, so this function is now unnecessary. It may + * be called, but will have no effect. + */ +CILK_EXPORT_AND_INLINE +int __cilkrts_bump_loop_rank(void) +{ + return 0; +} + +//@} + +#endif /* __CILKRTS_ABI_VERSION >= 1 */ + +__CILKRTS_END_EXTERN_C + +#else /* CILK_STUB */ + +// Programs compiled with CILK_STUB are not linked with the Cilk runtime +// library, so they should not have external references to runtime functions. +// Therefore, the functions are replaced with stubs. + +#ifdef _WIN32 +#define __cilkrts_set_param_w(name,value) ((value), 0) +#define __cilkrts_set_seh_callback(pfn) (0) +#endif +#define __cilkrts_set_param(name,value) ((value), 0) +#define __cilkrts_end_cilk() ((void) 0) +#define __cilkrts_init() ((void) 0) +#define __cilkrts_get_nworkers() (1) +#define __cilkrts_get_total_workers() (1) +#define __cilkrts_get_worker_number() (0) +#define __cilkrts_get_force_reduce() (0) +#define __cilkrts_metacall(tool,code,data) ((tool), (code), (data), 0) + +#if __CILKRTS_ABI_VERSION >= 1 +/* Pedigree stubs */ +#define __cilkrts_get_pedigree_info(context, sf_birthrank) (-1) +#define __cilkrts_get_worker_rank(rank) (*(rank) = 0) +#define __cilkrts_bump_worker_rank() (-1) +#define __cilkrts_bump_loop_rank() (-1) + +/* + * A stub method for __cilkrts_get_pedigree. + * Returns an empty __cilkrts_pedigree. + */ +__CILKRTS_INLINE +__cilkrts_pedigree __cilkrts_get_pedigree_stub(void) +{ + __cilkrts_pedigree ans; + ans.rank = 0; + ans.parent = NULL; + return ans; +} + +/* Renamed to an actual stub method. */ +#define __cilkrts_get_pedigree() __cilkrts_get_pedigree_stub() + +#endif /* __CILKRTS_ABI_VERSION >= 1 */ + +#endif /* CILK_STUB */ + +//@} + +#endif /* INCLUDED_CILK_API_H */ diff --git a/libcilkrts/include/cilk/cilk_api_linux.h b/libcilkrts/include/cilk/cilk_api_linux.h new file mode 100644 index 00000000000..ed9e70635f6 --- /dev/null +++ b/libcilkrts/include/cilk/cilk_api_linux.h @@ -0,0 +1,38 @@ +/* + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* THIS FILE IS DEPRECATED. USE cilk_api.h INSTEAD. */ +#include <cilk/cilk_api.h> diff --git a/libcilkrts/include/cilk/cilk_stub.h b/libcilkrts/include/cilk/cilk_stub.h new file mode 100644 index 00000000000..116e3ff5541 --- /dev/null +++ b/libcilkrts/include/cilk/cilk_stub.h @@ -0,0 +1,55 @@ +/* cilk_stub.h -*-C++-*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef INCLUDED_CILK_STUB_DOT_H +#define INCLUDED_CILK_STUB_DOT_H + +/* Definitions for creating a serialization from a Cilk program. + * These definitions are suitable for use by a compiler that is not + * Cilk-enabled. + */ + +/* Pretend we are a non-Cilk compiler */ +#undef __cilk +#define CILK_STUB + +/* Replace Cilk keywords with serial equivalents */ +#define _Cilk_spawn +#define _Cilk_sync +#define _Cilk_for for + +#endif /* ! defined(INCLUDED_CILK_STUB_DOT_H) */ diff --git a/libcilkrts/include/cilk/cilk_undocumented.h b/libcilkrts/include/cilk/cilk_undocumented.h new file mode 100644 index 00000000000..81cdd64bb89 --- /dev/null +++ b/libcilkrts/include/cilk/cilk_undocumented.h @@ -0,0 +1,131 @@ +/* + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + * + * cilk_undocumented.h + * + * This file defines exported functions that are not included in the standard + * documentation. + */ + +#ifndef INCLUDED_CILK_UNDOCUMENTED_H +#define INCLUDED_CILK_UNDOCUMENTED_H + +#include <cilk/common.h> + +#ifndef CILK_STUB + +__CILKRTS_BEGIN_EXTERN_C + +/* + * __cilkrts_synched + * + * Allows an application to determine if there are any outstanding children at + * this instant. This function will examine the current full frame to + * determine this. This function will return a valid result only when called + * within a spawn continuation, within the stack frame of the continuation + * itself. + */ + +CILK_EXPORT __CILKRTS_NOTHROW +int __cilkrts_synched(void); + +/* + * __cilkrts_cilkscreen_puts + * + * Allows an application to write a string to the Cilkscreen log. + * The standard error stream will be flushed after the write. + */ + +CILK_EXPORT __CILKRTS_NOTHROW +void __cilkrts_cilkscreen_puts(const char *); + +/* + * __cilkrts_get_sf + * + * A debugging aid that allows an application to get the __cilkrts_stack_frame + * for the current function. Only compiled into the DLL in debug builds. + */ + +CILK_EXPORT __CILKRTS_NOTHROW +void *__cilkrts_get_sf(void); + +/** + * Returns the size of stacks created by Cilk. + */ +CILK_EXPORT __CILKRTS_NOTHROW +size_t __cilkrts_get_stack_size(void); + +/** + * Dumps runtime statistics to stderr. + * Undocumented API for debugging. + */ +CILK_EXPORT __CILKRTS_NOTHROW +void __cilkrts_dump_stats(void); + +CILK_EXPORT __CILKRTS_NOTHROW +int __cilkrts_irml_version(void); + +struct __cilk_tbb_unwatch_thunk; +struct __cilk_tbb_stack_op_thunk; + +CILK_EXPORT __CILKRTS_NOTHROW +int __cilkrts_watch_stack(struct __cilk_tbb_unwatch_thunk *u, + struct __cilk_tbb_stack_op_thunk o); + +#ifndef IN_CILK_RUNTIME +#ifdef _WIN32 +/* Do not use CILK_API because __cilkrts_worker_stub must be __stdcall */ +CILK_EXPORT unsigned __CILKRTS_NOTHROW __stdcall +__cilkrts_worker_stub(void *arg); +#else +/* Do not use CILK_API because __cilkrts_worker_stub have default visibility */ +CILK_EXPORT void* __CILKRTS_NOTHROW +__cilkrts_worker_stub(void *arg); +#endif /* _WIN32 */ +#endif /* IN_CILK_RUNTIME */ + +__CILKRTS_END_EXTERN_C + +#else /* CILK_STUB */ + +/* Stubs for the api functions */ + +#define __cilkrts_get_stack_size() (0) +#define __cilkrts_synched() (1) + +#endif /* CILK_STUB */ + +#endif /* INCLUDED_CILK_UNDOCUMENTED_H */ diff --git a/libcilkrts/include/cilk/common.h b/libcilkrts/include/cilk/common.h new file mode 100644 index 00000000000..8ec19afa922 --- /dev/null +++ b/libcilkrts/include/cilk/common.h @@ -0,0 +1,376 @@ +/** common.h + * + * @copyright + * Copyright (C) 2010-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file common.h + * + * @brief Defines common macros and structures used by the Intel Cilk Plus + * runtime. + * + * @ingroup common + */ + +/** @defgroup common Common Definitions + * Macro, structure, and class definitions used elsewhere in the runtime. + * @{ + */ + +#ifndef INCLUDED_CILK_COMMON +#define INCLUDED_CILK_COMMON + +#ifdef __cplusplus +/** Namespace for all Cilk definitions that can be included in user code. + */ +namespace cilk { + + /** Namespace for definitions that are primarily intended for use + * in other Cilk definitions. + */ + namespace internal {} +} +#endif + +/** Cilk library version = 1.01 + */ +#define CILK_LIBRARY_VERSION 102 + +#ifdef __cplusplus +# include <cassert> +#else +# include <assert.h> +#endif + +/** + * Prefix standard library function and type names with __STDNS in order to + * get correct lookup in both C and C++. + */ +#ifdef __cplusplus +# define __STDNS std:: +#else +# define __STDNS +#endif + +/** + * @def CILK_EXPORT + * Define export of runtime functions from shared library. + * Should be exported only from cilkrts*.dll/cilkrts*.so + * @def CILK_EXPORT_DATA + * Define export of runtime data from shared library. + */ +#ifdef _WIN32 +# ifdef IN_CILK_RUNTIME +# define CILK_EXPORT __declspec(dllexport) +# define CILK_EXPORT_DATA __declspec(dllexport) +# else +# define CILK_EXPORT __declspec(dllimport) +# define CILK_EXPORT_DATA __declspec(dllimport) +# endif /* IN_CILK_RUNTIME */ +#elif defined(__CYGWIN__) || defined(__APPLE__) || defined(_DARWIN_C_SOURCE) +# define CILK_EXPORT /* nothing */ +# define CILK_EXPORT_DATA /* nothing */ +#else /* Unix/gcc */ +# ifdef IN_CILK_RUNTIME +# define CILK_EXPORT __attribute__((visibility("protected"))) +# define CILK_EXPORT_DATA __attribute__((visibility("protected"))) +# else +# define CILK_EXPORT /* nothing */ +# define CILK_EXPORT_DATA /* nothing */ +# endif /* IN_CILK_RUNTIME */ +#endif /* Unix/gcc */ + +/** + * @def __CILKRTS_BEGIN_EXTERN_C + * Macro to denote the start of a section in which all names have "C" linkage. + * That is, none of the names are to be mangled. + * @see __CILKRTS_END_EXTERN_C + * @see __CILKRTS_EXTERN_C + * + * @def __CILKRTS_END_EXTERN_C + * Macro to denote the end of a section in which all names have "C" linkage. + * That is, none of the names are to be mangled. + * @see __CILKRTS_BEGIN_EXTERN_C + * @see __CILKRTS_EXTERN_C + * + * @def __CILKRTS_EXTERN_C + * Macro to prefix a single definition which has "C" linkage. + * That is, the defined name is not to be mangled. + * @see __CILKRTS_BEGIN_EXTERN_C + * @see __CILKRTS_END_EXTERN_C + */ +#ifdef __cplusplus +# define __CILKRTS_BEGIN_EXTERN_C extern "C" { +# define __CILKRTS_END_EXTERN_C } +# define __CILKRTS_EXTERN_C extern "C" +#else +# define __CILKRTS_BEGIN_EXTERN_C +# define __CILKRTS_END_EXTERN_C +# define __CILKRTS_EXTERN_C +#endif + +/** + * OS-independent macro to specify a function which is known to not throw + * an exception. + */ +#ifdef __cplusplus +# ifdef _WIN32 +# define __CILKRTS_NOTHROW __declspec(nothrow) +# else /* Unix/gcc */ +# define __CILKRTS_NOTHROW __attribute__((nothrow)) +# endif /* Unix/gcc */ +#else +# define __CILKRTS_NOTHROW /* nothing */ +#endif /* __cplusplus */ + +/** Cache alignment. (Good enough for most architectures.) + */ +#define __CILKRTS_CACHE_LINE__ 64 + +/** + * Macro to specify alignment of a data member in a structure. + * Because of the way that gcc’s alignment attribute is defined, @a n must + * be a numeric literal, not just a compile-time constant expression. + */ +#ifdef _WIN32 +# define CILK_ALIGNAS(n) __declspec(align(n)) +#else /* Unix/gcc */ +# define CILK_ALIGNAS(n) __attribute__((__aligned__(n))) +#endif + +/** + * Macro to specify cache-line alignment of a data member in a structure. + */ +#define __CILKRTS_CACHE_ALIGN CILK_ALIGNAS(__CILKRTS_CACHE_LINE__) + +/** + * Macro to specify a class as being at least as strictly aligned as some + * type on Windows. gcc does not provide a way of doing this, so on Unix, + * this just specifies the largest natural type alignment. Put the macro + * between the `class` keyword and the class name: + * + * class CILK_ALIGNAS_TYPE(foo) bar { ... }; + */ +#ifdef _WIN32 +# define CILK_ALIGNAS_TYPE(t) __declspec(align(__alignof(t))) +#else /* Unix/gcc */ +# define CILK_ALIGNAS_TYPE(t) __attribute__((__aligned__)) +#endif + +/** + * @def CILK_API(RET_TYPE) + * A function called explicitly by the programmer. + * @def CILK_ABI(RET_TYPE) + * A function called by compiler-generated code. + * @def CILK_ABI_THROWS(RET_TYPE) + * An ABI function that may throw an exception + * + * Even when these are the same definitions, they should be separate macros so + * that they can be easily found in the code. + */ + +#ifdef _WIN32 +# define CILK_API(RET_TYPE) CILK_EXPORT RET_TYPE __CILKRTS_NOTHROW __cdecl +# define CILK_ABI(RET_TYPE) CILK_EXPORT RET_TYPE __CILKRTS_NOTHROW __cdecl +# define CILK_ABI_THROWS(RET_TYPE) CILK_EXPORT RET_TYPE __cdecl +#else +# define CILK_API(RET_TYPE) CILK_EXPORT RET_TYPE __CILKRTS_NOTHROW +# define CILK_ABI(RET_TYPE) CILK_EXPORT RET_TYPE __CILKRTS_NOTHROW +# define CILK_ABI_THROWS(RET_TYPE) CILK_EXPORT RET_TYPE +#endif + +/** + * __CILKRTS_ASSERT should be defined for debugging only, otherwise it + * interferes with vectorization. Since NDEBUG is not reliable (it must be + * set by the user), we must use a platform-specific detection of debug mode. + */ +#if defined(_WIN32) && defined(_DEBUG) + /* Windows debug */ +# define __CILKRTS_ASSERT(e) assert(e) +#elif (! defined(_WIN32)) && ! defined(__OPTIMIZE__) + /* Unix non-optimized */ +# define __CILKRTS_ASSERT(e) assert(e) +#elif defined __cplusplus + /* C++ non-debug */ +# define __CILKRTS_ASSERT(e) static_cast<void>(0) +#else + /* C non-debug */ +# define __CILKRTS_ASSERT(e) ((void) 0) +#endif + +/** + * OS-independent macro to specify a function that should be inlined + */ +#ifdef __cpluspus + // C++ +# define __CILKRTS_INLINE inline +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + // C99 +# define __CILKRTS_INLINE static inline +#elif defined(_MSC_VER) + // C89 on Windows +# define __CILKRTS_INLINE __inline +#else + // C89 on GCC-compatible systems +# define __CILKRTS_INLINE extern __inline__ +#endif + +/** + * Functions marked as CILK_EXPORT_AND_INLINE have both + * inline versions defined in the Cilk API, as well as + * non-inlined versions that are exported (for + * compatibility with previous versions that did not + * inline the functions). + */ +#ifdef COMPILING_CILK_API_FUNCTIONS +# define CILK_EXPORT_AND_INLINE CILK_EXPORT +#else +# define CILK_EXPORT_AND_INLINE __CILKRTS_INLINE +#endif + +/** + * Try to determine if compiler supports rvalue references. + */ +#if defined(__cplusplus) && !defined(__CILKRTS_RVALUE_REFERENCES) +# if __cplusplus >= 201103L // C++11 +# define __CILKRTS_RVALUE_REFERENCES 1 +# elif defined(__GXX_EXPERIMENTAL_CXX0X__) +# define __CILKRTS_RVALUE_REFERENCES 1 +# elif __cplusplus >= 199711L && __cplusplus < 201103L + // Compiler recognizes a language version prior to C++11 +# elif __INTEL_COMPILER == 1200 && defined(__STDC_HOSTED__) + // Intel compiler version 12.0 + // __cplusplus has a non-standard definition. In the absence of a + // proper definition, look for the C++0x macro, __STDC_HOSTED__. +# define __CILKRTS_RVALUE_REFERENCES 1 +# elif __INTEL_COMPILER > 1200 && defined(CHAR16T) + // Intel compiler version >= 12.1 + // __cplusplus has a non-standard definition. In the absence of a + // proper definition, look for the Intel macro, CHAR16T +# define __CILKRTS_RVALUE_REFERENCES 1 +# endif +#endif + +/* + * Include stdint.h to define the standard integer types. + * + * Unfortunately Microsoft doesn't provide stdint.h until Visual Studio 2010, + * so use our own definitions until those are available + */ + +#if ! defined(_MSC_VER) || (_MSC_VER >= 1600) +# include <stdint.h> +#else +# ifndef __MS_STDINT_TYPES_DEFINED__ +# define __MS_STDINT_TYPES_DEFINED__ + typedef signed char int8_t; + typedef short int16_t; + typedef int int32_t; + typedef __int64 int64_t; + + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + typedef unsigned __int64 uint64_t; +# endif /* __MS_STDINT_TYPES_DEFINED__ */ +#endif /* ! defined(_MSC_VER) || (_MSC_VER >= 1600) */ + +/** + * @brief Application Binary Interface version of the Cilk runtime library. + * + * The ABI version is determined by the compiler used. An object file + * compiled with a higher ABI version is not compatible with a library that is + * compiled with a lower ABI version. An object file compiled with a lower + * ABI version, however, can be used with a library compiled with a higher ABI + * version unless otherwise stated. + */ +#ifndef __CILKRTS_ABI_VERSION +# ifdef IN_CILK_RUNTIME +# define __CILKRTS_ABI_VERSION 1 +# elif __INTEL_COMPILER > 1200 + // Intel compiler version >= 12.1 +# define __CILKRTS_ABI_VERSION 1 +# else + // Compiler does not support ABI version 1 + // (Non-Intel compiler or Intel compiler prior to version 12.1). +# define __CILKRTS_ABI_VERSION 0 +# endif +#endif + +// These structs are exported because the inlining of +// the internal version of API methods require a worker +// structure as parameter. +__CILKRTS_BEGIN_EXTERN_C + /// Worker struct, exported for inlined API methods + /// @ingroup api + struct __cilkrts_worker; + + /// Worker struct, exported for inlined API methods + /// @ingroup api + typedef struct __cilkrts_worker __cilkrts_worker; + + /// Worker struct pointer, exported for inlined API methods + /// @ingroup api + typedef struct __cilkrts_worker *__cilkrts_worker_ptr; + + + /// Fetch the worker out of TLS. + CILK_ABI(__cilkrts_worker_ptr) __cilkrts_get_tls_worker(void); + + /// void *, defined to work around complaints from the compiler + /// about using __declspec(nothrow) after the "void *" return type + typedef void * __cilkrts_void_ptr; + +__CILKRTS_END_EXTERN_C + + +#if __CILKRTS_ABI_VERSION >= 1 +// Pedigree API is available only for compilers that use ABI version >= 1. + +/** Pedigree information kept in the worker and stack frame. + * @ingroup api + */ +typedef struct __cilkrts_pedigree +{ + /** Rank at start of spawn helper. Saved rank for spawning functions */ + uint64_t rank; + + /** Link to next in chain */ + const struct __cilkrts_pedigree *parent; +} __cilkrts_pedigree; + +#endif // __CILKRTS_ABI_VERSION >= 1 + +/// @} + +#endif /* INCLUDED_CILK_COMMON */ diff --git a/libcilkrts/include/cilk/holder.h b/libcilkrts/include/cilk/holder.h new file mode 100644 index 00000000000..8620c052f53 --- /dev/null +++ b/libcilkrts/include/cilk/holder.h @@ -0,0 +1,1000 @@ +/* + * @copyright + * Copyright (C) 2011-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * holder.h + * + * Purpose: hyperobject to provide different views of an object to each + * parallel strand. + */ + +#ifndef HOLDER_H_INCLUDED +#define HOLDER_H_INCLUDED + +#include <cilk/reducer.h> +#include <memory> +#include <utility> + +#ifdef __cplusplus + +/* C++ Interface + * + * Classes: holder<Type> + * + * Description: + * ============ + * This component provides a hyperobject that isolates a parallel uses of a + * common variable where it is not necessary to preserve changes from + * different parallel strands. In effect, a holder acts a bit like + * thread-local storage, but has qualities that work better with the + * fork-join structure of Cilk. In particular, a holder has the following + * qualities: + * + * - The view of a holder before the first spawn within a function is the same + * as the view after each sync (as in the case of a reducer). + * - The view of a holder within the first spawned child of a function (or the + * first child spawned after a sync) is the same as the view on entry to the + * function. + * - The view of a holder before entering a _Cilk_for loop is the same as the + * view during the first iteration of the loop and the view at the end of + * the loop. + * - The view of a holder in the continuation of a spawn or in an arbitrary + * iteration of a _Cilk_for loop is *non-deterministic*. It is generally + * recommended that the holder be explicitly put into a known state in these + * situations. + * + * A holder can be used as an alternative to parameter-passing. They are most + * useful for replacing non-local variables without massive refactoring. A + * holder takes advantage of the fact that, most of the time, a holder view + * does not change after a spawn or from one iteration of a parallel for loop + * to the next (i.e., stealing is the exception, not the rule). When the + * holder view is a large object that is expensive to construct, this + * optimization can save significant time versus creating a separate local + * object for each view. In addition, a holder using the "keep last" policy + * will have the same value after a sync as the serialization of the same + * program. The last quality will often allow the program to avoid + * recomputing a value. + * + * Usage Example: + * ============== + * Function 'compute()' is a complex function that computes a value using a + * memoized algorithm, storing intermediate results in a hash table. Compute + * calls several other functions, each of which calls several other functions, + * all of which share a global hash table. In all, there are over a dozen + * functions with a total of about 60 references to the hash table. + *.. + * hash_table<int, X> memos; + * + * void h(const X& x); // Uses memos + * + * double compute(const X& x) + * { + * memos.clear(); + * // ... + * memos[i] = x; + * ... + * g(i); // Uses memos + * // ... + * std::for_each(c.begin(), c.end(), h); // Call h for each element of c + * } + * + * int main() + * { + * const std::size_t ARRAY_SIZE = 1000000; + * extern X myArray[ARRAY_SIZE]; + * + * for (std::size_t i = 0; i < ARRAY_SIZE; ++i) + * { + * compute(myArray[i]); + * } + * } + *.. + * We would like to replace the 'for' loop in 'main' with a 'cilk_for'. + * Although the hash table is cleared on entry to each call to 'compute()', + * and although the values stored in the hash table are no longer used after + * 'compute()' returns, the use of the hash table as a global variable + * prevents 'compute()' from being called safely in parallel. One way to do + * this would be to make 'memos' a private variable within the cilk_for loop + * and pass it down to the actual computation, so that each loop iteration has + * its own private copy: + *.. + * cilk_for (std::size_t i = 0; i < ARRAY_SIZE; ++i) + * { + * hash_table<int, X> memos; + * compute(myArray[i], memos); + * } + *.. + * The problem with this approach is that it requires changing the signature + * of 'compute', 'h', 'g', and every one of the dozen or so functions that + * reference 'memos' as well as any function that calls those functions. This + * may break the abstraction of 'compute' and other functions, exposing an + * implementation detail that was not part of the interface. In addition, the + * function 'h' is called through a templated algorithm, 'for_each', which + * requires a fixed interface. Finally, there is constructor and destructor + * overhead for 'hash_table' each time through the loop. + * + * The alternative approach is to replace 'memos' with a holder. The holder + * would be available to all of the functions involved, but would not cause a + * race between parallel loop iterations. In order to make this work, each + * use of the 'memos' variable must be (mechanically) replaced by a use of the + * holder: + *.. + * cilk::holder<hash_table<int, X> > memos_h; + * + * void h(const X& x); // Uses memos_h + * + * double compute(const X& x) + * { + * memos_h().clear(); // operator() used to "dereference" the holder + * // ... + * memos_h()[i] = x; // operator() used to "dereference" the holder + * ... + * g(i); // Uses memos_h + * // ... + * std::for_each(c.begin(), c.end(), h); // Call h for each element of c + * } + *.. + * Note that each reference to the holder must be modified with an empty pair + * of parenthesis. This syntax is needed because there is no facility in C++ + * for a "smart reference" that would allow 'memos_h' to be a perfect + * replacement for 'memos'. One way that a user can avoid this syntax change + * is to wrap the holder in a class that has the same inteface as + * 'hash_table' but redirects all calls to the holder: + *.. + * template <typename K, typename V> + * class hash_table_holder + * { + * private: + * cilk::holder<hash_table<K, V> > m_holder; + * public: + * void clear() { m_holder().clear(); } + * V& operator[](const K& x) { return m_holder()[x]; } + * std::size_t size() const { return m_holder().size(); } + * // etc. ... + * }; + *.. + * Using the above wrapper, the original code can be left unchanged except for + * replacing 'hash_table' with 'hash_table_holder' and replacing 'for' with + * 'cilk_for': + *.. + * hash_table_holder<int, X> memos; + * + * void h(const X& x); // Uses memos + * + * double compute(const X& x) + * { + * memos.clear(); // Calls hash_table_holder::clear(). + * // ... + * } + *.. + * The above changes have no benefit over the use of thread-local storage. + * What if one of the functions has a 'cilk_spawn', however? + *.. + * void h(const X& x) + * { + * Y y = x.nested(); + * double d, w; + * if (y) + * { + * w = cilk_spawn compute_width(y); // May use 'memos' + * d = compute_depth(y); // Does not use 'memos' + * cilk_sync; + * compute(y); // recursive call. Uses 'memos'. + * } + * } + *.. + * In the above example, the view of the holder within 'compute_width' is the + * same as the view on entry to 'h'. More importantly, the view of the holder + * within the recursive call to 'compute' is the same as the view on entry to + * 'h', even if a different worker is executing the recursive call. Thus, the + * holder view within a Cilk program has useful qualities not found in + * thread-local storage. + */ + +namespace cilk { + + /** + * After a sync, the value stored in a holder matches the most recent + * value stored into the holder by one of the starnds entering the sync. + * The holder policy used to instantiate the holder determines which of + * the entering strands determines the final value of the holder. A policy + * of 'holder_keep_indeterminate' (the default) is the most efficient, and + * results in an indeterminate value depending on the runtime schedule + * (see below for more specifics). An indeterminate value after a sync is + * often acceptable, especially if the value of the holder is not reused + * after the sync. All of the remaining policies retain the value of the + * last strand that would be executed in the serialization of the program. + * They differ in the mechanism used to move the value from one view to + * another. A policy of 'holder_keep_last_copy' moves values by + * copy-assignment. A policy of 'holder_keep_last_swap' moves values by + * calling 'swap'. A policy of 'holder_keep_last_move' is available only + * for compilers that support C++0x rvalue references and moves values by + * move-assignment. A policy of 'holder_keep_last' attempts to choose the + * most efficient mechanism: member-function 'swap' if the view type + * supports it, otherwise move-assignment if supported, otherwise + * copy-assignment. (The swap member function for a class that provides + * one is almost always as fast or faster than move-assignment or + * copy-assignment.) + * + * The behavior of 'holder_keep_indeterminate', while indeterminate, is + * not random and can be used for advanced programming or debugging. With + * a policy of 'holder_keep_intermediate', values are never copied or + * moved between views. The value of the view after a sync is the same as + * the value set in the last spawned child before a steal occurs or the + * last value set in the continuation if no steal occurs. Using this + * knowledge, a programmer can use a holder to detect the earliest steal + * in a piece of code. An indeterminate holder is also useful for keeping + * cached data similar to the way some applications might use thread-local + * storage. + */ + enum holder_policy { + holder_keep_indeterminate, + holder_keep_last, + holder_keep_last_copy, + holder_keep_last_swap, +#ifdef __CILKRTS_RVALUE_REFERENCES + holder_keep_last_move +#endif + }; + + namespace internal { + + // Private special-case holder policy using the swap member-function + const holder_policy holder_keep_last_member_swap = + (holder_policy) (holder_keep_last_swap | 0x10); + + /* The constant, 'has_member_swap<T>::value', will be 'true' if 'T' + * has a non-static member function with prototype 'void swap(T&)'. + * The mechanism used to detect 'swap' is the most portable among + * present-day compilers, but is not the most robust. Specifically, + * the prototype for 'swap' must exactly match 'void swap(T&)'. + * Near-matches like a 'swap' function that returns 'int' instead of + * 'void' will not be detected. Detection will also fail if 'T' + * inherits 'swap' from a base class. + */ + template <typename T> + class has_member_swap + { + // This technique for detecting member functions was described by + // Rani Sharoni in comp.lang.c++.moderated: + // http://groups.google.com/group/comp.lang.c++.moderated/msg/2b06b2432fddfb60 + + // sizeof(notchar) is guaranteed larger than 1 + struct notchar { char x[2]; }; + + // Instantiationg Q<U, &U::swap> will fail unless U contains a + // non-static member with prototype 'void swap(U&)'. + template <class U, void (U::*)(U&)> struct Q { }; + + // First 'test' is preferred overload if U::swap exists with the + // correct prototype. Second 'test' is preferred overload + // otherwise. + template <typename U> static char test(Q<U,&U::swap>*); + template <typename U> static notchar test(...); + + public: + /// 'value' will be true if T has a non-static member function + /// with prototype 'void swap(T&)'. + static const bool value = (1 == sizeof(test<T>(0))); + }; + + template <typename T> const bool has_member_swap<T>::value; + + /** + * @brief Utility class for exception safety. + * + * The constuctor for this class takes a pointer and an allocator and + * holds on to them. The destructor deallocates the pointed-to + * object, without calling its destructor, typically to recover memory + * in case an exception is thrown. The release member clears the + * pointer so that the deallocation is prevented, i.e., when the + * exception danger has passed. The behavior of this class is similar + * to auto_ptr and unique_ptr. + */ + template <typename Type, typename Allocator = std::allocator<Type> > + class auto_deallocator + { + Allocator m_alloc; + Type* m_ptr; + + // Non-copiable + auto_deallocator(const auto_deallocator&); + auto_deallocator& operator=(const auto_deallocator&); + + public: + /// Constructor + explicit auto_deallocator(Type* p, const Allocator& a = Allocator()) + : m_alloc(a), m_ptr(p) { } + + /// Destructor - free allocated resources + ~auto_deallocator() { if (m_ptr) m_alloc.deallocate(m_ptr, 1); } + + /// Remove reference to resource + void release() { m_ptr = 0; } + }; + + /** + * Pure-abstract base class to initialize holder views + */ + template <typename Type, typename Allocator> + class init_base + { + public: + virtual ~init_base() { } + virtual init_base* clone_self(Allocator& a) const = 0; + virtual void delete_self(Allocator& a) = 0; + virtual void construct_view(Type* p, Allocator& a) const = 0; + }; + + /** + * Class to default-initialize a holder view + */ + template <typename Type, typename Allocator> + class default_init : public init_base<Type, Allocator> + { + typedef init_base<Type, Allocator> base; + + /// Private constructor (called from static make() function). + default_init() { } + + // Non-copiable + default_init(const default_init&); + default_init& operator=(const default_init&); + + public: + // Static factory function + static default_init* make(Allocator& a); + + // Virtual function overrides + virtual ~default_init(); + virtual base* clone_self(Allocator& a) const; + virtual void delete_self(Allocator& a); + virtual void construct_view(Type* p, Allocator& a) const; + }; + + template <typename Type, typename Allocator> + default_init<Type, Allocator>* + default_init<Type, Allocator>::make(Allocator&) + { + // Return a pointer to a singleton. All instances of this class + // are identical, so we need only one. + static default_init self; + return &self; + } + + template <typename Type, typename Allocator> + default_init<Type, Allocator>::~default_init() + { + } + + template <typename Type, typename Allocator> + init_base<Type, Allocator>* + default_init<Type, Allocator>::clone_self(Allocator& a) const + { + return make(a); + } + + template <typename Type, typename Allocator> + void default_init<Type, Allocator>::delete_self(Allocator&) + { + // Since make() returned a shared singleton, there is nothing to + // delete here. + } + + template <typename Type, typename Allocator> + void + default_init<Type, Allocator>::construct_view(Type* p, + Allocator&) const + { + ::new((void*) p) Type(); + // TBD: In a C++0x library, this should be rewritten + // std::allocator_traits<Allocator>::construct(a, p); + } + + /** + * Class to copy-construct a view from a stored exemplar. + */ + template <typename Type, typename Allocator> + class exemplar_init : public init_base<Type, Allocator> + { + typedef init_base<Type, Allocator> base; + + Type* m_exemplar; + + // Private constructors (called from make() functions). + exemplar_init(const Type& val, Allocator& a); +#ifdef __CILKRTS_RVALUE_REFERENCES + exemplar_init(Type&& val, Allocator& a); +#endif + + // Non-copyiable + exemplar_init(const exemplar_init&); + exemplar_init& operator=(const exemplar_init&); + + public: + // Static factory functions + static exemplar_init* make(const Type& val, + Allocator& a = Allocator()); +#ifdef __CILKRTS_RVALUE_REFERENCES + static exemplar_init* make(Type&& val, + Allocator& a = Allocator()); +#endif + + // Virtual function overrides + virtual ~exemplar_init(); + virtual base* clone_self(Allocator& a) const; + virtual void delete_self(Allocator& a); + virtual void construct_view(Type* p, Allocator& a) const; + }; + + template <typename Type, typename Allocator> + exemplar_init<Type, Allocator>::exemplar_init(const Type& val, + Allocator& a) + { + m_exemplar = a.allocate(1); + auto_deallocator<Type, Allocator> guard(m_exemplar, a); + a.construct(m_exemplar, val); + guard.release(); + } + +#ifdef __CILKRTS_RVALUE_REFERENCES + template <typename Type, typename Allocator> + exemplar_init<Type, Allocator>::exemplar_init(Type&& val, + Allocator& a) + { + m_exemplar = a.allocate(1); + auto_deallocator<Type, Allocator> guard(m_exemplar, a); + a.construct(m_exemplar, std::forward<Type>(val)); + guard.release(); + } +#endif + + template <typename Type, typename Allocator> + exemplar_init<Type, Allocator>* + exemplar_init<Type, Allocator>::make(const Type& val, + Allocator& a) + { + typedef typename Allocator::template rebind<exemplar_init>::other + self_alloc_t; + self_alloc_t alloc(a); + + exemplar_init *self = alloc.allocate(1); + auto_deallocator<exemplar_init, self_alloc_t> guard(self, alloc); + + // Don't use allocator to construct self. Allocator should be + // used only on elements of type 'Type'. + ::new((void*) self) exemplar_init(val, a); + + guard.release(); + + return self; + } + +#ifdef __CILKRTS_RVALUE_REFERENCES + template <typename Type, typename Allocator> + exemplar_init<Type, Allocator>* + exemplar_init<Type, Allocator>::make(Type&& val, + Allocator& a) + { + typedef typename Allocator::template rebind<exemplar_init>::other + self_alloc_t; + self_alloc_t alloc(a); + + exemplar_init *self = alloc.allocate(1); + auto_deallocator<exemplar_init, self_alloc_t> guard(self, alloc); + + // Don't use allocator to construct self. Allocator should be + // used only on elements of type 'Type'. + ::new((void*) self) exemplar_init(std::forward<Type>(val), a); + + guard.release(); + + return self; + } +#endif + + template <typename Type, typename Allocator> + exemplar_init<Type, Allocator>::~exemplar_init() + { + // Called only by delete_self, which deleted the exemplar using an + // allocator. + __CILKRTS_ASSERT(0 == m_exemplar); + } + + template <typename Type, typename Allocator> + init_base<Type, Allocator>* + exemplar_init<Type, Allocator>::clone_self(Allocator& a) const + { + return make(*m_exemplar, a); + } + + template <typename Type, typename Allocator> + void exemplar_init<Type, Allocator>::delete_self(Allocator& a) + { + typename Allocator::template rebind<exemplar_init>::other alloc(a); + + a.destroy(m_exemplar); + a.deallocate(m_exemplar, 1); + m_exemplar = 0; + + this->~exemplar_init(); + alloc.deallocate(this, 1); + } + + template <typename Type, typename Allocator> + void + exemplar_init<Type, Allocator>::construct_view(Type* p, + Allocator& a) const + { + a.construct(p, *m_exemplar); + // TBD: In a C++0x library, this should be rewritten + // std::allocator_traits<Allocator>::construct(a, p, *m_exemplar); + } + + /** + * Class to construct a view using a stored functor. The functor, + * 'f', must be be invokable using the expression 'Type x = f()'. + */ + template <typename Func, typename Allocator> + class functor_init : + public init_base<typename Allocator::value_type, Allocator> + { + typedef typename Allocator::value_type value_type; + typedef init_base<value_type, Allocator> base; + typedef typename Allocator::template rebind<Func>::other f_alloc; + + Func *m_functor; + + /// Private constructors (called from make() functions + functor_init(const Func& f, Allocator& a); +#ifdef __CILKRTS_RVALUE_REFERENCES + functor_init(Func&& f, Allocator& a); +#endif + + // Non-copiable + functor_init(const functor_init&); + functor_init& operator=(const functor_init&); + + public: + // Static factory functions + static functor_init* make(const Func& val, + Allocator& a = Allocator()); +#ifdef __CILKRTS_RVALUE_REFERENCES + static functor_init* make(Func&& val, + Allocator& a = Allocator()); +#endif + + // Virtual function overrides + virtual ~functor_init(); + virtual base* clone_self(Allocator& a) const; + virtual void delete_self(Allocator& a); + virtual void + construct_view(value_type* p, Allocator& a) const; + }; + + /// Specialization to strip off reference from 'Func&'. + template <typename Func, typename Allocator> + struct functor_init<Func&, Allocator> + : functor_init<Func, Allocator> { }; + + /// Specialization to strip off reference and cvq from 'const Func&'. + template <typename Func, typename Allocator> + struct functor_init<const Func&, Allocator> + : functor_init<Func, Allocator> { }; + + template <typename Func, typename Allocator> + functor_init<Func, Allocator>::functor_init(const Func& f, + Allocator& a) + { + f_alloc alloc(a); + + m_functor = alloc.allocate(1); + auto_deallocator<Func, f_alloc> guard(m_functor, alloc); + alloc.construct(m_functor, f); + guard.release(); + } + +#ifdef __CILKRTS_RVALUE_REFERENCES + template <typename Func, typename Allocator> + functor_init<Func, Allocator>::functor_init(Func&& f, + Allocator& a) + { + f_alloc alloc(a); + + m_functor = alloc.allocate(1); + auto_deallocator<Func, f_alloc> guard(m_functor, alloc); + alloc.construct(m_functor, std::forward<Func>(f)); + guard.release(); + } +#endif + + template <typename Func, typename Allocator> + functor_init<Func, Allocator>* + functor_init<Func, Allocator>::make(const Func& f, Allocator& a) + { + typedef typename Allocator::template rebind<functor_init>::other + self_alloc_t; + self_alloc_t alloc(a); + + functor_init *self = alloc.allocate(1); + auto_deallocator<functor_init, self_alloc_t> guard(self, alloc); + + // Don't use allocator to construct self. Allocator should be + // used only on elements of type 'Func'. + ::new((void*) self) functor_init(f, a); + + guard.release(); + + return self; + } + +#ifdef __CILKRTS_RVALUE_REFERENCES + template <typename Func, typename Allocator> + functor_init<Func, Allocator>* + functor_init<Func, Allocator>::make(Func&& f, Allocator& a) + { + typedef typename Allocator::template rebind<functor_init>::other + self_alloc_t; + self_alloc_t alloc(a); + + functor_init *self = alloc.allocate(1); + auto_deallocator<functor_init, self_alloc_t> guard(self, alloc); + + // Don't use allocator to construct self. Allocator should be + // used only on elements of type 'Func'. + ::new((void*) self) functor_init(std::forward<Func>(f), a); + + guard.release(); + + return self; + } +#endif + + template <typename Func, typename Allocator> + functor_init<Func, Allocator>::~functor_init() + { + // Called only by delete_self, which deleted the functor using an + // allocator. + __CILKRTS_ASSERT(0 == m_functor); + } + + template <typename Func, typename Allocator> + init_base<typename Allocator::value_type, Allocator>* + functor_init<Func, Allocator>::clone_self(Allocator& a) const + { + return make(*m_functor, a); + } + + template <typename Func, typename Allocator> + inline + void functor_init<Func, Allocator>::delete_self(Allocator& a) + { + typename Allocator::template rebind<functor_init>::other alloc(a); + f_alloc fa(a); + + fa.destroy(m_functor); + fa.deallocate(m_functor, 1); + m_functor = 0; + + this->~functor_init(); + alloc.deallocate(this, 1); + } + + template <typename Func, typename Allocator> + void functor_init<Func, Allocator>::construct_view(value_type* p, + Allocator& a) const + { + a.construct(p, (*m_functor)()); + // In C++0x, the above should be written + // std::allocator_traits<Allocator>::construct(a, p, m_functor()); + } + + /** + * Functor called to reduce a holder + */ + template <typename Type, holder_policy Policy> + struct holder_reduce_functor; + + /** + * Specialization to keep the left (first) value. + */ + template <typename Type> + struct holder_reduce_functor<Type, holder_keep_indeterminate> + { + void operator()(Type* left, Type* right) const { } + }; + + /** + * Specialization to copy-assign from the right (last) value. + */ + template <typename Type> + struct holder_reduce_functor<Type, holder_keep_last_copy> + { + void operator()(Type* left, Type* right) const { + *left = *right; + } + }; + + /* + * Specialization to keep the right (last) value via swap. + */ + template <typename Type> + struct holder_reduce_functor<Type, holder_keep_last_swap> + { + void operator()(Type* left, Type* right) const { + using std::swap; + swap(*left, *right); + } + }; + +#ifdef __CILKRTS_RVALUE_REFERENCES + /* + * Specialization to move-assign from the right (last) value. + */ + template <typename Type> + struct holder_reduce_functor<Type, holder_keep_last_move> + { + void operator()(Type* left, Type* right) const { + *left = std::move(*right); + } + }; +#endif + + /* + * Specialization to keep the right (last) value via the swap member + * function. + */ + template <typename Type> + struct holder_reduce_functor<Type, holder_keep_last_member_swap> + { + void operator()(Type* left, Type* right) const { + left->swap(*right); + } + }; + + /* + * Specialization to keep the right (last) value by the most efficient + * means detectable. + */ + template <typename Type> + struct holder_reduce_functor<Type, holder_keep_last> : + holder_reduce_functor<Type, + (holder_policy) + (has_member_swap<Type>::value ? + holder_keep_last_member_swap : +#ifdef __CILKRTS_RVALUE_REFERENCES + holder_keep_last_move +#else + holder_keep_last_copy +#endif + )> + { + }; + } // end namespace internal + + /** + * Monoid for holders. + * Allocator type is required to be thread-safe. + */ + template <typename Type, + holder_policy Policy = holder_keep_indeterminate, + typename Allocator = std::allocator<Type> > + class holder_monoid : public monoid_base<Type> + { + // Allocator is mutable because the copy of the monoid inside the + // reducer is const (to avoid races on the shared state). However, + // the allocator is required to be thread-safe, so it is ok (and + // necessary) to modify. + mutable Allocator m_allocator; + internal::init_base<Type, Allocator> *m_initializer; + + public: + /// This constructor uses default-initialization for both the leftmost + /// view and each identity view. + holder_monoid(const Allocator& a = Allocator()) + : m_allocator(a) + , m_initializer( + internal::default_init<Type, Allocator>::make(m_allocator)) + { } + + /// These constructors use 'val' as an exemplar to copy-construct both + /// the leftmost view and each identity view. + holder_monoid(const Type& val, const Allocator& a = Allocator()) + : m_allocator(a) + , m_initializer(internal::exemplar_init<Type, Allocator>::make( + val, m_allocator)) { } + /// This constructor uses 'f' as a functor to construct both + /// the leftmost view and each identity view. + template <typename Func> + holder_monoid(const Func& f, const Allocator& a = Allocator()) + : m_allocator(a) + , m_initializer( + internal::functor_init<Func, Allocator>::make(f,m_allocator)) + { } + + /// Copy constructor + holder_monoid(const holder_monoid& rhs) + : m_allocator(rhs.m_allocator) + , m_initializer(rhs.m_initializer->clone_self(m_allocator)) { } + + /// "Extended" copy constructor with allocator + holder_monoid(const holder_monoid& rhs, const Allocator& a) + : m_allocator(a) + , m_initializer(rhs.m_initializer->clone_self(m_allocator)) { } + +#ifdef __CILKRTS_RVALUE_REFERENCES + /// Move constructor + holder_monoid(holder_monoid&& rhs) + : m_allocator(rhs.m_allocator) + , m_initializer(rhs.m_initializer) { + rhs.m_initializer = + internal::default_init<Type, Allocator>::make(m_allocator); + } + + /// "Extended" move constructor with allocator + holder_monoid(holder_monoid&& rhs, const Allocator& a) + : m_allocator(a) + , m_initializer(0) { + if (a != rhs.m_allocator) + m_initializer = rhs.m_initializer->clone_self(a); + else { + m_initializer = rhs.m_initializer; + rhs.m_initializer = + internal::default_init<Type, Allocator>::make(m_allocator); + } + } +#endif + /// Destructor + ~holder_monoid() { m_initializer->delete_self(m_allocator); } + + holder_monoid& operator=(const holder_monoid& rhs) { + if (this == &rhs) return *this; + m_initializer->delete_self(m_allocator); + m_initializer = rhs.m_initializer->clone_self(m_allocator); + } + +#ifdef __CILKRTS_RVALUE_REFERENCES + holder_monoid& operator=(holder_monoid&& rhs) { + if (m_allocator != rhs.m_allocator) + // Delegate to copy-assignment on unequal allocators + return operator=(static_cast<const holder_monoid&>(rhs)); + std::swap(m_initializer, rhs.m_initializer); + return *this; + } +#endif + + /// Constructs IDENTITY value into the uninitilized '*p' + void identity(Type* p) const + { m_initializer->construct_view(p, m_allocator); } + + /// Calls the destructor on the object pointed-to by 'p' + void destroy(Type* p) const + { m_allocator.destroy(p); } + + /// Return a pointer to size bytes of raw memory + void* allocate(std::size_t s) const { + __CILKRTS_ASSERT(sizeof(Type) == s); + return m_allocator.allocate(1); + } + + /// Deallocate the raw memory at p + void deallocate(void* p) const { + m_allocator.deallocate(static_cast<Type*>(p), sizeof(Type)); + } + + void reduce(Type* left, Type* right) const { + internal::holder_reduce_functor<Type, Policy>()(left, right); + } + + void swap(holder_monoid& other) { + __CILKRTS_ASSERT(m_allocator == other.m_allocator); + std::swap(m_initializer, other.m_initializer); + } + + Allocator get_allocator() const { + return m_allocator; + } + }; + + // Namespace-scope swap + template <typename Type, holder_policy Policy, typename Allocator> + inline void swap(holder_monoid<Type, Policy, Allocator>& a, + holder_monoid<Type, Policy, Allocator>& b) + { + a.swap(b); + } + + /** + * Hyperobject to provide different views of an object to each + * parallel strand. + */ + template <typename Type, + holder_policy Policy = holder_keep_indeterminate, + typename Allocator = std::allocator<Type> > + class holder : public reducer<holder_monoid<Type, Policy, Allocator> > + { + typedef holder_monoid<Type, Policy, Allocator> monoid_type; + typedef reducer<monoid_type> imp; + + // Return a value of Type constructed using the functor Func. + template <typename Func> + Type make_value(const Func& f) const { + struct obj { + union { + char buf[sizeof(Type)]; + void* align1; + double align2; + }; + + obj(const Func& f) { f(static_cast<Type*>(buf)); } + ~obj() { static_cast<Type*>(buf)->~Type(); } + + operator Type&() { return *static_cast<Type*>(buf); } + }; + + return obj(f); + } + + public: + /// Default constructor uses default-initialization for both the + /// leftmost view and each identity view. + holder(const Allocator& alloc = Allocator()) + : imp(monoid_type(alloc)) { } + + /// Construct from an exemplar that is used to initialize both the + /// leftmost view and each identity view. + holder(const Type& v, const Allocator& alloc = Allocator()) + // Alas, cannot use an rvalue reference for 'v' because it is used + // twice in the same expression for initializing imp. + : imp(monoid_type(v, alloc), v) { } + + /// Construct from a functor that is used to initialize both the + /// leftmost view and each identity view. The functor, 'f', must be be + /// invokable using the expression 'Type x = f()'. + template <typename Func> + holder(const Func& f, const Allocator& alloc = Allocator()) + // Alas, cannot use an rvalue for 'f' because it is used twice in + // the same expression for initializing imp. + : imp(monoid_type(f, alloc), make_value(f)) { } + }; + +} // end namespace cilk + +#else /* C */ +# error Holders are currently available only for C++ +#endif /* __cplusplus */ + +#endif /* HOLDER_H_INCLUDED */ diff --git a/libcilkrts/include/cilk/hyperobject_base.h b/libcilkrts/include/cilk/hyperobject_base.h new file mode 100644 index 00000000000..484bf5f01ea --- /dev/null +++ b/libcilkrts/include/cilk/hyperobject_base.h @@ -0,0 +1,172 @@ +/* + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef INCLUDED_CILK_HYPEROBJECT_BASE +#define INCLUDED_CILK_HYPEROBJECT_BASE + +#ifdef __cplusplus +# include <cstdlib> +# include <cstddef> +#else +# include <stdlib.h> +# include <stddef.h> +#endif + +#include <cilk/common.h> + +#if defined _WIN32 || defined _WIN64 +# if !defined CILK_STUB && !defined IN_CILK_RUNTIME + /* bring in the Cilk library, which has definitions for some of these + * functions. */ +# pragma comment(lib, "cilkrts") +# endif +#endif + +/* The __CILKRTS_STRAND_PURE attribute tells the compiler that the value + * returned by 'func' for a given argument to 'func' will remain valid until + * the next strand boundary (spawn or sync) or until the next call to a + * function with the __CILKRTS_STRAND_STALE attribute using the same function + * argument. + */ +#if 0 && defined __cilk && (defined __GNUC__ && !defined _WIN32) && defined __cilkartsrev +# define __CILKRTS_STRAND_PURE(func) \ + func __attribute__((__cilk_hyper__("lookup"))) +# define __CILKRTS_STRAND_STALE(func) \ + func __attribute__((__cilk_hyper__("flush"))) +#else +# define __CILKRTS_STRAND_PURE(func) func +# define __CILKRTS_STRAND_STALE(func) func +#endif + +/***************************************************************************** + * C runtime interface to the hyperobject subsystem + *****************************************************************************/ + +__CILKRTS_BEGIN_EXTERN_C + +/* Callback function signatures. The 'r' argument always points to the + * reducer itself and is commonly ignored. */ +typedef void (*cilk_c_reducer_reduce_fn_t)(void* r, void* lhs, void* rhs); +typedef void (*cilk_c_reducer_identity_fn_t)(void* r, void* view); +typedef void (*cilk_c_reducer_destroy_fn_t)(void* r, void* view); +typedef void* (*cilk_c_reducer_allocate_fn_t)(void* r, __STDNS size_t bytes); +typedef void (*cilk_c_reducer_deallocate_fn_t)(void* r, void* view); + +/** Representation of the monoid */ +typedef struct cilk_c_monoid { + cilk_c_reducer_reduce_fn_t reduce_fn; + cilk_c_reducer_identity_fn_t identity_fn; + cilk_c_reducer_destroy_fn_t destroy_fn; + cilk_c_reducer_allocate_fn_t allocate_fn; + cilk_c_reducer_deallocate_fn_t deallocate_fn; +} cilk_c_monoid; + +/** Base of the hyperobject */ +typedef struct __cilkrts_hyperobject_base +{ + cilk_c_monoid __c_monoid; + unsigned long long __flags; + __STDNS ptrdiff_t __view_offset; /* offset (in bytes) to leftmost view */ + __STDNS size_t __view_size; /* Size of each view */ +} __cilkrts_hyperobject_base; + + +#ifndef CILK_STUB + +/* Library functions. */ +CILK_EXPORT + void __cilkrts_hyper_create(__cilkrts_hyperobject_base *key); +CILK_EXPORT void __CILKRTS_STRAND_STALE( + __cilkrts_hyper_destroy(__cilkrts_hyperobject_base *key)); +CILK_EXPORT void* __CILKRTS_STRAND_PURE( + __cilkrts_hyper_lookup(__cilkrts_hyperobject_base *key)); + +CILK_EXPORT + void* __cilkrts_hyperobject_alloc(void* ignore, __STDNS size_t bytes); +CILK_EXPORT + void __cilkrts_hyperobject_dealloc(void* ignore, void* view); + +/* No-op destroy function */ +CILK_EXPORT + void __cilkrts_hyperobject_noop_destroy(void* ignore, void* ignore2); + + +#else // CILK_STUB + +// Programs compiled with CILK_STUB are not linked with the Cilk runtime +// library, so they should not have external references to cilkrts functions. +// Furthermore, they don't need the hyperobject functionality, so the +// functions can be stubbed. + +#define __cilkrts_hyperobject_create __cilkrts_hyperobject_create__stub +__CILKRTS_INLINE + void __cilkrts_hyper_create(__cilkrts_hyperobject_base *key) + {} + +#define __cilkrts_hyperobject_destroy __cilkrts_hyperobject_destroy__stub +__CILKRTS_INLINE + void __cilkrts_hyper_destroy(__cilkrts_hyperobject_base *key) + {} + +#define __cilkrts_hyperobject_lookup __cilkrts_hyperobject_lookup__stub +__CILKRTS_INLINE + void* __cilkrts_hyper_lookup(__cilkrts_hyperobject_base *key) + { return (char*)(key) + key->__view_offset; } + +// Pointers to these functions are stored into monoids, so real functions +// are needed. + +#define __cilkrts_hyperobject_alloc __cilkrts_hyperobject_alloc__stub +__CILKRTS_INLINE + void* __cilkrts_hyperobject_alloc(void* ignore, __STDNS size_t bytes) + { assert(0); return __STDNS malloc(bytes); } + +#define __cilkrts_hyperobject_dealloc __cilkrts_hyperobject_dealloc__stub +__CILKRTS_INLINE + void __cilkrts_hyperobject_dealloc(void* ignore, void* view) + { assert(0); __STDNS free(view); } + +#define __cilkrts_hyperobject_noop_destroy \ + __cilkrts_hyperobject_noop_destroy__stub +__CILKRTS_INLINE + void __cilkrts_hyperobject_noop_destroy(void* ignore, void* ignore2) + {} + +#endif + +__CILKRTS_END_EXTERN_C + +#endif /* INCLUDED_CILK_HYPEROBJECT_BASE */ diff --git a/libcilkrts/include/cilk/metaprogramming.h b/libcilkrts/include/cilk/metaprogramming.h new file mode 100644 index 00000000000..5f6f29df87b --- /dev/null +++ b/libcilkrts/include/cilk/metaprogramming.h @@ -0,0 +1,606 @@ +/* metaprogramming.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2012-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file metaprogramming.h + * + * @brief Defines metaprogramming utility classes used in the Cilk library. + * + * @ingroup common + */ + +#ifndef METAPROGRAMMING_H_INCLUDED +#define METAPROGRAMMING_H_INCLUDED + +#ifdef __cplusplus + +#include <functional> +#include <new> +#include <cstdlib> +#ifdef _WIN32 +#include <malloc.h> +#endif +#include <algorithm> + +namespace cilk { + +namespace internal { + +/** Test if a class is empty. + * + * If @a Class is an empty (and therefore necessarily stateless) class, then + * the “empty base-class optimization” guarantees that + * `sizeof(check_for_empty_class<Class>) == sizeof(char)`. Conversely, if + * `sizeof(check_for_empty_class<Class>) > sizeof(char)`, then @a Class is not + * empty, and we must discriminate distinct instances of @a Class. + * + * Typical usage: + * + * // General definition of A<B> for non-empty B: + * template <typename B, bool BIsEmpty = class_is_empty<B>::value> > + * class A { ... }; + * + * // Specialized definition of A<B> for empty B: + * template <typename B> + * class A<B, true> { ... }; + * + * @tparam Class The class to be tested for emptiness. + * + * @result The `value` member will be `true` if @a Class is empty, + * `false` otherwise. + * + * @ingroup common + */ +template <class Class> +class class_is_empty { + class check_for_empty_class : public Class + { + char m_data; + public: + // Declared but not defined + check_for_empty_class(); + check_for_empty_class(const check_for_empty_class&); + check_for_empty_class& operator=(const check_for_empty_class&); + ~check_for_empty_class(); + }; +public: + + /** Constant is true if and only if @a Class is empty. + */ + static const bool value = (sizeof(check_for_empty_class) == sizeof(char)); +}; + + +/** Get the alignment of a type. + * + * For example: + * + * align_of<double>::value == 8 + * + * @tparam Tp The type whose alignment is to be computed. + * + * @result The `value` member of an instantiation of this class template + * will hold the integral alignment requirement of @a Tp. + * + * @pre @a Tp shall be a complete type. + * + * @ingroup common + */ +template <typename Tp> +struct align_of +{ +private: + struct imp { + char m_padding; + Tp m_val; + + // The following declarations exist to suppress compiler-generated + // definitions, in case @a Tp does not have a public default + // constructor, copy constructor, or destructor. + imp(const imp&); // Declared but not defined + ~imp(); // Declared but not defined + }; + +public: + /// The integral alignment requirement of @a Tp. + static const std::size_t value = (sizeof(imp) - sizeof(Tp)); +}; + + +/** A class containing raw bytes with a specified alignment and size. + * + * An object of type `aligned_storage<S, A>` will have alignment `A` and + * size at least `S`. Its contents will be uninitialized bytes. + * + * @tparam Size The required minimum size of the resulting class. + * @tparam Alignment The required alignment of the resulting class. + * + * @pre @a Alignment shall be a power of 2 no greater then 64. + * + * @note This is implemented using the `CILK_ALIGNAS` macro, which uses + * the non-standard, implementation-specific features + * `__declspec(align(N))` on Windows, and + * `__attribute__((__aligned__(N)))` on Unix. The `gcc` implementation + * of `__attribute__((__aligned__(N)))` requires a numeric literal `N` + * (_not_ an arbitrary compile-time constant expression). Therefore, + * this class is implemented using specialization on the required + * alignment. + * + * @note The template class is specialized only for the supported + * alignments. An attempt to instantiate it for an unsupported + * alignment will result in a compilation error. + */ +template <std::size_t Size, std::size_t Alignment> +struct aligned_storage; + +template<std::size_t Size> class aligned_storage<Size, 1> + { CILK_ALIGNAS( 1) char m_bytes[Size]; }; +template<std::size_t Size> class aligned_storage<Size, 2> + { CILK_ALIGNAS( 2) char m_bytes[Size]; }; +template<std::size_t Size> class aligned_storage<Size, 4> + { CILK_ALIGNAS( 4) char m_bytes[Size]; }; +template<std::size_t Size> class aligned_storage<Size, 8> + { CILK_ALIGNAS( 8) char m_bytes[Size]; }; +template<std::size_t Size> class aligned_storage<Size, 16> + { CILK_ALIGNAS(16) char m_bytes[Size]; }; +template<std::size_t Size> class aligned_storage<Size, 32> + { CILK_ALIGNAS(32) char m_bytes[Size]; }; +template<std::size_t Size> class aligned_storage<Size, 64> + { CILK_ALIGNAS(64) char m_bytes[Size]; }; + + +/** A buffer of uninitialized bytes with the same size and alignment as a + * specified type. + * + * The class `storage_for_object<Type>` will have the same size and alignment + * properties as `Type`, but it will contain only raw (uninitialized) bytes. + * This allows the definition of a data member which can contain a `Type` + * object which is initialized explicitly under program control, rather + * than implicitly as part of the initialization of the containing class. + * For example: + * + * class C { + * storage_for_object<MemberClass> _member; + * public: + * C() ... // Does NOT initialize _member + * void initialize(args) + * { new (_member.pointer()) MemberClass(args); } + * const MemberClass& member() const { return _member.object(); } + * MemberClass& member() { return _member.object(); } + * + * @tparam Type The type whose size and alignment are to be reflected + * by this class. + */ +template <typename Type> +class storage_for_object : + aligned_storage< sizeof(Type), align_of<Type>::value > +{ +public: + /// Return a typed reference to the buffer. + const Type& object() const { return *reinterpret_cast<Type*>(this); } + Type& object() { return *reinterpret_cast<Type*>(this); } +}; + + +/** Get the functor class corresponding to a binary function type. + * + * The `binary_functor` template class class can be instantiated with a binary + * functor class or with a real binary function, and will yield an equivalent + * binary functor class class in either case. + * + * @tparam F A binary functor class, a binary function type, or a pointer to + * binary function type. + * + * @result `binary_functor<F>::%type` will be the same as @a F if @a F is + * a class. It will be a `std::pointer_to_binary_function` wrapper + * if @a F is a binary function or binary function pointer type. + * (It will _not_ necessarily be an `Adaptable Binary Function` + * class, since @a F might be a non-adaptable binary functor + * class.) + * + * @ingroup common + */ +template <typename F> +struct binary_functor { + /// The binary functor class equivalent to @a F. + typedef F type; +}; + +/// @copydoc binary_functor +/// Specialization for binary function. +template <typename R, typename A, typename B> +struct binary_functor<R(A,B)> { + /// The binary functor class equivalent to @a F. + typedef std::pointer_to_binary_function<A, B, R> type; +}; + +/// @copydoc binary_functor +/// Specialization for pointer to binary function. +template <typename R, typename A, typename B> +struct binary_functor<R(*)(A,B)> { + /// The binary functor class equivalent to @a F. + typedef std::pointer_to_binary_function<A, B, R> type; +}; + + +/** Indirect binary function class with specified types. + * + * `typed_indirect_binary_function<F>` is an `Adaptable Binary Function` class + * based on an existing binary functor class or binary function type @a F. If + * @a F is a stateless class, then this class will be empty, and its + * `operator()` will invoke @a F’s `operator()`. Otherwise, an object of this + * class will hold a pointer to an object of type @a F, and will refer its + * `operator()` calls to the pointed-to @a F object. + * + * That is, suppose that we have the declarations: + * + * F *p; + * typed_indirect_binary_function<F, int, int, bool> ibf(p); + * + * Then: + * + * - `ibf(x, y) == (*p)(x, y)`. + * - `ibf(x, y)` will not do a pointer dereference if `F` is an empty class. + * + * @note Just to repeat: if `F` is an empty class, then + * `typed_indirect_binary_function\<F\>' is also an empty class. + * This is critical for its use in the @ref min_max::view_base + * "min/max reducer view classes", where it allows the view to + * call a comparison functor in the monoid without actually + * having to allocate a pointer in the view class when the + * comparison class is empty. + * + * @note If you have an `Adaptable Binary Function` class or a binary + * function type, then you can use the + * @ref indirect_binary_function class, which derives the + * argument and result types parameter type instead of requiring + * you to specify them as template arguments. + * + * @tparam F A binary functor class, a binary function type, or a pointer to + * binary function type. + * @param A1 The first argument type. + * @param A2 The second argument type. + * @param R The result type. + * + * @see min_max::comparator_base + * @see indirect_binary_function + * + * @ingroup common + */ +template < typename F + , typename A1 + , typename A2 + , typename R + , typename Functor = typename binary_functor<F>::type + , bool FunctorIsEmpty = class_is_empty<Functor>::value + > +class typed_indirect_binary_function : std::binary_function<A1, A2, R> +{ + const F* f; +public: + /// Constructor captures a pointer to the wrapped function. + typed_indirect_binary_function(const F* f) : f(f) {} + + /// Return the comparator pointer, or `NULL` if the comparator is stateless. + const F* pointer() const { return f; } + + /// Apply the pointed-to functor to the arguments. + R operator()(const A1& a1, const A2& a2) const { return (*f)(a1, a2); } +}; + + +/// @copydoc typed_indirect_binary_function +/// Specialization for an empty functor class. (This is only possible if @a F +/// itself is an empty class. If @a F is a function or pointer-to-function +/// type, then the functor will contain a pointer.) +template <typename F, typename A1, typename A2, typename R, typename Functor> +class typed_indirect_binary_function<F, A1, A2, R, Functor, true> : + std::binary_function<A1, A2, R> +{ +public: + /// Return `NULL` for the comparator pointer of a stateless comparator. + const F* pointer() const { return 0; } + + /// Constructor discards the pointer to a stateless functor class. + typed_indirect_binary_function(const F* f) {} + + /// Create an instance of the stateless functor class and apply it to the arguments. + R operator()(const A1& a1, const A2& a2) const { return F()(a1, a2); } +}; + + +/** Indirect binary function class with inferred types. + * + * This is identical to @ref typed_indirect_binary_function, except that it + * derives the binary function argument and result types from the parameter + * type @a F instead of taking them as additional template parameters. If @a F + * is a class type, then it must be an `Adaptable Binary Function`. + * + * @see typed_indirect_binary_function + * + * @ingroup common + */ +template <typename F, typename Functor = typename binary_functor<F>::type> +class indirect_binary_function : + typed_indirect_binary_function< F + , typename Functor::first_argument_type + , typename Functor::second_argument_type + , typename Functor::result_type + > +{ + typedef typed_indirect_binary_function< F + , typename Functor::first_argument_type + , typename Functor::second_argument_type + , typename Functor::result_type + > + base; +public: + indirect_binary_function(const F* f) : base(f) {} ///< Constructor +}; + + +/** Choose a type based on a boolean constant. + * + * This metafunction is identical to C++11’s condition metafunction. + * It needs to be here until we can reasonably assume that users will be + * compiling with C++11. + * + * @tparam Cond A boolean constant. + * @tparam IfTrue A type. + * @tparam IfFalse A type. + * @result The `type` member will be a typedef of @a IfTrue if @a Cond + * is true, and a typedef of @a IfFalse if @a Cond is false. + * + * @ingroup common + */ +template <bool Cond, typename IfTrue, typename IfFalse> +struct condition +{ + typedef IfTrue type; ///< The type selected by the condition. +}; + +/// @copydoc condition +/// Specialization for @a Cond == `false`. +template <typename IfTrue, typename IfFalse> +struct condition<false, IfTrue, IfFalse> +{ + typedef IfFalse type; ///< The type selected by the condition. +}; + + +/** @def __CILKRTS_STATIC_ASSERT + * + * @brief Compile-time assertion. + * + * Causes a compilation error if a compile-time constant expression is false. + * + * @par Usage example. + * This assertion is used in reducer_min_max.h to avoid defining + * legacy reducer classes that would not be binary-compatible with the + * same classes compiled with earlier versions of the reducer library. + * + * __CILKRTS_STATIC_ASSERT( + * internal::class_is_empty< internal::binary_functor<Compare> >::value, + * "cilk::reducer_max<Value, Compare> only works with an empty Compare class"); + * + * @note In a C++11 compiler, this is just the language predefined + * `static_assert` macro. + * + * @note In a non-C++11 compiler, the @a Msg string is not directly included + * in the compiler error message, but it may appear if the compiler + * prints the source line that the error occurred on. + * + * @param Cond The expression to test. + * @param Msg A string explaining the failure. + * + * @ingroup common + */ +#if defined(__INTEL_CXX11_MODE__) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define __CILKRTS_STATIC_ASSERT(Cond, Msg) static_assert(Cond, Msg) +#else +# define __CILKRTS_STATIC_ASSERT(Cond, Msg) \ + typedef int __CILKRTS_STATIC_ASSERT_DUMMY_TYPE \ + [::cilk::internal::static_assert_failure<(Cond)>::Success] + +/// @cond internal + template <bool> struct static_assert_failure { }; + template <> struct static_assert_failure<true> { enum { Success = 1 }; }; + +# define __CILKRTS_STATIC_ASSERT_DUMMY_TYPE \ + __CILKRTS_STATIC_ASSERT_DUMMY_TYPE1(__cilkrts_static_assert_, __LINE__) +# define __CILKRTS_STATIC_ASSERT_DUMMY_TYPE1(a, b) \ + __CILKRTS_STATIC_ASSERT_DUMMY_TYPE2(a, b) +# define __CILKRTS_STATIC_ASSERT_DUMMY_TYPE2(a, b) a ## b +/// @endcond + +#endif + +/// @cond internal + +/** @name Aligned heap management. + */ +//@{ + +/** Implementation-specific aligned memory allocation function. + * + * @param size The minimum number of bytes to allocate. + * @param alignment The required alignment (must be a power of 2). + * @return The address of a block of memory of at least @a size + * bytes. The address will be a multiple of @a alignment. + * `NULL` if the allocation fails. + * + * @see deallocate_aligned() + */ +inline void* allocate_aligned(std::size_t size, std::size_t alignment) +{ +#ifdef _WIN32 + return _aligned_malloc(size, alignment); +#else +#if defined(ANDROID) || defined(__ANDROID__) + return memalign(std::max(alignment, sizeof(void*)), size); +#else + void* ptr; + return (posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size) == 0) ? ptr : 0; +#endif +#endif +} + +/** Implementation-specific aligned memory deallocation function. + * + * @param ptr A pointer which was returned by a call to alloc_aligned(). + */ +inline void deallocate_aligned(void* ptr) +{ +#ifdef _WIN32 + _aligned_free(ptr); +#else + std::free(ptr); +#endif +} + +/** Class to allocate and guard an aligned pointer. + * + * A new_aligned_pointer object allocates aligned heap-allocated memory when + * it is created, and automatically deallocates it when it is destroyed + * unless its `ok()` function is called. + * + * @tparam T The type of the object to allocate on the heap. The allocated + * will have the size and alignment of an object of type T. + */ +template <typename T> +class new_aligned_pointer { + void* m_ptr; +public: + /// Constructor allocates the pointer. + new_aligned_pointer() : + m_ptr(allocate_aligned(sizeof(T), internal::align_of<T>::value)) {} + /// Destructor deallocates the pointer. + ~new_aligned_pointer() { if (m_ptr) deallocate_aligned(m_ptr); } + /// Get the pointer. + operator void*() { return m_ptr; } + /// Return the pointer and release the guard. + T* ok() { + T* ptr = static_cast<T*>(m_ptr); + m_ptr = 0; + return ptr; + } +}; + +//@} + +/// @endcond + +} // namespace internal + +//@{ + +/** Allocate an aligned data structure on the heap. + * + * `cilk::aligned_new<T>([args])` is equivalent to `new T([args])`, except + * that it guarantees that the returned pointer will be at least as aligned + * as the alignment requirements of type `T`. + * + * @ingroup common + */ +template <typename T> +T* aligned_new() +{ + internal::new_aligned_pointer<T> ptr; + new (ptr) T(); + return ptr.ok(); +} + +template <typename T, typename T1> +T* aligned_new(const T1& x1) +{ + internal::new_aligned_pointer<T> ptr; + new (ptr) T(x1); + return ptr.ok(); +} + +template <typename T, typename T1, typename T2> +T* aligned_new(const T1& x1, const T2& x2) +{ + internal::new_aligned_pointer<T> ptr; + new (ptr) T(x1, x2); + return ptr.ok(); +} + +template <typename T, typename T1, typename T2, typename T3> +T* aligned_new(const T1& x1, const T2& x2, const T3& x3) +{ + internal::new_aligned_pointer<T> ptr; + new (ptr) T(x1, x2, x3); + return ptr.ok(); +} + +template <typename T, typename T1, typename T2, typename T3, typename T4> +T* aligned_new(const T1& x1, const T2& x2, const T3& x3, const T4& x4) +{ + internal::new_aligned_pointer<T> ptr; + new (ptr) T(x1, x2, x3, x4); + return ptr.ok(); +} + +template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5> +T* aligned_new(const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5) +{ + internal::new_aligned_pointer<T> ptr; + new (ptr) T(x1, x2, x3, x4, x5); + return ptr.ok(); +} + +//@} + + +/** Deallocate an aligned data structure on the heap. + * + * `cilk::aligned_delete(ptr)` is equivalent to `delete ptr`, except that it + * operates on a pointer that was allocated by aligned_new(). + * + * @ingroup common + */ +template <typename T> +void aligned_delete(const T* ptr) +{ + ptr->~T(); + internal::deallocate_aligned((void*)ptr); +} + +} // namespace cilk + +#endif // __cplusplus + +#endif // METAPROGRAMMING_H_INCLUDED diff --git a/libcilkrts/include/cilk/reducer.h b/libcilkrts/include/cilk/reducer.h new file mode 100644 index 00000000000..a22651e1e6f --- /dev/null +++ b/libcilkrts/include/cilk/reducer.h @@ -0,0 +1,1900 @@ +/* reducer.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer.h + * + * @brief Defines foundation classes for creating Cilk reducers. + * + * @ingroup Reducers + * + * @see @ref pagereducers + * + * @defgroup Reducers Reducers + */ + +#ifndef REDUCER_H_INCLUDED +#define REDUCER_H_INCLUDED + +#include "cilk/hyperobject_base.h" +#include "cilk/metaprogramming.h" + +#ifdef __cplusplus + +//===================== C++ interfaces =================================== + +#include <new> + +namespace cilk { + +/** Base class for defining monoids. + * + * The monoid_base class template is useful for creating classes that model + * the monoid concept. It provides the core type and memory management + * functionality. A subclass of monoid_base need only declare and implement + * the `identity` and `reduce` functions. + * + * The monoid_base class also manages the integration between the monoid, the + * reducer class that is based on it, and an optional view class which wraps + * value objects and restricts access to their operations. + * + * @tparam Value The value type for the monoid. + * @tparam View An optional view class that serves as a proxy for the value + * type. + * + * @see monoid_with_view + */ +template <typename Value, typename View = Value> +class monoid_base +{ +protected: + + /** Class for provisionally constructed objects. + * + * The monoid_base::construct() functions manually construct both a monoid + * and a view. If one of these is constructed successfully, and the + * construction of the other (or some other initialization) fails, then + * the first one must be destroyed to avoid a memory leak. Because the + * construction is explicit, the destruction must be explicit, too. + * + * A provisional_guard object wraps a pointer to a newly constructed + * object. A call to its confirm() function confirms that the object is + * really going to be used. If the guard is destroyed without being + * confirmed, then the pointed-to object is destroyed (but not + * deallocated). + * + * Expected usage: + * + * provisional_guard<T1> x1_provisional( new (x1) T1() ); + * … more initialization … + * x1_provisional.confirm(); + * + * or + * + * provisional_guard<T1> x1_provisional( new (x1) T1() ); + * x1_provisional.confirm_if( new (x2) T2() ); + * + * If an exception is thrown in the “more initialization” code in the + * first example, or in the `T2` constructor in the second example, then + * `x1_provisional` will not be confirmed, so when its destructor is + * called during exception unwinding, the `T1` object that was constructed + * in `x1` will be destroyed. + * + * @see provisional() + * + * @tparam Type The type of the provisionally constructed object. + */ + template <typename Type> + class provisional_guard { + Type* m_ptr; + + public: + + /** Constructor. Creates a guard for a provisionally constructed object. + * + * @param ptr A pointer to the provisionally constructed object. + */ + provisional_guard(Type* ptr) : m_ptr(ptr) {} + + /** Destructor. Destroy the object pointed to by the contained pointer + * if it has not been confirmed. + */ + ~provisional_guard() { if (m_ptr) m_ptr->~Type(); } + + /** Confirm the provisional construction. Do *not* delete the contained + * pointer when the guard is destroyed. + */ + void confirm() { m_ptr = 0; } + + /** Confirm provisional construction if argument is non-null. Note that + * if an exception is thrown during evaluation of the argument + * expression, then this function will not be called, and the + * provisional object will not be confirmed. This allows the usage: + * + * x1_provisional.confirm_if( new (x2) T2() ); + * + * @param cond An arbitrary pointer. The provisional object will be + * confirmed if @a cond is not null. + * + * @returns The value of the @a cond argument. + */ + template <typename Cond> + Cond* confirm_if(Cond* cond) { if (cond) m_ptr = 0; return cond; } + }; + + + /** Create a provisional_guard object. This function allows simpler code + * when the only use of a provisional_guard is in a + * provisional_guard::confirm_if() call immediately following its + * creation. Instead of + * + * provisional_guard<T>guard( new (ptr_to_T) T() ); + * guard.confirm_if( new (ptr_to_U) U() ); + * + * you can just write + * + * provisional( new (ptr_to_T) T() ).confirm_if( new (ptr_to_U) U() ); + * + * @tparam Type The type of the provisionally constructed object. + * + * @param ptr A pointer to a provisionally constructed object. + * + * @returns A @ref provisional_guard object that guards the + * provisionally constructed object pointed to by @a ptr. + */ + template <typename Type> + static provisional_guard<Type> provisional(Type* ptr) + { return provisional_guard<Type>(ptr); } + +public: + + /** Value type of the monoid. + */ + typedef Value value_type; + + /** View type of the monoid. Defaults to be the same as the value type. + * @see monoid_with_view + */ + typedef View view_type; + + enum { + /** Should reducers created with this monoid be aligned? + * + * @details + * “Aligned” means that the view is allocated at a cache-line aligned + * offset in the reducer, and the reducer must be cache-line aligned. + * “Unaligned” means that the reducer as a whole is just naturally + * aligned, but it contains a large enough block of uninitialized + * storage for a cache-line aligned view to be allocated in it at + * reducer construction time. + * + * Since the standard heap allocator (new reducer) does not allocate + * cache-line aligned storage, only unaligned reducers can be safely + * allocated on the heap. + * + * Default is false (unaligned) unless overridden in a subclass. + * + * @since 1.02 + * (In Cilk library versions 1.0 and 1.01, the default was true. + * In Cilk library versions prior to 1.0, reducers were always aligned, + * and this data member did not exist.) + */ + align_reducer = false + }; + + /** Destroy a view. Destroys (without deallocating) the @a View object + * pointed to by @a p. + * + * @param p The address of the @a View object to be destroyed. + */ + void destroy(view_type* p) const { p->~view_type(); } + + /** Allocate raw memory. Allocate @a s bytes of memory with no + * initialization. + * + * @param s The number of bytes of memory to allocate. + * @return An untyped pointer to the allocated memory. + */ + void* allocate(size_t s) const { return operator new(s); } + + /** Deallocate raw memory. Deallocates the memory pointed to by @a p + * without doing any destruction. + * + * @param p Pointer to the memory to be deallocated. + * + * @pre @a p points to a block of memory that was allocated by a + * call to allocate(). + */ + void deallocate(void* p) const { operator delete(p); } + + /** Create the identity value. Constructs (without allocating) a @a View + * object representing the default value of the @a Value type. + * + * @param p A pointer to a block of raw memory large enough to hold a + * @a View object. + * + * @post The memory pointed to by @a p contains a @a View object that + * represents the default value of the @a View type. + * + * @deprecated This function constructs the @a View object with its default + * constructor, which will often, but not always, yield the + * appropriate identity value. Monoid classes should declare + * their identity function explicitly, rather than relying on + * this default definition. + */ + void identity(View* p) const { new ((void*) p) View(); } + + + /** @name Construct the monoid and the view with arbitrary arguments. + * + * A @ref reducer object contains monoid and view data members, which are + * declared as raw storage (byte arrays), so that they are not implicitly + * constructed when the reducer is constructed. Instead, a reducer + * constructor calls one of the monoid class’s static construct() + * functions with the addresses of the monoid and the view, and the + * construct() function uses placement `new` to construct them. + * + * This allows the monoid to determine the order in which the monoid and + * view are constructed, and to make one of them dependent on the other. + * + * Any arguments to the reducer constructor are just passed on as + * additional arguments to the construct() function (after the monoid + * and view addresses). + * + * Any monoid whose needs are satisfied by the suite of construct() + * functions below, such as @ref monoid_with_view, can just inherit them + * from monoid_base. Other monoids will need to provide their own versions + * to override the monoid_base functions. + */ + //@{ + + /** Default-construct the monoid, and pass zero to five const reference + * arguments to the view constructor. + */ + //@{ + + template <typename Monoid> + static void construct(Monoid* monoid, View* view) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + (monoid->identity(view), view) ); } + + template <typename Monoid, typename T1> + static void construct(Monoid* monoid, View* view, const T1& x1) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(x1) ); } + + template <typename Monoid, typename T1, typename T2> + static void construct(Monoid* monoid, View* view, + const T1& x1, const T2& x2) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(x1, x2) ); } + + template <typename Monoid, typename T1, typename T2, typename T3> + static void construct(Monoid* monoid, View* view, + const T1& x1, const T2& x2, const T3& x3) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(x1, x2, x3) ); } + + template <typename Monoid, typename T1, typename T2, typename T3, + typename T4> + static void construct(Monoid* monoid, View* view, + const T1& x1, const T2& x2, const T3& x3, + const T4& x4) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(x1, x2, x3, x4) ); } + + template <typename Monoid, typename T1, typename T2, typename T3, + typename T4, typename T5> + static void construct(Monoid* monoid, View* view, + const T1& x1, const T2& x2, const T3& x3, + const T4& x4, const T5& x5) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(x1, x2, x3, x4, x5) ); } + + //@} + + /** Default-construct the monoid, and pass one non-const reference argument + * to the view constructor. + */ + //@{ + template <typename Monoid, typename T1> + static void construct(Monoid* monoid, View* view, T1& x1) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(x1) ); } + //@} + + /** Copy-construct the monoid, and pass zero to four const reference + * arguments to the view constructor. + */ + //@{ + + template <typename Monoid> + static void construct(Monoid* monoid, View* view, const Monoid& m) + { provisional( new ((void*)monoid) Monoid(m) ).confirm_if( + new ((void*)view) View() ); } + + template <typename Monoid, typename T1> + static void construct(Monoid* monoid, View* view, const Monoid& m, + const T1& x1) + { provisional( new ((void*)monoid) Monoid(m) ).confirm_if( + new ((void*)view) View(x1) ); } + + template <typename Monoid, typename T1, typename T2> + static void construct(Monoid* monoid, View* view, const Monoid& m, + const T1& x1, const T2& x2) + { provisional( new ((void*)monoid) Monoid(m) ).confirm_if( + new ((void*)view) View(x1, x2) ); } + + template <typename Monoid, typename T1, typename T2, typename T3> + static void construct(Monoid* monoid, View* view, const Monoid& m, + const T1& x1, const T2& x2, const T3& x3) + { + provisional( new ((void*)monoid) Monoid(m) ).confirm_if( + new ((void*)view) View(x1, x2, x3) ); + } + + template <typename Monoid, typename T1, typename T2, typename T3, + typename T4> + static void construct(Monoid* monoid, View* view, const Monoid& m, + const T1& x1, const T2& x2, const T3& x3, + const T4& x4) + { + provisional( new ((void*)monoid) Monoid(m) ).confirm_if( + new ((void*)view) View(x1, x2, x3, x4) ); + } + + //@} + + //@} +}; + + +/** Monoid class that gets its value type and identity and reduce operations + * from its view. + * + * A simple implementation of the monoid-view-reducer architecture would + * distribute knowledge about the type and operations for the reduction + * between the monoid and the view — the identity and reduction operations are + * specified in the monoid, the reduction operations are implemented in the + * view, and the value type is specified in both the monoid and the view. + * This is inelegant. + * + * monoid_with_view is a subclass of @ref monoid_base that gets its value type + * and its identity and reduction operations from its view class. No + * customization of the monoid_with_view class itself is needed beyond + * instantiating it with an appropriate view class. (Customized subclasses of + * monoid_with_view may be needed for other reasons, such as to keep some + * state for the reducer.) All of the Cilk predefined reducers use + * monoid_with_view or one of its subclasses. + * + * The view class `View` of a monoid_with_view must provide the following public definitions: + * + * Definition | Meaning + * ---------------------------------|-------- + * `value_type` | a typedef of the value type for the reduction + * `View()` | a default constructor which constructs the identity value for the reduction + * `void reduce(const View* other)` | a member function which applies the reduction operation to the values of `this` view and the `other` view, leaving the result as the value of `this` view, and leaving the value of the `other` view undefined (but valid) + * + * @tparam View The view class for the monoid. + * @tparam Align If true, reducers instantiated on this monoid will be + * cache-aligned. By default, library reducers (unlike legacy + * library reducer _wrappers_) are aligned only as required by + * contents. + */ +template <class View, bool Align = false> +class monoid_with_view : public monoid_base<typename View::value_type, View> +{ +public: + /** Should reducers created with this monoid be aligned? + */ + enum { align_reducer = Align }; + + /** Create the identity value. + * + * Implements the monoid `identity` operation by using the @a View class’s + * default constructor. + * + * @param p A pointer to a block of raw memory large enough to hold a + * @p View object. + */ + void identity(View* p) const { new ((void*)p) View(); } + + /** Reduce the values of two views. + * + * Implements the monoid `reduce` operation by calling the left view’s + * `%reduce()` function with the right view as an operand. + * + * @param left The left operand of the reduce operation. + * @param right The right operand of the reduce operation. + * @post The left view contains the result of the reduce + * operation, and the right view is undefined. + */ + void reduce(View* left, View* right) const { left->reduce(right); } +}; + + +/** Base class for simple views with (usually) scalar values. + * + * The scalar_view class is intended as a base class which provides about half + * of the required definitions for simple views. It defines the `value_type` + * required by a @ref monoid_with_view (but not the identity constructor and + * reduce operation, which are inherently specific to a particular kind of + * reduction). It also defines the value access functions which will be called + * by the corresponding @ref reducer functions. (It uses copy semantics for + * the view_move_in() and view_move_out() functions, which is appropriate + * for simple scalar types, but not necessarily for more complex types like + * STL containers. + * + * @tparam Type The type of value wrapped by the view. + */ +template <typename Type> +class scalar_view +{ +protected: + Type m_value; ///< The wrapped accumulator variable. + +public: + /** Value type definition required by @ref monoid_with_view. + */ + typedef Type value_type; + + /** Default constructor. + */ + scalar_view() : m_value() {} + + /** Value constructor. + */ + scalar_view(const Type& v) : m_value(v) {} + + /** @name Value functions required by the reducer class. + * + * Note that the move in/out functions use simple assignment semantics. + */ + //@{ + + /** Set the value of the view. + */ + void view_move_in(Type& v) { m_value = v; } + + /** Get the value of the view. + */ + void view_move_out(Type& v) { v = m_value; } + + /** Set the value of the view. + */ + void view_set_value(const Type& v) { m_value = v; } + + /** Get the value of the view. + */ + Type const& view_get_value() const { return m_value; } + + /** Get a reference to the value contained in the view. For legacy + * reducer support only. + */ + Type & view_get_reference() { return m_value; } + + /** Get a reference to the value contained in the view. For legacy + * reducer support only. + */ + Type const& view_get_reference() const { return m_value; } + //@} +}; + + +/** Wrapper class for move-in construction. + * + * Some types allow their values to be _moved_ as an alternative to copying. + * Moving a value may be much faster than copying it, but may leave the value + * of the move’s source undefined. Consider the `swap` operation provided by + * many STL container classes: + * + * list<T> x, y; + * x = y; // Copy + * x.swap(y); // Move + * + * The assignment _copies_ the value of `y` into `x` in time linear in the + * size of `y`, leaving `y` unchanged. The `swap` _moves_ the value of `y` + * into `x` in constant time, but it also moves the value of `x` into `y`, + * potentially leaving `y` undefined. + * + * A move_in_wrapper simply wraps a pointer to an object. It is created by a + * call to cilk::move_in(). Passing a move_in_wrapper to a view constructor + * (actually, passing it to a reducer constructor, which passes it to the + * monoid `construct()` function, which passes it to the view constructor) + * allows, but does not require, the value pointed to by the wrapper to be + * moved into the view instead of copied. + * + * A view class exercises this option by defining a _move-in constructor_, + * i.e., a constructor with a move_in_wrapper parameter. The constructor calls + * the wrapper’s `value()` function to get a reference to its pointed-to + * value, and can then use that reference in a move operation. + * + * A move_in_wrapper also has an implicit conversion to its pointed-to value, + * so if a view class does not define a move-in constructor, its ordinary + * value constructor will be called with the wrapped value. For example, an + * @ref ReducersAdd "op_add" view does not have a move-in constructor, so + * + * int x; + * reducer< op_add<int> > xr(move_in(x)); + * + * will simply call the `op_add_view(const int &)` constructor. But an + * @ref ReducersList "op_list_append" view does have a move-in constructor, + * so + * + * list<int> x; + * reducer< op_list_append<int> > xr(move_in(x)); + * + * will call the `op_list_append_view(move_in_wrapper<int>)` constructor, + * which can `swap` the value of `x` into the view. + * + * @note Remember that passing the value of a variable to a reducer + * constructor using a move_in_wrapper leaves the variable undefined. + * You cannot assume that the constructor either will or will not copy + * or move the value. + * + * @tparam Type The type of the wrapped value. + * + * @see cilk::move_in() + */ +template <typename Type> +class move_in_wrapper +{ + Type *m_pointer; +public: + + /** Constructor that captures the address of its argument. This is almost + * always called from the @ref move_in function. + */ + explicit move_in_wrapper(Type& ref) : m_pointer(&ref) { } + + /** Implicit conversion to the wrapped value. This allows a move_in_wrapper + * to be used where a value of the wrapped type is expected, in which case + * the wrapper is completely transparent. + */ + operator Type&() const { return *m_pointer; } + + /** Get a reference to the pointed-to value. This has the same effect as + * the implicit conversion, but makes the intent clearer in a move-in + * constructor. + */ + Type& value() const { return *m_pointer; } +}; + +/** Function to create a move_in_wrapper for a value. + * + * @tparam Type The type of the argument, which will be the `type` of the + * created wrapper. + * + * @see move_in_wrapper + */ +template <typename Type> +inline +move_in_wrapper<Type> move_in(Type& ref) + { return move_in_wrapper<Type>(ref); } + + +/** @copydoc move_in(Type&) + * + * @note Applying a function that is explicitly specified as modifying its + * argument to a const argument is obviously an irrational thing to + * do. This move_in() variant is just provided to allow calling a + * move-in constructor with a function return value, which the + * language treats as a const. Using it for any other purpose will + * probably end in tears. + */ +template <typename Type> +inline +move_in_wrapper<Type> move_in(const Type& ref) + { return move_in_wrapper<Type>(ref); } + + +/** Wrapper class to allow implicit downcasts to reducer subclasses. + * + * The Cilk library contains a collection of reducer wrapper classes which + * were created before the `cilk::reducer<Monoid>` style was developed. For + * example, `cilk::reducer_opadd<Type>` provided essentially the same + * functionality that is now provided by + * `cilk::reducer< cilk::op_add<Type> >`. These legacy reducer classes are + * deprecated, but still supported, and they have been reimplemented as + * subclasses of the corresponding `cilk::reducer` classes. For example: + * + * template <class T> + * reducer_opadd<T> : public reducer< op_add<T> > { ... }; + * + * This reimplementation allows transparent conversion between legacy and + * new reducers. That is, a `reducer<op_add>*` or `reducer<op_add>&` can be + * used anywhere that a `reducer_opadd*` or `reducer_opadd&` is expected, + * and vice versa. + * + * The conversion from the legacy reducer to the new reducer is just an + * up-cast, which is provided for free by C++. The conversion from the new + * reducer to the legacy reducer is a down-cast, though, which requires an + * explicit conversion member function in the `reducer` class. The challenge + * is to define a function in the reducer template class which will convert + * each cilk::reducer specialization to the corresponding legacy reducer, + * if there is one. + * + * The trick is in the legacy_reducer_downcast template class, which provides + * a mapping from `cilk::reducer` specializations to legacy reducer classes. + * `reducer<Monoid>` has a conversion function to convert itself to + * `legacy_reducer_downcast< reducer<Monoid> >::%type`. By default, + * `legacy_reducer_downcast<Reducer>::%type` is just a trivial subclass of + * `Reducer`, which is uninteresting, but a reducer with a legacy counterpart + * will have a specialization of `legacy_reducer_downcast` whose `type` is + * the corresponding legacy reducer. For example: + * + * template <typename Type> + * struct legacy_reducer_downcast< reducer< op_add<Type> > > + * { + * typedef reducer_opadd<Type> type; + * }; + * + * + * @tparam Reducer The new-style reducer class whose corresponding legacy reducer class + * is `type`, if there is such a legacy reducer class. + */ +template <typename Reducer> +struct legacy_reducer_downcast +{ + /** The related legacy reducer class. + * + * By default, this is just a trivial subclass of Reducer, but it can be + * overridden in the specialization of legacy_reducer_downcast for + * a reducer that has a corresponding legacy reducers. + */ + struct type : Reducer { }; +}; + + +namespace internal { +/// @cond internal + +template <typename Value, typename View> +struct reducer_set_get +{ + static View theView; // Declared but not defined + + // sizeof(notchar) is guaranteed larger than 1 + struct notchar { char x[2]; }; + + // check_for_ref returns char if 'get_value' returns by value and notchar + // if 'get_value' returns by reference. + static char check_for_ref(Value, ...); + static notchar check_for_ref(Value&, int); + + enum { GET_VALUE_BY_VALUE = + (1 == sizeof(check_for_ref(theView.view_get_value(), 0))) } ; + + typedef typename condition<GET_VALUE_BY_VALUE, + Value, const Value&>::type get_value_type; + + static void move_in(View& view, Value& v) { view.view_move_in(v); } + static void move_out(View& view, Value& v) { view.view_move_out(v); } + + static void set_value(View& view, const Value& v) + { view.view_set_value(v); } + + static get_value_type get_value(const View& view) + { return view.view_get_value(); } +}; + +template <typename Value> +struct reducer_set_get<Value, Value> +{ + typedef const Value& get_value_type; + + static void move_in(Value& view, Value& v) { view = v; } + static void move_out(Value& view, Value& v) { v = view; } + + static void set_value(Value& view, const Value& v) { view = v; } + + static get_value_type get_value(const Value& view) { return view; } +}; + +/// @endcond + + +/** Base class defining the data layout that is common to all reducers. + */ +template <typename Monoid> +class reducer_base { + typedef typename Monoid::view_type view_type; + + // This makes the reducer a hyper-object. (Partially initialized in + // the derived reducer_content class.) + // + __cilkrts_hyperobject_base m_base; + + // The monoid is allocated here as raw bytes, and is constructed explicitly + // by a call to the monoid_type::construct() function in the constructor of + // the `reducer` subclass. + // + storage_for_object<Monoid> m_monoid; + + // Used for sanity checking at destruction. + // + void* m_initialThis; + + // The leftmost view comes next. It is defined in the derived + // reducer_content class. + + /** @name C-callable wrappers for the C++-coded monoid dispatch functions. + */ + //@{ + + static void reduce_wrapper(void* r, void* lhs, void* rhs); + static void identity_wrapper(void* r, void* view); + static void destroy_wrapper(void* r, void* view); + static void* allocate_wrapper(void* r, __STDNS size_t bytes); + static void deallocate_wrapper(void* r, void* view); + + //@} + +protected: + + /** Constructor. + * + * @param leftmost The address of the leftmost view in the reducer. + */ + reducer_base(char* leftmost) + { + static const cilk_c_monoid c_monoid_initializer = { + (cilk_c_reducer_reduce_fn_t) &reduce_wrapper, + (cilk_c_reducer_identity_fn_t) &identity_wrapper, + (cilk_c_reducer_destroy_fn_t) &destroy_wrapper, + (cilk_c_reducer_allocate_fn_t) &allocate_wrapper, + (cilk_c_reducer_deallocate_fn_t) &deallocate_wrapper + }; + + m_base.__c_monoid = c_monoid_initializer; + m_base.__flags = 0; + m_base.__view_offset = (char*)leftmost - (char*)this; + m_base.__view_size = sizeof(view_type); + m_initialThis = this; + + __cilkrts_hyper_create(&m_base); + } + + /** Destructor. + */ + __CILKRTS_STRAND_STALE(~reducer_base()) + { + // Make sure we haven't been memcopy'd or corrupted + __CILKRTS_ASSERT( + this == m_initialThis || + // Allow for a layout bug that may put the initialThis field one + // word later in 1.0 reducers than in 0.9 and 1.1 reducers. + this == *(&m_initialThis + 1) + ); + __cilkrts_hyper_destroy(&m_base); + } + + /** Monoid data member. + * + * @return A pointer to the reducer’s monoid data member. + */ + Monoid* monoid_ptr() { return &m_monoid.object(); } + + /** Leftmost view data member. + * + * @return A pointer to the reducer’s leftmost view data member. + * + * @note This function returns the address of the *leftmost* view, + * which is unique for the lifetime of the reducer. It is + * intended to be used in constructors and destructors. + * Use the reducer::view() function to access the per-strand + * view instance. + */ + view_type* leftmost_ptr() + { + char* view_addr = (char*)this + m_base.__view_offset; + return reinterpret_cast<view_type*>(view_addr); + } + +public: + + /** @name Access the current view. + * + * These functions return a reference to the instance of the reducer’s + * view that was created for the current strand of a parallel computation + * (and create it if it doesn’t already exist). Note the difference from + * the (private) leftmost_ptr() function, which returns a pointer to the + * _leftmost_ view, which is the same in all strands. + */ + //@{ + + /** Per-strand view instance. + * + * @return A reference to the per-strand view instance. + */ + view_type& view() + { + return *static_cast<view_type *>(__cilkrts_hyper_lookup(&m_base)); + } + + /** @copydoc view() + */ + const view_type& view() const + { + return const_cast<reducer_base*>(this)->view(); + } + + //@} + + /** Initial view pointer field. + * + * @internal + * + * @return a reference to the m_initialThis field. + * + * @note This function is provided for “white-box” testing of the + * reducer layout code. There is never any reason for user code + * to call it. + */ + const void* const & initial_this() const { return m_initialThis; } +}; + +template <typename Monoid> +void reducer_base<Monoid>::reduce_wrapper(void* r, void* lhs, void* rhs) +{ + Monoid* monoid = static_cast<reducer_base*>(r)->monoid_ptr(); + monoid->reduce(static_cast<view_type*>(lhs), + static_cast<view_type*>(rhs)); +} + +template <typename Monoid> +void reducer_base<Monoid>::identity_wrapper(void* r, void* view) +{ + Monoid* monoid = static_cast<reducer_base*>(r)->monoid_ptr(); + monoid->identity(static_cast<view_type*>(view)); +} + +template <typename Monoid> +void reducer_base<Monoid>::destroy_wrapper(void* r, void* view) +{ + Monoid* monoid = static_cast<reducer_base*>(r)->monoid_ptr(); + monoid->destroy(static_cast<view_type*>(view)); +} + +template <typename Monoid> +void* reducer_base<Monoid>::allocate_wrapper(void* r, __STDNS size_t bytes) +{ + Monoid* monoid = static_cast<reducer_base*>(r)->monoid_ptr(); + return monoid->allocate(bytes); +} + +template <typename Monoid> +void reducer_base<Monoid>::deallocate_wrapper(void* r, void* view) +{ + Monoid* monoid = static_cast<reducer_base*>(r)->monoid_ptr(); + monoid->deallocate(static_cast<view_type*>(view)); +} + + +/** Base class defining the data members of a reducer. + * + * @tparam Aligned The `m_view` data member, and therefore the entire + * structure, are cache-line aligned if this parameter + * is `true'. + */ +template <typename Monoid, bool Aligned = Monoid::align_reducer> +class reducer_content; + +/** Base class defining the data members of an aligned reducer. + */ +template <typename Monoid> +class reducer_content<Monoid, true> : public reducer_base<Monoid> +{ + typedef typename Monoid::view_type view_type; + + // The leftmost view is defined as raw bytes. It will be constructed + // by the monoid `construct` function. It is cache-aligned, which + // will push it into a new cache line. Furthermore, its alignment causes + // the reducer as a whole to be cache-aligned, which makes the reducer + // size a multiple of a cache line. Since there is nothing in the reducer + // after the view, all this means that the leftmost view gets one or more + // cache lines all to itself, which prevents false sharing. + // + __CILKRTS_CACHE_ALIGN + char m_leftmost[sizeof(view_type)]; + + /** Test if the reducer is cache-line-aligned. + * + * Used in assertions. + */ + bool reducer_is_cache_aligned() const + { return 0 == ((std::size_t) this & (__CILKRTS_CACHE_LINE__ - 1)); } + +protected: + + /** Constructor. + */ + reducer_content() : reducer_base<Monoid>((char*)&m_leftmost) + { +#ifndef CILK_IGNORE_REDUCER_ALIGNMENT + assert(reducer_is_cache_aligned() && + "Reducer should be cache aligned. Please see comments following this assertion for explanation and fixes."); +#endif + /* "REDUCER SHOULD BE CACHE ALIGNED" ASSERTION. + * + * This Reducer class instantiation specifies cache-line alignment of the + * leftmost view field (and, implicitly, of the reducer itself). You got + * this assertion because a reducer with this class was allocated at a + * non-cache-aligned address, probably because it was allocated on the + * heap with `new`. This can be a problem for two reasons: + * + * 1. If the leftmost view is not on a cache line by itself, there might + * be a slowdown resulting from accesses to the same cache line from + * different threads. + * + * 2. The compiler thinks that reducer is cache-line aligned, but it + * really isn't. If the reducer is contained in a structure, then the + * compiler will believe that the containing structure, and other + * fields contained in it, are also more aligned than they really + * are. In particular, if the structure contains a numeric array that + * is used in a vectorizable loop, then the compiler might generate + * invalid vector instructions, resulting in a runtime error. + * + * The compiler will always allocate reducer variables, and structure + * variables containing reducers, with their required alignment. + * Reducers, and structures containing a reducer, which are allocated + * on the heap with `new` will _not_ be properly aligned. + * + * There are three ways that you can fix this assertion failure. + * + * A. Rewrite your code to use the new-style `reducer< op_XXX<Type> >` + * instead of the legacy `reducer_XXX<type>`. The new-style reducers + * are not declared to be cache-aligned, and will work properly if + * they are not cache-aligned. + * + * B. If you must allocate an old-style reducer or a structure containing + * a reducer on the heap, figure out how to align it correctly. The + * suggested fix is to use `cilk::aligned_new()` and + * `cilk::aligned_delete()` instead of `new` and `delete`, as follows: + * + * Type* ptr = cilk::aligned_new<Type>(constructor-arguments); + * cilk::aligned_delete(ptr); + * + * C. Define the macro CILK_IGNORE_REDUCER_ALIGNMENT, which will suppress + * the assertion check. Do this only if you are comfortable that + * problem (2) above will not occur. + */ + } +}; + +/** Base class defining the data members of an unaligned reducer. + */ +template <typename Monoid> +class reducer_content<Monoid, false> : public reducer_base<Monoid> +{ + typedef typename Monoid::view_type view_type; ///< The view type. + + // Reserve space for the leftmost view. The view will be allocated at an + // aligned offset in this space at runtime, to guarantee that the view + // will get one or more cache lines all to itself, to prevent false + // sharing. + // + // The number of bytes to reserve is determined as follows: + // * Start with the view size. + // * Round up to a multiple of the cache line size, to get the total size + // of the cache lines that will be dedicated to the view. + // * Add (cache line size - 1) filler bytes to guarantee that the reserved + // area will contain a cache-aligned block of the required cache lines, + // no matter where the reserved area starts. + // + char m_leftmost[ + // View size rounded up to multiple cache lines + ( (sizeof(view_type) + __CILKRTS_CACHE_LINE__ - 1) + & ~ (__CILKRTS_CACHE_LINE__ - 1) + ) + // plus filler to allow alignment. + + __CILKRTS_CACHE_LINE__ - 1 + ]; + +protected: + + /** Constructor. Find the first cache-aligned position in the reserved + * area, and pass it to the base constructor as the leftmost view + * address. + */ + reducer_content() : + reducer_base<Monoid>( + (char*)( ((std::size_t)&m_leftmost + __CILKRTS_CACHE_LINE__ - 1) + & ~ (__CILKRTS_CACHE_LINE__ - 1) ) ) + {} +}; + + +} // namespace internal + + +// The __cilkrts_hyperobject_ functions are defined differently depending on +// whether a file is compiled with or without the CILK_STUB option. Therefore, +// reducers compiled in the two modes should be link-time incompatible, so that +// object files compiled with stubbed reducers won't be linked into an +// unstubbed program, or vice versa. We achieve this by putting the reducer +// class definition into the cilk::stub namespace in a stubbed compilation. + +#ifdef CILK_STUB +namespace stub { +#endif + +/** Reducer class. + * + * A reducer is instantiated on a Monoid. The Monoid provides the value + * type, associative reduce function, and identity for the reducer. + * + * @tparam Monoid The monoid class that the reducer is instantiated on. It must model + * the @ref reducers_monoid_concept "monoid concept". + * + * @see @ref pagereducers + */ +template <class Monoid> +class reducer : public internal::reducer_content<Monoid> +{ + typedef internal::reducer_content<Monoid> base; + using base::monoid_ptr; + using base::leftmost_ptr; + public: + typedef Monoid monoid_type; ///< The monoid type. + typedef typename Monoid::value_type value_type; ///< The value type. + typedef typename Monoid::view_type view_type; ///< The view type. + + private: + typedef internal::reducer_set_get<value_type, view_type> set_get; + + reducer(const reducer&); ///< Disallow copying. + reducer& operator=(const reducer&); ///< Disallow assignment. + + public: + + /** @name Constructors + * + * All reducer constructors call the static `construct()` function of the monoid class to + * construct the reducer's monoid and leftmost view. + * + * The reducer constructor arguments are simply passed through to the construct() function. + * Thus, the constructor parameters accepted by a particular reducer class are determined + * by its monoid class. + */ + //@{ + + /** 0 – 6 const reference parameters. + */ + //@{ + + reducer() + { + monoid_type::construct(monoid_ptr(), leftmost_ptr()); + } + + template <typename T1> + reducer(const T1& x1) + { + monoid_type::construct(monoid_ptr(), leftmost_ptr(), x1); + } + + template <typename T1, typename T2> + reducer(const T1& x1, const T2& x2) + { + monoid_type::construct(monoid_ptr(), leftmost_ptr(), x1, x2); + } + + template <typename T1, typename T2, typename T3> + reducer(const T1& x1, const T2& x2, const T3& x3) + { + monoid_type::construct(monoid_ptr(), leftmost_ptr(), x1, x2, x3); + } + + template <typename T1, typename T2, typename T3, typename T4> + reducer(const T1& x1, const T2& x2, const T3& x3, const T4& x4) + { + monoid_type::construct(monoid_ptr(), leftmost_ptr(), x1, x2, x3, x4); + } + + template <typename T1, typename T2, typename T3, typename T4, typename T5> + reducer(const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5) + { + monoid_type::construct(monoid_ptr(), leftmost_ptr(), x1, x2, x3, x4, x5); + } + + template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> + reducer(const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, const T6& x6) + { + monoid_type::construct(monoid_ptr(), leftmost_ptr(), x1, x2, x3, x4, x5, x6); + } + + //@} + + /** 1 non-const reference parameter. + */ + //@{ + + template <typename T1> + reducer(T1& x1) + { + monoid_type::construct(monoid_ptr(), leftmost_ptr(), x1); + } + + //@} + + /** Destructor. + */ + __CILKRTS_STRAND_STALE(~reducer()) + { + leftmost_ptr()->~view_type(); + monoid_ptr()->~monoid_type(); + } + + //@{ + /** Get the monoid. + * + * @return A reference to the monoid object belonging to this reducer. + */ + Monoid& monoid() { return *monoid_ptr(); } + + const Monoid& monoid() const + { return const_cast<reducer*>(this)->monoid(); } + //@} + + //@{ + /** Access the current view. + * + * Return a reference to the instance of the reducer’s view that was + * created for the current strand of a parallel computation (and create + * it if it doesn’t already exist). + */ + view_type& view() { return base::view(); } + const view_type& view() const { return base::view(); } + //@} + + + /** @name Dereference the reducer to get the view. + * + * “Dereferencing” a reducer yields the view for the current strand. The + * view, in turn, acts as a proxy for its contained value, exposing only + * those operations which are consistent with the reducer’s monoid. Thus, + * all modifications of the reducer’s accumulator variable are written as + * + * *reducer OP ... + * + * or + * + * reducer->func(...) + * + * (The permitted operations on a reducer’s accumulator are listed in the + * documentation for that particular kind of reducer.) + * + * @note `*r` is a synonym for `r.view()`. Recommended style is to use + * `*r` (or `r->`) in the common case where code is simply + * updating the accumulator variable wrapped in the view, and to + * use `r.view()` in the unusual case where it is desirable to + * call attention to the view itself. + */ + //@{ + + //@{ + /** Dereference operator. + * + * @return A reference to the per-strand view instance. + */ + view_type& operator*() { return view(); } + view_type const& operator*() const { return view(); } + //@} + + //@{ + /** Pointer operator. + * + * @return A pointer to the per-strand view instance. + */ + view_type* operator->() { return &view(); } + view_type const* operator->() const { return &view(); } + //@} + + //@{ + /** Deprecated view access. + * + * `r()` is a synonym for `*r` which was used with early versions of Cilk + * reducers. `*r` is now the preferred usage. + * + * @deprecated Use operator*() instead of operator()(). + * + * @return A reference to the per-strand view instance. + */ + view_type& operator()() { return view(); } + view_type const& operator()() const { return view(); } + //@} + + //@} + + /** @name Set and get the value. + * + * These functions are used to set an initial value for the reducer before + * starting the reduction, or to get the final value after the reduction + * is complete. + * + * @note These functions are completely different from the view + * operations that are made available via operator*() and + * operator->(), which are used to _modify_ the reducer’s value + * _during_ the reduction. + * + * @warning These functions _can_ be called at any time, and in + * general, they will refer to the value contained in the view + * for the current strand. However, using them other than to + * set the reduction’s initial value or get its final value + * will almost always result in undefined behavior. + */ + //@{ + + /** Move a value into the reducer. + * + * This function is used to set the initial value of the reducer’s + * accumulator variable by either copying or _moving_ the value of @a obj + * into it. Moving a value can often be performed in constant time, even + * for large container objects, but has the side effect of leaving the + * value of @a obj undefined. (See the description of the + * @ref move_in_wrapper class for a discussion of moving values.) + * + * @par Usage + * A move_in() call to initialize a reducer is often paired with a + * move_out() call to get its final value: + * + * reducer<Type> xr; + * xr.move_in(x); + * … do the reduction … + * xr.move_out(x); + * + * @par Assumptions + * - You cannot assume either that this will function will copy its + * value or that it will move it. + * - You must assume that the value of @a obj will be undefined + * after the call to move_in(). + * - You can assume that move_in() will be at least as efficient as + * set_value(), and you should therefore prefer move_in() unless + * you need the value of @a obj to be unchanged after the call. + * (But you should usually prefer the move-in constructor over a + * move_in() call — see the note below.) + * + * @note The behavior of a default constructor followed by move-in + * initialization: + * + * reducer<Type> xr; + * xr.move_in(x); + * + * @note is not necessarily the same as a move-in constructor: + * + * reducer<Type> xr(move_in(x)); + * + * @note In particular, when @a Type is a container type with a + * non-empty allocator, the move-in constructor will create the + * accumulator variable with the same allocator as the input + * argument @a x, while the default constructor will create the + * accumulator variable with a default allocator. The mismatch of + * allocators in the latter case means that the input argument + * @a x may have to be copied in linear time instead of being + * moved in constant time. + * + * @note Best practice is to prefer the move-in constructor over the + * move-in function unless the move-in function is required for + * some specific reason. + * + * @warning Calling this function other than to set the initial value + * for a reduction will almost always result in undefined + * behavior. + * + * @param obj The object containing the value that will be moved into the + * reducer. + * + * @post The reducer contains the value that was initially in @a obj. + * @post The value of @a obj is undefined. + * + * @see set_value() + */ + void move_in(value_type& obj) { set_get::move_in(view(), obj);} + + /** Move the value out of the reducer. + * + * This function is used to retrieve the final value of the reducer’s + * accumulator variable by either copying or _moving_ the value of @a obj + * into it. Moving a value can often be performed in constant time, even + * for large container objects, but has the side effect of leaving the + * value of the reducer’s accumulator variable undefined. (See the + * description of the @ref move_in_wrapper class for a discussion of + * moving values.) + * + * @par Usage + * A move_in() call to initialize a reducer is often paired with a + * move_out() call to get its final value: + * + * reducer<Type> xr; + * xr.move_in(x); + * … do the reduction … + * xr.move_out(x); + * + * @par Assumptions + * - You cannot assume either that this will function will copy its + * value or that it will move it. + * - You must assume that the value of the reducer’s accumulator + * variable will be undefined after the call to move_out(). + * - You can assume that move_out() will be at least as efficient as + * get_value(), and you should therefore prefer move_out() unless + * you need the accumulator variable to be preserved after the + * call. + * + * @warning Calling this function other than to retrieve the final + * value of a reduction will almost always result in undefined + * behavior. + * + * @param obj The object that the value of the reducer will be moved into. + * + * @post @a obj contains the value that was initially in the reducer. + * @post The value of the reducer is undefined. + * + * @see get_value() + */ + void move_out(value_type& obj) { set_get::move_out(view(), obj); } + + /** Set the value of the reducer. + * + * This function sets the initial value of the reducer’s accumulator + * variable to the value of @a obj. + * + * @note The behavior of a default constructor followed by + * initialization: + * + * reducer<Type> xr; + * xr.set_value(x); + * + * @note is not necessarily the same as a value constructor: + * + * reducer<Type> xr(x); + * + * @note In particular, when @a Type is a container type with a + * non-empty allocator, the value constructor will create the + * accumulator variable with the same allocator as the input + * argument @a x, while the default constructor will create the + * accumulator variable with a default allocator. + * + * @warning Calling this function other than to set the initial value + * for a reduction will almost always result in undefined + * behavior. + * + * @param obj The object containing the value that will be copied into + * the reducer. + * + * @post The reducer contains a copy of the value in @a obj. + * + * @see move_in() + */ + void set_value(const value_type& obj) { set_get::set_value(view(), obj); } + + /** Get the value of the reducer. + * + * This function gets the final value of the reducer’s accumulator + * variable. + * + * @warning Calling this function other than to retrieve the final + * value of a reduction will almost always result in undefined + * behavior. + * + * @return A reference to the value contained in the reducer. + * + * @see move_out() + */ + typename set_get::get_value_type get_value() const + { return set_get::get_value(view()); } + + //@} + + /** Implicit downcast to legacy reducer wrapper, if any. + * + * @see legacy_reducer_downcast + */ + operator typename legacy_reducer_downcast<reducer>::type& () + { + typedef typename legacy_reducer_downcast<reducer>::type downcast_type; + return *reinterpret_cast<downcast_type*>(this); + } + + + /** Implicit downcast to legacy reducer wrapper, if any. + * + * @see legacy_reducer_downcast + */ + operator const typename legacy_reducer_downcast<reducer>::type& () const + { + typedef typename legacy_reducer_downcast<reducer>::type downcast_type; + return *reinterpret_cast<const downcast_type*>(this); + } +}; + +#ifdef CILK_STUB +} // namespace stub +using stub::reducer; +#endif + +} // end namespace cilk + +#endif /* __cplusplus */ + +/** @page page_reducers_in_c Creating and Using Reducers in C + * + * @tableofcontents + * + * The Cilk runtime supports reducers written in C as well as in C++. The basic logic is the + * same, but the implementation details are very different. The C++ reducer implementation uses + * templates heavily to create very generic components. The C reducer implementation uses + * macros, which are a much blunter instrument. The most immediate consequence is that the + * monoid/view/reducer architecture is mostly implicit rather than explicit in C reducers. + * + * @section reducers_c_overview Overview of Using Reducers in C + * + * The basic usage pattern for C reducers is: + * + * 1. Create and initialize a reducer object. + * 2. Tell the Cilk runtime about the reducer. + * 3. Update the value contained in the reducer in a parallel computation. + * 4. Tell the Cilk runtime that you are done with the reducer. + * 5. Retrieve the value from the reducer. + * + * @subsection reducers_c_creation Creating and Initializing a C Reducer + * + * The basic pattern for creating and initializing a reducer object in C is + * + * CILK_C_DECLARE_REDUCER(value-type) reducer-name = + * CILK_C_INIT_REDUCER(value-type, + * reduce-function, + * identity-function, + * destroy-function, + * initial-value); + * + * This is simply an initialized definition of a variable named _reducer-name_. The + * @ref CILK_C_DECLARE_REDUCER macro expands to an anonymous `struct` declaration for a reducer + * object containing a view of type _value-type_, and the @ref CILK_C_INIT_REDUCER macro + * expands to a struct initializer. + * + * @subsection reducers_c_reduce_func Reduce Functions + * + * The reduce function for a reducer is called when a parallel execution strand terminates, to + * combine the values computed by the terminating strand and the strand to its left. It takes + * three arguments: + * + * - `void* reducer` — the address of the reducer. + * - `void* left` — the address of the value for the left strand. + * - `void* right` — the address of the value for the right (terminating) strand. + * + * It must apply the reducer’s reduction operation to the `left` and `right` values, leaving + * the result in the `left` value. The `right` value is undefined after the reduce function + * call. + * + * @subsection reducers_c_identity_func Identity Functions + * + * The identity function for a reducer is called when a parallel execution strand begins, to + * initialize its value to the reducer’s identity value. It takes two arguments: + * + * - `void* reducer` — the address of the reducer. + * - `void* v` — the address of a freshly allocated block of memory of size + * `sizeof(value-type)`. + * + * It must initialize the memory pointed to by `v` so that it contains the reducer’s identity + * value. + * + * @subsection reducers_c_destroy_func Destroy Functions + * + * The destroy function for a reducer is called when a parallel execution strand terminates, to + * do any necessary cleanup before its value is deallocated. It takes two arguments: + * + * - `void* reducer` — the address of the reducer. + * - `void* p` — the address of the value for the terminating strand. + * + * It must release any resources belonging to the value pointed to by `p`, to avoid a resource + * leak when the memory containing the value is deallocated. + * + * The runtime function `__cilkrts_hyperobject_noop_destroy` can be used for the destructor + * function if the reducer’s values do not need any cleanup. + * + * @subsection reducers_c_register Tell the Cilk Runtime About the Reducer + * + * Call the @ref CILK_C_REGISTER_REDUCER macro to register the reducer with the Cilk runtime: + * + * CILK_C_REGISTER_REDUCER(reducer-name); + * + * The runtime will manage reducer values for all registered reducers when parallel execution + * strands begin and end. + * + * @subsection reducers_c_update Update the Value Contained in the Reducer + * + * The @ref REDUCER_VIEW macro returns a reference to the reducer’s value for the current + * parallel strand: + * + * REDUCER_VIEW(reducer-name) = REDUCER_VIEW(reducer-name) OP x; + * + * C++ reducer views restrict access to the wrapped value so that it can only be modified in + * ways consistent with the reducer’s operation. No such protection is provided for C reducers. + * It is + * entirely the responsibility of the user to avoid modifying the value in any + * inappropriate way. + * + * @subsection c_reducers_unregister Tell the Cilk Runtime That You Are Done with the Reducer + * + * When the parallel computation is complete, call the @ref CILK_C_UNREGISTER_REDUCER macro to + * unregister the reducer with the Cilk runtime: + * + * CILK_C_UNREGISTER_REDUCER(reducer-name); + * + * The runtime will stop managing reducer values for the reducer. + * + * @subsection c_reducers_retrieve Retrieve the Value from the Reducer + * + * When the parallel computation is complete, use the @ref REDUCER_VIEW macro to retrieve the + * final value computed by the reducer. + * + * @subsection reducers_c_example_custom Example — Creating and Using a Custom C Reducer + * + * The `IntList` type represents a simple list of integers. + * + * struct _intListNode { + * int value; + * _intListNode* next; + * } IntListNode; + * typedef struct { IntListNode* head; IntListNode* tail; } IntList; + * + * // Initialize a list to be empty + * void IntList_init(IntList* list) { list->head = list->tail = 0; } + * + * // Append an integer to the list + * void IntList_append(IntList* list, int x) + * { + * IntListNode* node = (IntListNode*) malloc(sizeof(IntListNode)); + * if (list->tail) list->tail->next = node; else list->head = node; + * list->tail = node; + * } + * + * // Append the right list to the left list, and leave the right list empty + * void IntList_concat(IntList* left, IntList* right) + * { + * if (left->head) { + * left->tail->next = right->head; + * if (right->tail) left->tail = right->tail; + * } + * else { + * *left = *right; + * } + * IntList_init(*right); + * } + * + * This code creates a reducer that supports creating an `IntList` by appending values to it. + * + * void identity_IntList(void* reducer, void* list) + * { + * IntList_init((IntList*)list); + * } + * + * void reduce_IntList(void* reducer, void* left, void* right) + * { + * IntList_concat((IntList*)left, (IntList*)right); + * } + * + * CILK_C_DECLARE_REDUCER(IntList) my_list_int_reducer = + * CILK_C_INIT_REDUCER(IntList, + * reduce_int_list, + * identity_int_list, + * __cilkrts_hyperobject_noop_destroy); + * // Initial value omitted // + * ListInt_init(&REDUCER_VIEW(my_int_list_reducer)); + * + * CILK_C_REGISTER_REDUCER(my_int_list_reducer); + * cilk_for (int i = 0; i != n; ++i) { + * IntList_append(&REDUCER_VIEW(my_int_list_reducer), a[i]); + * } + * CILK_C_UNREGISTER_REDUCER(my_int_list_reducer); + * + * IntList result = REDUCER_VIEW(my_int_list_reducer); + * + * @section reducers_c_predefined Predefined C Reducers + * + * Some of the predefined reducer classes in the Cilk library come with a set of predefined + * macros to provide the same capabilities in C. In general, two macros are provided for each + * predefined reducer family: + * + * - `CILK_C_REDUCER_operation(reducer-name, type-name, initial-value)` — Declares a + * reducer object named _reducer-name_ with initial value _initial-value_ to perform + * a reduction using the _operation_ on values of the type specified by _type-name_. + * This is the equivalent of the general code described in @ref reducers_c_creation : + * + * CILK_C_DECLARE_REDUCER(type) reducer-name = + * CILK_C_INIT_REDUCER(type, ..., initial-value); + * + * where _type_ is the C type corresponding to _type_name_. See @ref reducers_c_type_names + * below for the _type-names_ that you can use. + * + * - `CILK_C_REDUCER_operation_TYPE(type-name)` — Expands to the `typedef` name for the type + * of the reducer object declared by + * `CILK_C_REDUCER_operation(reducer-name, type-name, initial-value)`. + * + * See @ref reducers_c_example_predefined. + * + * The predefined C reducers are: + * + * | Operation | Name | Documentation | + * |-------------------|---------------|-------------------------------| + * | addition | `OPADD` | @ref ReducersAdd | + * | bitwise and | `OPAND` | @ref ReducersAnd | + * | bitwise or | `OPOR` | @ref ReducersOr | + * | bitwise xor | `OPXOR` | @ref ReducersXor | + * | multiplication | `OPMUL` | @ref ReducersMul | + * | minimum | `MIN` | @ref ReducersMinMax | + * | minimum & index | `MIN_INDEX` | @ref ReducersMinMax | + * | maximum | `MIN` | @ref ReducersMinMax | + * | maximum & index | `MIN_INDEX` | @ref ReducersMinMax | + * + * @subsection reducers_c_type_names Numeric Type Names + * + * The type and function names created by the C reducer definition macros incorporate both the + * reducer kind (`opadd`, `opxor`, etc.) and the value type of the reducer (`int`, `double`, + * etc.). The value type is represented by a _numeric type name_ string. The types supported + * in C reducers, and their corresponding numeric type names, are given in the following table: + * + * | Type | Numeric Type Name | + * |-----------------------|-------------------------------| + * | `char` | `char` | + * | `unsigned char` | `uchar` | + * | `signed char` | `schar` | + * | `wchar_t` | `wchar_t` | + * | `short` | `short` | + * | `unsigned short` | `ushort` | + * | `int` | `int` | + * | `unsigned int` | `uint` | + * | `unsigned int` | `unsigned` (alternate name) | + * | `long` | `long` | + * | `unsigned long` | `ulong` | + * | `long long` | `longlong` | + * | `unsigned long long` | `ulonglong` | + * | `float` | `float` | + * | `double` | `double` | + * | `long double` | `longdouble` | + * + * @subsection reducers_c_example_predefined Example — Using a Predefined C Reducer + * + * To compute the sum of all the values in an array of `unsigned int`: + * + * CILK_C_REDUCER_OPADD(sum, uint, 0); + * CILK_C_REGISTER_REDUCER(sum); + * cilk_for(int i = 0; i != n; ++i) { + * REDUCER_VIEW(sum) += a[i]; + * } + * CILK_C_UNREGISTER_REDUCER(sum); + * printf("The sum is %u\n", REDUCER_VIEW(sum)); + */ + + + /** @name C language reducer macros + * + * These macros are used to declare and work with reducers in C code. + * + * @see @ref page_reducers_in_c + */ + //@{ + +/// @cond internal + +/** @name Compound identifier macros. + * + * These macros are used to construct an identifier by concatenating two or three identifiers. + */ +//@{ + +/** Expand to an identifier formed by concatenating two identifiers. + */ +#define __CILKRTS_MKIDENT(a,b) __CILKRTS_MKIDENT_IMP(a,b,) + +/** Expand to an identifier formed by concatenating three identifiers. + */ +#define __CILKRTS_MKIDENT3(a,b,c) __CILKRTS_MKIDENT_IMP(a,b,c) + +/** Helper macro to do the concatenation. + */ +#define __CILKRTS_MKIDENT_IMP(a,b,c) a ## b ## c + +//@} + +/** Compiler-specific keyword for the “type of” operator. + */ +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +# define _Typeof __typeof__ +#endif + +/** @name Predefined reducer function declaration macros. + * + * These macros are used to create the function headers for the identity, reduction, + * and destructor functions for a builtin reducer family. The macro can be followed by + * a semicolon to create a declaration, or by a brace-enclosed body to create a definition. + */ +//@{ + +/** Create an identity function header. + * + * @note The name of the function’s value pointer parameter will always be `v`. + * + * @param name The reducer family name. + * @param tn The type name. + */ +#define __CILKRTS_DECLARE_REDUCER_IDENTITY(name,tn) CILK_EXPORT \ + void __CILKRTS_MKIDENT3(name,_identity_,tn)(void* key, void* v) + +/** Create a reduction function header. + * + * @param name The reducer family name. + * @param tn The type name. + * @param l The name to use for the function’s left value pointer parameter. + * @param r The name to use for the function’s right value pointer parameter. + */ +#define __CILKRTS_DECLARE_REDUCER_REDUCE(name,tn,l,r) CILK_EXPORT \ + void __CILKRTS_MKIDENT3(name,_reduce_,tn)(void* key, void* l, void* r) + +/** Create a destructor function header. + * + * @param name The reducer family name. + * @param tn The type name. + * @param p The name to use for the function’s value pointer parameter. + */ +#define __CILKRTS_DECLARE_REDUCER_DESTROY(name,tn,p) CILK_EXPORT \ + void __CILKRTS_MKIDENT3(name,_destroy_,tn)(void* key, void* p) + +//@} + +/// @endcond + + +/*************************************************************************** + * Real implementation + ***************************************************************************/ + +/** Declaration of a C reducer structure type. + * + * This macro expands into an anonymous structure declaration for a C reducer structure + * which contains a @a Type value. For example: + * + * CILK_C_DECLARE_REDUCER(int) my_add_int_reducer = + * CILK_C_INIT_REDUCER(int, …); + * + * @param Type The type of the value contained in the reducer object. + * + * @see @ref reducers_c_creation + */ +#define CILK_C_DECLARE_REDUCER(Type) struct { \ + __cilkrts_hyperobject_base __cilkrts_hyperbase; \ + __CILKRTS_CACHE_ALIGN Type value; \ + } + +/** Initializer for a C reducer structure. + * + * This macro expands into a brace-enclosed structure initializer for a C reducer structure + * that was declared with `CILK_C_DECLARE_REDUCER(Type)`. For example: + * + * CILK_C_DECLARE_REDUCER(int) my_add_int_reducer = + * CILK_C_INIT_REDUCER(int, + * add_int_reduce, + * add_int_identity, + * __cilkrts_hyperobject_noop_destroy, + * 0); + * + * @param Type The type of the value contained in the reducer object. Must be the same as + * the @a Type argument of the CILK_C_DECLARE_REDUCER macro call that created + * the reducer. + * @param Reduce The address of the @ref reducers_c_reduce_func "reduce function" for the + * reducer. + * @param Identity The address of the @ref reducers_c_identity_func "identity function" for + * the reducer. + * @param Destroy The address of the @ref reducers_c_destroy_func "destroy function" for the + * reducer. + * @param ... The initial value for the reducer. (A single expression if @a Type is a + * scalar type; a list of values if @a Type is a struct or array type.) + * + * @see @ref reducers_c_creation + */ + +#define CILK_C_INIT_REDUCER(Type, Reduce, Identity, Destroy, ...) \ + { { { Reduce \ + , Identity \ + , Destroy \ + , __cilkrts_hyperobject_alloc \ + , __cilkrts_hyperobject_dealloc \ + } \ + , 0 \ + , __CILKRTS_CACHE_LINE__ \ + , sizeof(Type) \ + } \ + , __VA_ARGS__ \ + } + +/** Register a reducer with the Cilk runtime. + * + * The runtime will manage reducer values for all registered reducers when parallel execution + * strands begin and end. For example: + * + * CILK_C_REGISTER_REDUCER(my_add_int_reducer); + * cilk_for (int i = 0; i != n; ++i) { + * … + * } + * + * @param Expr The reducer to be registered. + * + * @see @ref page_reducers_in_c + */ +#define CILK_C_REGISTER_REDUCER(Expr) \ + __cilkrts_hyper_create(&(Expr).__cilkrts_hyperbase) + +/** Unregister a reducer with the Cilk runtime. + * + * The runtime will stop managing reducer values for a reducer after it is unregistered. For + * example: + * + * cilk_for (int i = 0; i != n; ++i) { + * … + * } + * CILK_C_UNREGISTER_REDUCER(my_add_int_reducer); + * + * @param Expr The reducer to be unregistered. + * + * @see @ref page_reducers_in_c + */ +#define CILK_C_UNREGISTER_REDUCER(Expr) \ + __cilkrts_hyper_destroy(&(Expr).__cilkrts_hyperbase) + +/** Get the current view for a reducer. + * + * The `REDUCER_VIEW(reducer-name)` returns a reference to the reducer’s value for the + * current parallel strand. This can be used to initialize thevalue of the reducer before it + * is used, to modify the value of the reducer on the current parallel strand, or to retrieve + * the final value of the reducer at the end of the parallel computation. + * + * REDUCER_VIEW(my_add_int_reducer) = REDUCER_VIEW(my_add_int_reducer) + x; + * + * @note C++ reducer views restrict access to the wrapped value so that it can only be + * modified in ways consistent with the reducer’s operation. No such protection is provided + * for C reducers. It is entirely the responsibility of the user to refrain from modifying the + * value in any inappropriate way. + * + * @param Expr The reducer whose value is to be returned. + * + * @see @ref page_reducers_in_c + */ +#define REDUCER_VIEW(Expr) (*(_Typeof((Expr).value)*) \ + __cilkrts_hyper_lookup(&(Expr).__cilkrts_hyperbase)) + +//@} C language reducer macros + +#endif // CILK_REDUCER_H_INCLUDED diff --git a/libcilkrts/include/cilk/reducer_file.h b/libcilkrts/include/cilk/reducer_file.h new file mode 100644 index 00000000000..75af994e9d4 --- /dev/null +++ b/libcilkrts/include/cilk/reducer_file.h @@ -0,0 +1,37 @@ +/* + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + + diff --git a/libcilkrts/include/cilk/reducer_list.h b/libcilkrts/include/cilk/reducer_list.h new file mode 100644 index 00000000000..fc0be1e03d3 --- /dev/null +++ b/libcilkrts/include/cilk/reducer_list.h @@ -0,0 +1,1127 @@ +/* reducer_list.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_list.h + * + * @brief Defines classes for doing parallel list creation by appending or + * prepending. + * + * @ingroup ReducersList + * + * @see ReducersList + */ + +#ifndef REDUCER_LIST_H_INCLUDED +#define REDUCER_LIST_H_INCLUDED + +#include <cilk/reducer.h> +#include <list> + +/** @defgroup ReducersList List Reducers + * + * List append and prepend reducers allow the creation of a standard list by + * concatenating a set of lists or values in parallel. + * + * @ingroup Reducers + * + * You should be familiar with @ref pagereducers "Cilk reducers", described in + * file `reducers.md`, and particularly with @ref reducers_using, before trying + * to use the information in this file. + * + * @section redlist_usage Usage Example + * + * // Create a list containing the labels of the nodes of a tree in + * // “inorder” (left subtree, root, right subtree). + * + * struct Tree { Tree* left; Tree* right; string label; ... }; + * + * list<string> x; + * cilk::reducer< cilk::op_list_append<string> > xr(cilk::move_in(x)); + * collect_labels(tree, xr); + * xr.move_out(x); + * + * void collect_labels(Tree* node, + * cilk::reducer< cilk::op_list_append<string> >& xr) + * { + * if (node) { + * cilk_spawn collect_labels(node->left, xr); + * xr->push_back(node->label); + * collect_labels(node->right, xr); + * cilk_sync; + * } + * } + * + * @section redlist_monoid The Monoid + * + * @subsection redlist_monoid_values Value Set + * + * The value set of a list reducer is the set of values of the class + * `std::list<Type, Allocator>`, which we refer to as “the reducer’s list + * type”. + * + * @subsection redlist_monoid_operator Operator + * + * The operator of a list append reducer is defined as + * + * x CAT y == (every element of x, followed by every element of y) + * + * The operator of a list prepend reducer is defined as + * + * x RCAT y == (every element of y, followed by every element of x) + * + * @subsection redlist_monoid_identity Identity + * + * The identity value of a list reducer is the empty list, which is the value + * of the expression `std::list<Type, Allocator>([allocator])`. + * + * @section redlist_operations Operations + * + * In the operation descriptions below, the type name `List` refers to the + * reducer’s string type, `std::list<Type, Allocator>`. + * + * @subsection redlist_constructors Constructors + * + * Any argument list which is valid for a `std::list` constructor is valid for + * a list reducer constructor. The usual move-in constructor is also provided: + * + * reducer(move_in(List& variable)) + * + * A list reducer with no constructor arguments, or with only an allocator + * argument, will initially contain the identity value, an empty list. + * + * @subsection redlist_get_set Set and Get + * + * r.set_value(const List& value) + * const List& = r.get_value() const + * r.move_in(List& variable) + * r.move_out(List& variable) + * + * @subsection redlist_view_ops View Operations + * + * The view of a list append reducer provides the following member functions: + * + * void push_back(const Type& element) + * void insert_back(List::size_type n, const Type& element) + * template <typename Iter> void insert_back(Iter first, Iter last) + * void splice_back(List& x) + * void splice_back(List& x, List::iterator i) + * void splice_back(List& x, List::iterator first, List::iterator last) + * + * The view of a list prepend reducer provides the following member functions: + * + * void push_front(const Type& element) + * void insert_front(List::size_type n, const Type& element) + * template <typename Iter> void insert_front(Iter first, Iter last) + * void splice_front(List& x) + * void splice_front(List& x, List::iterator i) + * void splice_front(List& x, List::iterator first, List::iterator last) + * + * The `push_back` and `push_front` functions are the same as the + * corresponding `std::list` functions. The `insert_back`, `splice_back`, + * `insert_front`, and `splice_front` functions are the same as the + * `std::list` `insert` and `splice` functions, with the first parameter + * fixed to the end or beginning of the list, respectively. + * + * @section redlist_performance Performance Considerations + * + * An efficient reducer requires that combining the values of two views (using + * the view `reduce()` function) be a constant-time operations. Two lists can + * be merged in constant time using the `splice()` function if they have the + * same allocator. Therefore, the lists for new views are created (by the view + * identity constructor) using the same allocator as the list that was created + * when the reducer was constructed. + * + * The performance of adding elements to a list reducer depends on the view + * operations that are used: + * + * * The `push` functions add a single element to the list, and therefore + * take constant time. + * * An `insert` function that inserts _N_ elements adds each of them + * individually, and therefore takes _O(N)_ time. + * * A `splice` function that inserts _N_ elements just adjusts a couple of + * pointers, and therefore takes constant time, _if the splice is from a + * list with the same allocator as the reducer_. Otherwise, it is + * equivalent to an `insert`, and takes _O(N)_ time. + * + * This means that for best performance, if you will be adding elements to a + * list reducer in batches, you should `splice` them from a list having the + * same allocator as the reducer. + * + * The reducer `move_in` and `move_out` functions do a constant-time `swap` if + * the variable has the same allocator as the reducer, and a linear-time copy + * otherwise. + * + * Note that the allocator of a list reducer is determined when the reducer is + * constructed. The following two examples may have very different behavior: + * + * list<Element, Allocator> a_list; + * + * reducer< list_append<Element, Allocator> reducer1(move_in(a_list)); + * ... parallel computation ... + * reducer1.move_out(a_list); + * + * reducer< list_append<Element, Allocator> reducer2; + * reducer2.move_in(a_list); + * ... parallel computation ... + * reducer2.move_out(a_list); + * + * * `reducer1` will be constructed with the same allocator as `a_list`, + * because the list was was specified in the constructor. The `move_in` + * and`move_out` can therefore be done with a `swap` in constant time. + * * `reducer2` will be constructed with a _default_ allocator, + * “`Allocator()`”, which may or may not be the same as the allocator of + * `a_list`. Therefore, the `move_in` and `move_out` may have to be done + * with a copy in _O(N)_ time. + * + * (All instances of an allocator type with no internal state (like + * `std::allocator`) are “the same”. You only need to worry about the “same + * allocator” issue when you create list reducers with custom allocator types.) + * + * @section redlist_types Type and Operator Requirements + * + * `std::list<Type, Allocator>` must be a valid type. + */ + + +namespace cilk { + +namespace internal { + +/** @ingroup ReducersList */ +//@{ + +/** Base class for list append and prepend view classes. + * + * @note This class provides the definitions that are required for a class + * that will be used as the parameter of a @ref list_monoid_base + * specialization. + * + * @tparam Type The list element type (not the list type). + * @tparam Allocator The list's allocator class. + * + * @see ReducersList + * @see list_monoid_base + */ +template <typename Type, typename Allocator> +class list_view_base +{ +protected: + /// The type of the contained list. + typedef std::list<Type, Allocator> list_type; + + /// The list accumulator variable. + list_type m_value; + +public: + + /** @name Monoid support. + */ + //@{ + + /// Required by @ref monoid_with_view + typedef list_type value_type; + + /// Required by @ref list_monoid_base + Allocator get_allocator() const + { + return m_value.get_allocator(); + } + + //@} + + + /** @name Constructors. + */ + //@{ + + /// Standard list constructor. + explicit list_view_base(const Allocator& a = Allocator()) : m_value(a) {} + explicit list_view_base( + typename list_type::size_type n, + const Type& value = Type(), + const Allocator& a = Allocator() ) : m_value(n, value, a) {} + template <typename Iter> + list_view_base(Iter first, Iter last, const Allocator& a = Allocator()) : + m_value(first, last, a) {} + list_view_base(const list_type& list) : m_value(list) {} + + /// Move-in constructor. + explicit list_view_base(move_in_wrapper<value_type> w) + : m_value(w.value().get_allocator()) + { + m_value.swap(w.value()); + } + + //@} + + /** @name Reducer support. + */ + //@{ + + /// Required by reducer::move_in() + void view_move_in(value_type& v) + { + if (m_value.get_allocator() == v.get_allocator()) + // Equal allocators. Do a (fast) swap. + m_value.swap(v); + else + // Unequal allocators. Do a (slow) copy. + m_value = v; + v.clear(); + } + + /// Required by reducer::move_out() + void view_move_out(value_type& v) + { + if (m_value.get_allocator() == v.get_allocator()) + // Equal allocators. Do a (fast) swap. + m_value.swap(v); + else + // Unequal allocators. Do a (slow) copy. + v = m_value; + m_value.clear(); + } + + /// Required by reducer::set_value() + void view_set_value(const value_type& v) { m_value = v; } + + /// Required by reducer::get_value() + value_type const& view_get_value() const { return m_value; } + + // Required by legacy wrapper get_reference() + value_type & view_get_reference() { return m_value; } + value_type const& view_get_reference() const { return m_value; } + + //@} +}; + + +/** Base class for list append and prepend monoid classes. + * + * The key to efficient reducers is that the `identity` operation, which + * creates a new per-strand view, and the `reduce` operation, which combines + * two per-strand views, must be constant-time operations. Two lists can be + * concatenated in constant time only if they have the same allocator. + * Therefore, all the per-strand list accumulator variables must be created + * with the same allocator as the leftmost view list. + * + * This means that a list reduction monoid must have a copy of the allocator + * of the leftmost view’s list, so that it can use it in the `identity` + * operation. This, in turn, requires that list reduction monoids have a + * specialized `construct()` function, which constructs the leftmost view + * before the monoid, and then passes the leftmost view’s allocator to the + * monoid constructor. + * + * @tparam View The list append or prepend view class. + * @tparam Align If `false` (the default), reducers instantiated on this + * monoid will be naturally aligned (the Cilk library 1.0 + * behavior). If `true`, reducers instantiated on this monoid + * will be cache-aligned for binary compatibility with + * reducers in Cilk library version 0.9. + * + * @see ReducersList + * @see list_view_base + */ +template <typename View, bool Align> +class list_monoid_base : public monoid_with_view<View, Align> +{ + typedef typename View::value_type list_type; + typedef typename list_type::allocator_type allocator_type; + allocator_type m_allocator; + + using monoid_base<list_type, View>::provisional; + +public: + + /** Constructor. + * + * There is no default constructor for list monoids, because the allocator + * must always be specified. + * + * @param allocator The list allocator to be used when + * identity-constructing new views. + */ + list_monoid_base(const allocator_type& allocator = allocator_type()) : + m_allocator(allocator) {} + + /** Create an identity view. + * + * List view identity constructors take the list allocator as an argument. + * + * @param v The address of the uninitialized memory in which the view + * will be constructed. + */ + void identity(View *v) const { ::new((void*) v) View(m_allocator); } + + /** @name construct functions + * + * All `construct()` functions first construct the leftmost view, using + * the optional @a x1, @a x2, and @a x3 arguments that were passed in from + * the reducer constructor. They then call the view’s `get_allocator()` + * function to get the list allocator from its contained list, and pass it + * to the monoid constructor. + */ + //@{ + + template <typename Monoid> + static void construct(Monoid* monoid, View* view) + { provisional( new ((void*)view) View() ).confirm_if( + new ((void*)monoid) Monoid(view->get_allocator()) ); } + + template <typename Monoid, typename T1> + static void construct(Monoid* monoid, View* view, const T1& x1) + { provisional( new ((void*)view) View(x1) ).confirm_if( + new ((void*)monoid) Monoid(view->get_allocator()) ); } + + template <typename Monoid, typename T1, typename T2> + static void construct(Monoid* monoid, View* view, const T1& x1, const T2& x2) + { provisional( new ((void*)view) View(x1, x2) ).confirm_if( + new ((void*)monoid) Monoid(view->get_allocator()) ); } + + template <typename Monoid, typename T1, typename T2, typename T3> + static void construct(Monoid* monoid, View* view, const T1& x1, const T2& x2, + const T3& x3) + { provisional( new ((void*)view) View(x1, x2, x3) ).confirm_if( + new ((void*)monoid) Monoid(view->get_allocator()) ); } + + //@} +}; + +//@} + +} // namespace internal + + +/** @ingroup ReducersList */ +//@{ + +/** The list append reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_list_append<Type, Allocator> >`. It holds the + * accumulator variable for the reduction, and allows only append operations + * to be performed on it. + * + * @note The reducer “dereference” operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `push_back` operation would be used in an expression like + * `r->push_back(a)`, where `r` is a list append reducer variable. + * + * @tparam Type The list element type (not the list type). + * @tparam Allocator The list allocator type. + * + * @see ReducersList + * @see op_list_append + */ +template <class Type, + class Allocator = typename std::list<Type>::allocator_type> +class op_list_append_view : public internal::list_view_base<Type, Allocator> +{ + typedef internal::list_view_base<Type, Allocator> base; + typedef std::list<Type, Allocator> list_type; + typedef typename list_type::iterator iterator; + + iterator end() { return this->m_value.end(); } + +public: + + /** @name Constructors. + * + * All op_list_append_view constructors simply pass their arguments on to + * the @ref internal::list_view_base base class constructor. + * + * @ref internal::list_view_base supports all the std::list constructor + * forms, as well as the reducer move_in constructor form. + */ + //@{ + + op_list_append_view() : base() {} + + template <typename T1> + op_list_append_view(const T1& x1) : base(x1) {} + + template <typename T1, typename T2> + op_list_append_view(const T1& x1, const T2& x2) : base(x1, x2) {} + + template <typename T1, typename T2, typename T3> + op_list_append_view(const T1& x1, const T2& x2, const T3& x3) : + base(x1, x2, x3) {} + + //@} + + /** @name View modifier operations. + */ + //@{ + + /** Add an element at the end of the list. + * + * This is equivalent to `list.push_back(element)` + */ + void push_back(const Type& element) + { this->m_value.push_back(element); } + + /** Insert elements at the end of the list. + * + * This is equivalent to `list.insert(list.end(), n, element)` + */ + void insert_back(typename list_type::size_type n, const Type& element) + { this->m_value.insert(end(), n, element); } + + /** Insert elements at the end of the list. + * + * This is equivalent to `list.insert(list.end(), first, last)` + */ + template <typename Iter> + void insert_back(Iter first, Iter last) + { this->m_value.insert(end(), first, last); } + + /** Splice elements at the end of the list. + * + * This is equivalent to `list.splice(list.end(), x)` + */ + void splice_back(list_type& x) { + if (x.get_allocator() == this->m_value.get_allocator()) + this->m_value.splice(end(), x); + else { + insert_back(x.begin(), x.end()); + x.clear(); + } + } + + /** Splice elements at the end of the list. + * + * This is equivalent to `list.splice(list.end(), x, i)` + */ + void splice_back(list_type& x, iterator i) { + if (x.get_allocator() == this->m_value.get_allocator()) + this->m_value.splice(end(), x, i); + else { + push_back(*i); + x.erase(i); + } + } + + /** Splice elements at the end of the list. + * + * This is equivalent to `list.splice(list.end(), x, first, last)` + */ + void splice_back(list_type& x, iterator first, iterator last) { + if (x.get_allocator() == this->m_value.get_allocator()) + this->m_value.splice(end(), x, first, last); + else { + insert_back(first, last); + x.erase(first, last); + } + } + + //@} + + /** Reduction operation. + * + * This function is invoked by the @ref op_list_append monoid to combine + * the views of two strands when the right strand merges with the left + * one. It appends the value contained in the right-strand view to the + * value contained in the left-strand view, and leaves the value in the + * right-strand view undefined. + * + * @param right A pointer to the right-strand view. (`this` points to + * the left-strand view.) + * + * @note Used only by the @ref op_list_append monoid to implement the + * monoid reduce operation. + */ + void reduce(op_list_append_view* right) + { + __CILKRTS_ASSERT( + this->m_value.get_allocator() == right->m_value.get_allocator()); + this->m_value.splice(end(), right->m_value); + } +}; + + +/** The list prepend reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_list_prepend<Type, Allocator> >`. It holds the + * accumulator variable for the reduction, and allows only prepend operations + * to be performed on it. + * + * @note The reducer “dereference” operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `push_front` operation would be used in an expression like + * `r->push_front(a)`, where `r` is a list prepend reducer variable. + * + * @tparam Type The list element type (not the list type). + * @tparam Allocator The list allocator type. + * + * @see ReducersList + * @see op_list_prepend + */ +template <class Type, + class Allocator = typename std::list<Type>::allocator_type> +class op_list_prepend_view : public internal::list_view_base<Type, Allocator> +{ + typedef internal::list_view_base<Type, Allocator> base; + typedef std::list<Type, Allocator> list_type; + typedef typename list_type::iterator iterator; + + iterator begin() { return this->m_value.begin(); } + +public: + + /** @name Constructors. + * + * All op_list_prepend_view constructors simply pass their arguments on to + * the @ref internal::list_view_base base class constructor. + * + * @ref internal::list_view_base supports all the std::list constructor + * forms, as well as the reducer move_in constructor form. + * + */ + //@{ + + op_list_prepend_view() : base() {} + + template <typename T1> + op_list_prepend_view(const T1& x1) : base(x1) {} + + template <typename T1, typename T2> + op_list_prepend_view(const T1& x1, const T2& x2) : base(x1, x2) {} + + template <typename T1, typename T2, typename T3> + op_list_prepend_view(const T1& x1, const T2& x2, const T3& x3) : + base(x1, x2, x3) {} + + //@} + + /** @name View modifier operations. + */ + //@{ + + /** Add an element at the beginning of the list. + * + * This is equivalent to `list.push_front(element)` + */ + void push_front(const Type& element) + { this->m_value.push_front(element); } + + /** Insert elements at the beginning of the list. + * + * This is equivalent to `list.insert(list.begin(), n, element)` + */ + void insert_front(typename list_type::size_type n, const Type& element) + { this->m_value.insert(begin(), n, element); } + + /** Insert elements at the beginning of the list. + * + * This is equivalent to `list.insert(list.begin(), first, last)` + */ + template <typename Iter> + void insert_front(Iter first, Iter last) + { this->m_value.insert(begin(), first, last); } + + /** Splice elements at the beginning of the list. + * + * This is equivalent to `list.splice(list.begin(), x)` + */ + void splice_front(list_type& x) { + if (x.get_allocator() == this->m_value.get_allocator()) + this->m_value.splice(begin(), x); + else { + insert_front(x.begin(), x.begin()); + x.clear(); + } + } + + /** Splice elements at the beginning of the list. + * + * This is equivalent to `list.splice(list.begin(), x, i)` + */ + void splice_front(list_type& x, iterator i) { + if (x.get_allocator() == this->m_value.get_allocator()) + this->m_value.splice(begin(), x, i); + else { + push_front(*i); + x.erase(i); + } + } + + /** Splice elements at the beginning of the list. + * + * This is equivalent to `list.splice(list.begin(), x, first, last)` + */ + void splice_front(list_type& x, iterator first, iterator last) { + if (x.get_allocator() == this->m_value.get_allocator()) + this->m_value.splice(begin(), x, first, last); + else { + insert_front(first, last); + x.erase(first, last); + } + } + + //@} + + /** Reduction operation. + * + * This function is invoked by the @ref op_list_prepend monoid to combine + * the views of two strands when the right strand merges with the left + * one. It prepends the value contained in the right-strand view to the + * value contained in the left-strand view, and leaves the value in the + * right-strand view undefined. + * + * @param right A pointer to the right-strand view. (`this` points to + * the left-strand view.) + * + * @note Used only by the @ref op_list_prepend monoid to implement the + * monoid reduce operation. + */ + /** Reduce operation. + * + * Required by @ref monoid_base. + */ + void reduce(op_list_prepend_view* right) + { + __CILKRTS_ASSERT( + this->m_value.get_allocator() == right->m_value.get_allocator()); + this->m_value.splice(begin(), right->m_value); + } +}; + + + +/** Monoid class for list append reductions. Instantiate the cilk::reducer + * template class with a op_list_append monoid to create a list append reducer + * class. For example, to create a list of strings: + * + * cilk::reducer< cilk::op_list_append<std::string> > r; + * + * @tparam Type The list element type (not the list type). + * @tparam Alloc The list allocator type. + * @tparam Align If `false` (the default), reducers instantiated on this + * monoid will be naturally aligned (the Cilk library 1.0 + * behavior). If `true`, reducers instantiated on this monoid + * will be cache-aligned for binary compatibility with + * reducers in Cilk library version 0.9. + * + * @see ReducersList + * @see op_list_append_view + */ +template <typename Type, + typename Allocator = typename std::list<Type>::allocator_type, + bool Align = false> +struct op_list_append : + public internal::list_monoid_base<op_list_append_view<Type, Allocator>, Align> +{ + /// Construct with default allocator. + op_list_append() {} + /// Construct with specified allocator. + op_list_append(const Allocator& alloc) : + internal::list_monoid_base<op_list_append_view<Type, Allocator>, Align>(alloc) {} +}; + +/** Monoid class for list prepend reductions. Instantiate the cilk::reducer + * template class with a op_list_prepend monoid to create a list prepend + * reducer class. For example, to create a list of strings: + * + * cilk::reducer< cilk::op_list_prepend<std::string> > r; + * + * @tparam Type The list element type (not the list type). + * @tparam Alloc The list allocator type. + * @tparam Align If `false` (the default), reducers instantiated on this + * monoid will be naturally aligned (the Cilk library 1.0 + * behavior). If `true`, reducers instantiated on this monoid + * will be cache-aligned for binary compatibility with + * reducers in Cilk library version 0.9. + * + * @see ReducersList + * @see op_list_prepend_view + */ +template <typename Type, + typename Allocator = typename std::list<Type>::allocator_type, + bool Align = false> +struct op_list_prepend : + public internal::list_monoid_base<op_list_prepend_view<Type, Allocator>, Align> +{ + /// Construct with default allocator. + op_list_prepend() {} + /// Construct with specified allocator. + op_list_prepend(const Allocator& alloc) : + internal::list_monoid_base<op_list_prepend_view<Type, Allocator>, Align>(alloc) {} +}; + + +/** Deprecated list append reducer wrapper class. + * + * reducer_list_append is the same as + * @ref reducer<@ref op_list_append>, except that reducer_list_append is a + * proxy for the contained view, so that accumulator variable update + * operations can be applied directly to the reducer. For example, an element + * is appended to a `reducer<%op_list_append>` with `r->push_back(a)`, but an + * element can be appended to a `%reducer_list_append` with `r.push_back(a)`. + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_list_append. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_list_append` + * and `reducer<%op_list_append>`. This allows incremental code + * conversion: old code that used `%reducer_list_append` can pass a + * `%reducer_list_append` to a converted function that now expects a + * pointer or reference to a `reducer<%op_list_append>`, and vice + * versa. + * + * @tparam Type The value type of the list. + * @tparam Allocator The allocator type of the list. + * + * @see op_list_append + * @see reducer + * @see ReducersList + */ +template <class Type, class Allocator = std::allocator<Type> > +class reducer_list_append : + public reducer<op_list_append<Type, Allocator, true> > +{ + typedef reducer<op_list_append<Type, Allocator, true> > base; + using base::view; +public: + + /// The reducer’s list type. + typedef typename base::value_type list_type; + + /// The list’s element type. + typedef Type list_value_type; + + /// The reducer’s primitive component type. + typedef Type basic_value_type; + + /// The monoid type. + typedef typename base::monoid_type Monoid; + + /** @name Constructors + */ + //@{ + + /** Construct a reducer with an empty list. + */ + reducer_list_append() {} + + /** Construct a reducer with a specified initial list value. + */ + reducer_list_append(const std::list<Type, Allocator> &initial_value) : + base(initial_value) {} + + //@} + + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_and_view. */ + //@{ + + /// @copydoc op_list_append_view::push_back(const Type&) + void push_back(const Type& element) { view().push_back(element); } + + //@} + + /** Allow mutable access to the list within the current view. + * + * @warning If this method is called before the parallel calculation is + * complete, the list returned by this method will be a partial + * result. + * + * @returns A mutable reference to the list within the current view. + */ + list_type &get_reference() { return view().view_get_reference(); } + + /** Allow read-only access to the list within the current view. + * + * @warning If this method is called before the parallel calculation is + * complete, the list returned by this method will be a partial + * result. + * + * @returns A const reference to the list within the current view. + */ + list_type const &get_reference() const { return view().view_get_reference(); } + + /// @name Dereference + //@{ + /** Dereferencing a wrapper is a no-op. It simply returns the wrapper. + * Combined with the rule that a wrapper forwards view operations to the + * view, this means that view operations can be written the same way on + * reducers and wrappers, which is convenient for incrementally + * converting code using wrappers to code using reducers. That is: + * + * reducer< op_list_append<int> > r; + * r->push_back(a); // *r returns the view + * // push_back is a view member function + * + * reducer_list_append<int> w; + * w->push_back(a); // *w returns the wrapper + * // push_back is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_list_append& operator*() { return *this; } + reducer_list_append const& operator*() const { return *this; } + + reducer_list_append* operator->() { return this; } + reducer_list_append const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_list_append<Type, Allocator, false> >& () + { + return *reinterpret_cast< + reducer< op_list_append<Type, Allocator, false> >* + >(this); + } + operator const reducer< op_list_append<Type, Allocator, false> >& () const + { + return *reinterpret_cast< + const reducer< op_list_append<Type, Allocator, false> >* + >(this); + } + //@} + +}; + + +/** Deprecated list prepend reducer wrapper class. + * + * reducer_list_prepend is the same as + * @ref reducer<@ref op_list_prepend>, except that reducer_list_prepend is a + * proxy for the contained view, so that accumulator variable update operations + * can be applied directly to the reducer. For example, an element is prepended + * to a `reducer<op_list_prepend>` with `r->push_back(a)`, but an element is + * prepended to a `reducer_list_prepend` with `r.push_back(a)`. + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_list_prepend. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_list_prepend` + * and `reducer<%op_list_prepend>`. This allows incremental code + * conversion: old code that used `%reducer_list_prepend` can pass a + * `%reducer_list_prepend` to a converted function that now expects a + * pointer or reference to a `reducer<%op_list_prepend>`, and vice + * versa. + * + * @tparam Type The value type of the list. + * @tparam Allocator The allocator type of the list. + * + * @see op_list_prepend + * @see reducer + * @see ReducersList + */ +template <class Type, class Allocator = std::allocator<Type> > +class reducer_list_prepend : + public reducer<op_list_prepend<Type, Allocator, true> > +{ + typedef reducer<op_list_prepend<Type, Allocator, true> > base; + using base::view; +public: + + /** The reducer’s list type. + */ + typedef typename base::value_type list_type; + + /** The list’s element type. + */ + typedef Type list_value_type; + + /** The reducer’s primitive component type. + */ + typedef Type basic_value_type; + + /** The monoid type. + */ + typedef typename base::monoid_type Monoid; + + /** @name Constructors + */ + //@{ + + /** Construct a reducer with an empty list. + */ + reducer_list_prepend() {} + + /** Construct a reducer with a specified initial list value. + */ + reducer_list_prepend(const std::list<Type, Allocator> &initial_value) : + base(initial_value) {} + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_and_view. + */ + //@{ + + /// @copydoc op_list_prepend_view::push_front(const Type&) + void push_front(const Type& element) { view().push_front(element); } + + //@} + + /** Allow mutable access to the list within the current view. + * + * @warning If this method is called before the parallel calculation is + * complete, the list returned by this method will be a partial + * result. + * + * @returns A mutable reference to the list within the current view. + */ + list_type &get_reference() { return view().view_get_reference(); } + + /** Allow read-only access to the list within the current view. + * + * @warning If this method is called before the parallel calculation is + * complete, the list returned by this method will be a partial + * result. + * + * @returns A const reference to the list within the current view. + */ + list_type const &get_reference() const { return view().view_get_reference(); } + + /// @name Dereference + /** Dereferencing a wrapper is a no-op. It simply returns the wrapper. + * Combined with the rule that a wrapper forwards view operations to the + * view, this means that view operations can be written the same way on + * reducers and wrappers, which is convenient for incrementally + * converting code using wrappers to code using reducers. That is: + * + * reducer< op_list_prepend<int> > r; + * r->push_front(a); // *r returns the view + * // push_front is a view member function + * + * reducer_list_prepend<int> w; + * w->push_front(a); // *w returns the wrapper + * // push_front is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_list_prepend& operator*() { return *this; } + reducer_list_prepend const& operator*() const { return *this; } + + reducer_list_prepend* operator->() { return this; } + reducer_list_prepend const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_list_prepend<Type, Allocator, false> >& () + { + return *reinterpret_cast< + reducer< op_list_prepend<Type, Allocator, false> >* + >(this); + } + operator const reducer< op_list_prepend<Type, Allocator, false> >& () const + { + return *reinterpret_cast< + const reducer< op_list_prepend<Type, Allocator, false> >* + >(this); + } + //@} + +}; + +/// @cond internal + +/** Metafunction specialization for reducer conversion. + * + * This specialization of the @ref legacy_reducer_downcast template class + * defined in reducer.h causes the `reducer< op_list_append<Type, Allocator> >` + * class to have an `operator reducer_list_append<Type, Allocator>& ()` + * conversion operator that statically downcasts the `reducer<op_list_append>` + * to the corresponding `reducer_list_append` type. (The reverse conversion, + * from `reducer_list_append` to `reducer<op_list_append>`, is just an upcast, + * which is provided for free by the language.) + */ +template <class Type, class Allocator, bool Align> +struct legacy_reducer_downcast<reducer<op_list_append<Type, Allocator, Align> > > +{ + typedef reducer_list_append<Type, Allocator> type; +}; + +/** Metafunction specialization for reducer conversion. + * + * This specialization of the @ref legacy_reducer_downcast template class + * defined in reducer.h causes the + * `reducer< op_list_prepend<Type, Allocator> >` class to have an + * `operator reducer_list_prepend<Type, Allocator>& ()` conversion operator + * that statically downcasts the `reducer<op_list_prepend>` to the + * corresponding `reducer_list_prepend` type. (The reverse conversion, from + * `reducer_list_prepend` to `reducer<op_list_prepend>`, is just an upcast, + * which is provided for free by the language.) + */ +template <class Type, class Allocator, bool Align> +struct legacy_reducer_downcast<reducer<op_list_prepend<Type, Allocator, Align> > > +{ + typedef reducer_list_prepend<Type, Allocator> type; +}; + +/// @endcond + +//@} + +} // Close namespace cilk + +#endif // REDUCER_LIST_H_INCLUDED diff --git a/libcilkrts/include/cilk/reducer_max.h b/libcilkrts/include/cilk/reducer_max.h new file mode 100644 index 00000000000..3ba3a0bc8ac --- /dev/null +++ b/libcilkrts/include/cilk/reducer_max.h @@ -0,0 +1,46 @@ +/* reducer_max.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_max.h + * + * @brief Defines classes for doing parallel maximum reductions. + * + * @ingroup ReducersMinMax + * + * @see ReducersMinMax + */ + +#include "reducer_min_max.h" diff --git a/libcilkrts/include/cilk/reducer_min.h b/libcilkrts/include/cilk/reducer_min.h new file mode 100644 index 00000000000..f5a3910850e --- /dev/null +++ b/libcilkrts/include/cilk/reducer_min.h @@ -0,0 +1,46 @@ +/* reducer_min.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_min.h + * + * @brief Defines classes for doing parallel minimum reductions. + * + * @ingroup ReducersMinMax + * + * @see ReducersMinMax + */ + +#include "reducer_min_max.h" diff --git a/libcilkrts/include/cilk/reducer_min_max.h b/libcilkrts/include/cilk/reducer_min_max.h new file mode 100644 index 00000000000..55f068c34a3 --- /dev/null +++ b/libcilkrts/include/cilk/reducer_min_max.h @@ -0,0 +1,3606 @@ +/* reducer_min_max.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_min_max.h + * + * @brief Defines classes for doing parallel minimum and maximum reductions. + * + * @ingroup ReducersMinMax + * + * @see ReducersMinMax + */ + +#ifndef REDUCER_MIN_MAX_H_INCLUDED +#define REDUCER_MIN_MAX_H_INCLUDED + +#include <cilk/reducer.h> + +#ifdef __cplusplus + +#include <algorithm> +#include <limits> + +/** @defgroup ReducersMinMax Minimum and Maximum Reducers + * + * Minimum and maximum reducers allow the computation of the minimum or + * maximum of a set of values in parallel. + * + * @ingroup Reducers + * + * You should be familiar with @ref pagereducers "Cilk reducers", described in + * file `reducers.md`, and particularly with @ref reducers_using, before trying + * to use the information in this file. + * + * @section redminmax_usage Usage Examples + * + * cilk::reducer< cilk::op_max<int> > rm; + * cilk_for (int i = 0; i < ARRAY_SIZE; ++i) + * { + * rm->calc_max(a[i]); // or *rm = cilk::max_of(*max, a[i]) + * } + * std::cout << "maximum value is " << rm.get_value() << std::endl; + * + * and + * + * cilk::reducer< cilk::op_min_index<int, double> > rmi; + * cilk_for (int i = 0; i < ARRAY_SIZE; ++i) + * { + * rmi->calc_min(i, a[i]) // or *rmi = cilk::min_of(*rmi, i, a[i]); + * } + * std::cout << "minimum value a[" << rmi.get_value().first << "] = " + * << rmi.get_value().second << std::endl; + * + * @section redminmax_monoid The Monoid + * + * @subsection redminmax_monoid_values Value Set + * + * The value set of a minimum or maximum reducer is the set of values of + * `Type`, possibly augmented with a special identity value which is greater + * than (less than) any value of `Type`. + * + * @subsection redminmax_monoid_operator Operator + * + * In the most common case, the operator of a minimum reducer is defined as + * + * x MIN y == (x < y) ? x : y + * + * Thus, `a1 MIN a2 MIN … an` is the first `ai` which is not greater than any + * other `ai`. + * + * The operator of a maximum reducer is defined as + * + * x MAX y == (x > y) ? x : y + * + * Thus, `a1 MAX a2 MAX … an` is the first `ai` which is not less than any + * other `ai`. + * + * @subsection redminmax_monoid_comparators Comparators + * + * Min/max reducers are not limited to finding the minimum or maximum value + * determined by the `<` or `>` operator. In fact, all min/max reducers use a + * _comparator_, which is either a function or an object of a function class + * that defines a [strict weak ordering] + * (http://en.wikipedia.org/wiki/Strict_weak_ordering#Strict_weak_orderings) + * on a set of values. (This is exactly the same as the requirement for the + * comparison predicate for STL associative containers and sorting + * algorithms.) + * + * Just as with STL algorithms and containers, the comparator type parameter + * for min/max reducers is optional. If it is omitted, it defaults to + * `std::less`, which gives the behavior described in the previous section. + * Using non-default comparators (anything other than `std::less`) with + * min/max reducers is just like using them with STL containers and + * algorithms. + * + * Taking comparator objects into account, the reduction operation `MIN` for a + * minimum reducer is defined as + * + * x MIN y == compare(x, y) ? x : y + * + * where `compare()` is the reducer’s comparator. Similarly, the reduction + * operation MAX for a maximum reducer is defined as + * + * x MAX y == compare(y, x) ? x : y + * + * (If `compare(x, y) == x < y`, then `compare(y, x) == x > y`.) + * + * @subsection redminmax_monoid_identity Identity + * + * The identity value of the reducer is the value which is greater than (less + * than) any other value in the value set of the reducer. This is the + * [“special identity value”](#redminmax_monoid_values) if the reducer has + * one, or the largest (smallest) value in the value set otherwise. + * + * @section redminmax_index Value and Index Reducers + * + * Min/max reducers come in two families. The _value_ reducers, using `op_min` + * and `op_max` monoids, simply find the smallest or largest value from a set + * of values. The _index_ reducers, using `op_min_index` and `op_max_index` + * monoids, also record an index value associated with the first occurrence of + * the smallest or largest value. + * + * In the `%op_min_index` usage example [above](#redminmax_usage), the values + * are taken from an array, and the index of a value is the index of the array + * element it comes from. More generally, though, an index can be any sort of + * key which identifies a particular value in a collection of values. For + * example, if the values were taken from the nodes of a tree, then the + * “index” of a value might be a pointer to the node containing that value. + * + * A min/max index reducer is essentially the same as a min/max value reducer + * whose value type is an (index, value) pair, and whose comparator ignores + * the index part of the pair. (index, value) pairs are represented by + * `std::pair<Index, Type>` objects. This has the consequence that wherever + * the interface of a min/max value reducer has a `Type`, the interface of the + * corresponding min/max index reducer has a `std::pair<Index, Type>`. (There + * are convenience variants of the `reducer(Type)` constructor and the + * `calc_min()`, `calc_max()`, `%min_of()`, and `%max_of()` functions that + * take an index argument and a value argument instead of an index/value + * pair.) + * + * @section redminmax_operations Operations + * + * @subsection redminmax_constructors Constructors + * + * @subsubsection redminmax_constructors_value Min/Max Value Reducers + * + * reducer() // identity + * reducer(const Compare& compare) // identity + * reducer(const Type& value) + * reducer(move_in(Type& variable)) + * reducer(const Type& value, const Compare& compare) + * reducer(move_in(Type& variable), const Compare& compare) + * + * @subsubsection redminmax_constructors_index Min/Max Index Reducers + * + * reducer() // identity + * reducer(const Compare& compare) // identity + * reducer(const std::pair<Index, Type>& pair) + * reducer(const Index& index, const Type& value) + * reducer(move_in(std::pair<Index, Type>& variable)) + * reducer(const std::pair<Index, Type>& pair, const Compare& compare) + * reducer(const Index& index, const Type& value, const Compare& compare) + * reducer(move_in(std::pair<Index, Type>& variable), const Compare& compare) + * + * @subsection redminmax_get_set Set and Get + * + * r.set_value(const Type& value) + * Type = r.get_value() const + * r.move_in(Type& variable) + * r.move_out(Type& variable) + * + * Note that for an index reducer, the `Type` in these operations is actually a + * `std::pair<Index, Type>`. (See @ref redminmax_index.) There is _not_ a + * `set_value(value, index)` operation. + * + * @subsection redminmax_initial Initial Values and is_set() + * + * A minimum or maximum reducer without a specified initial value, before any + * MIN or MAX operation has been performed on it, represents the [identity + * value](#redminmax_monoid_identity) of its monoid. For value reducers with a + * numeric type and default comparator (`std::less`), this will be a well + * defined value. For example, + * + * reducer< op_max<unsigned> > r1; + * // r1.get_value() == 0 + * + * reducer< op_min<float> > r2; + * // r2.get_value() == std::numeric_limits<float>::infinity + * + * In other cases, though (index reducers, non-numeric types, or non-default + * comparators), the actual identity value for the monoid may be unknown, or + * it may not even be a value of the reducer’s type. For example, there is no + * “largest string” to serve as the initial value for a + * `reducer< op_min<std::string> >`. In these cases, the result of calling + * `get_value()` is undefined. + * + * To avoid calling `get_value()` when its result is undefined, you can call + * the view’s `is_set()` function, which will return true if the reducer + * has a well-defined value — either because a MIN or MAX operation has been + * performed, or because it had a well-defined initial value: + * + * reducer< op_max<unsigned> > r1; + * // r1->is_set() == true + * // r1.get_value() == 0 + * + * reducer< op_min<std::string> > r2; + * // r2->is_set() == false + * // r2.get_value() is undefined + * r2->calc_min("xyzzy"); + * // r2->is_set() == true + * // r2.get_value() == "xyzzy" + * + * > Note: For an index reducer without a specified initial value, the + * > initial value of the index is the default value of the `Index` type. + * + * @subsection redminmax_view_ops View Operations + * + * The basic reduction operation is `x = x MIN a` for a minimum reducer, or + * `x = x MAX a` for a maximum reducer. The basic syntax for these operations + * uses the `calc_min()` and `calc_max()` member functions of the view class. + * An assignment syntax is also provided, using the %cilk::min_of() and + * %cilk::max_of() global functions: + * + * Class | Modifier | Assignment + * ---------------|---------------------|----------- + * `op_min` | `r->calc_min(x)` | `*r = min_of(*r, x)` or `*r = min_of(x, *r)` + * `op_max` | `r->calc_max(x)` | `*r = max_of(*r, x)` or `*r = max_of(x, *r)` + * `op_min_index` | `r->calc_min(i, x)` | `*r = min_of(*r, i, x)` or `*r = min_of(i, x, *r)` + * `op_max_index` | `r->calc_max(i, x)` | `*r = max_of(*r, i, x)` or `*r = max_of(i, x, *r)` + * + * Wherever an “`i`, `x`” argument pair is shown in the table above, a single + * pair argument may be passed instead. For example: + * + * Index index; + * Type value; + * std::pair<Index, Type> ind_val(index, value); + * // The following statements are all equivalent. + * r->calc_min(index, value); + * r->calc_min(ind_val); + * *r = min_of(*r, index, value); + * *r = min_of(*r, ind_val); + * + * The `calc_min()` and `calc_max()` member functions return a reference to + * the view, so they can be chained: + * + * r->calc_max(x).calc_max(y).calc_max(z); + * + * In a `%min_of()` or `%max_of()` assignment, the view on the left-hand side + * of the assignment must be the same as the view argument in the call. + * Otherwise, the behavior is undefined (but an assertion error will occur if + * the code is compiled with debugging enabled). + * + * *r = max_of(*r, x); // OK + * *r1 = max_of(*r2, y); // ERROR + * + * `%min_of()` and `%max_of()` calls can be nested: + * + * *r = max_of(max_of(max_of(*r, x), y), z); + * *r = min_of(i, a[i], min_of(j, a[j], min_of(k, a[k], *r))); + * + * @section redminmax_compatibility Compatibility Issues + * + * Most Cilk library reducers provide + * * Binary compatibility between `reducer_KIND` reducers compiled with Cilk + * library version 0.9 (distributed with Intel® C++ Composer XE version + * 13.0 and earlier) and the same reducers compiled with Cilk library + * version 1.0 and later. + * * Transparent casting between references to `reducer<op_KIND>` and + * `reducer_KIND`. + * + * This compatibility is not available in all cases for min/max reducers. + * There are two areas of incompatibility. + * + * @subsection redminmax_compatibility_stateful Non-empty Comparators + * + * There is no way to provide binary compatibility between the 0.9 and 1.0 + * definitions of min/max reducers that use a non-empty comparator class or a + * comparator function. (Empty comparator classes like `std::less` are not a + * problem.) + * + * To avoid run-time surprises, the legacy `reducer_{min|max}[_index]` classes + * have been coded in the 1.0 library so that they will not even compile when + * instantiated with a non-empty comparator class. + * + * @subsection redminmax_compatibility_optimized Numeric Optimization + * + * Min/max reducers with a numeric value type and the default comparator can + * be implemented slightly more efficiently than other min/max reducers. + * However, the optimization is incompatible with the 0.9 library + * implementation of min/max reducers. + * + * The default min/max reducers implementation in the 1.0 library uses this + * numeric optimization. Code using legacy reducers compiled with the 1.0 + * library can be safely used in the same program as code compiled with the + * 0.9 library, but classes compiled with the different Cilk libraries will be + * defined in different namespaces. + * + * The simplest solution is just to recompile the code that was compiled with + * the older version of Cilk. However, if this is impossible, you can define + * the `CILK_LIBRARY_0_9_REDUCER_MINMAX` macro (on the compiler command line, + * or in your source code before including `reducer_min_max.h`) when compiling + * with the new library. This will cause it to generate numeric reducers that + * will be less efficient, but will be fully compatible with previously + * compiled code. (Note that this macro has no effect on [the non-empty + * comparator incompatibility] (redminmax_compatibility_stateful).) + * + * @section redminmax_types Type Requirements + * + * `Type` and `Index` must be `Copy Constructible`, `Default Constructible`, + * and `Assignable`. + * + * `Compare` must be `Copy Constructible` if the reducer is constructed with a + * `compare` argument, and `Default Constructible` otherwise. + * + * The `Compare` function must induce a strict weak ordering on the elements + * of `Type`. + * + * @section redminmax_in_c Minimum and Maximum Reducers in C + * + * These macros can be used to do minimum and maximum reductions in C: + * + * Declaration | Type | Operation + * -----------------------------|-----------------------------------|---------- + * @ref CILK_C_REDUCER_MIN |@ref CILK_C_REDUCER_MIN_TYPE |@ref CILK_C_REDUCER_MIN_CALC + * @ref CILK_C_REDUCER_MAX |@ref CILK_C_REDUCER_MAX_TYPE |@ref CILK_C_REDUCER_MAX_CALC + * @ref CILK_C_REDUCER_MIN_INDEX |@ref CILK_C_REDUCER_MIN_INDEX_TYPE |@ref CILK_C_REDUCER_MIN_INDEX_CALC + * @ref CILK_C_REDUCER_MAX_INDEX |@ref CILK_C_REDUCER_MAX_INDEX_TYPE |@ref CILK_C_REDUCER_MAX_INDEX_CALC + * + * For example: + * + * CILK_C_REDUCER_MIN(r, int, INT_MAX); + * CILK_C_REGISTER_REDUCER(r); + * cilk_for(int i = 0; i != n; ++i) { + * CILK_C_REDUCER_MIN_CALC(r, a[i]); + * } + * CILK_C_UNREGISTER_REDUCER(r); + * printf("The smallest value in a is %d\n", REDUCER_VIEW(r)); + * + * + * CILK_C_REDUCER_MAX_INDEX(r, uint, 0); + * CILK_C_REGISTER_REDUCER(r); + * cilk_for(int i = 0; i != n; ++i) { + * CILK_C_REDUCER_MAX_INDEX_CALC(r, i, a[i]); + * } + * CILK_C_UNREGISTER_REDUCER(r); + * printf("The largest value in a is %u at %d\n", + * REDUCER_VIEW (r).value, REDUCER_VIEW(r).index); + * + * See @ref reducers_c_predefined. + */ + +namespace cilk { + +/** @defgroup ReducersMinMaxBinComp Binary compatibility + * + * If the macro CILK_LIBRARY_0_9_REDUCER_MINMAX is defined, then we generate + * reducer code and data structures which are binary-compatible with code that + * was compiled with the old min/max wrapper definitions, so we want the + * mangled names of the legacy min/max reducer wrapper classes to be the + * same as the names produced by the old definitions. + * + * Conversely, if the macro is not defined, then we generate binary- + * incompatible code, so we want different mangled names, to make sure that + * the linker does not allow new and old compiled legacy wrappers to be passed + * to one another. (Global variables are a different, and probably insoluble, + * problem.) + * + * Similarly, min/max classes compiled with and without + * CILK_LIBRARY_0_9_REDUCER_MINMAX are binary-incompatible, and must get + * different mangled names. + * + * The trick is, when compiling in normal (non-compatibility) mode, wrap + * everything in an extra namespace, and then `use` it into the top-level cilk + * namespace. Then + * + * * Classes and functions compiled in normal mode will be in + * different namespaces from the same classes and functions compiled in + * compatibility mode. + * * The legacy wrapper classes and functions will be in the same namespace + * as the same classes and functions compiled with the0.9 library if and + * only if the are compiled in compatibility mode. + * + * @ingroup ReducersMinMax + */ + +#ifndef CILK_LIBRARY_0_9_REDUCER_MINMAX +/** Namespace to wrap min/max reducer definitions when not compiling in “binary + * compatibility” mode. + * + * By default, all of the min/max reducer definitions are defined in this + * namespace and then imported into namespace ::cilk, so that they do not + * clash with the legacy definitions with the same names. However, if the + * macro `CILK_LIBRARY_0_9_REDUCER_MINMAX` is defined, then the min/max + * definitions go directly into namespace ::cilk, so that, for example, + * cilk::reducer_max defined with the 1.0 library is equivalent (to the + * linker) to cilk::reducer_max defined with the 0.9 library. + * + * @ingroup ReducersMinMaxBinComp + * @ingroup ReducersMinMax + */ +namespace cilk_lib_1_0 { +#endif + +/** Namespace containing internal implementation classes and functions for + * min/max reducers. + * + * @ingroup ReducersMinMax + */ +namespace min_max_internal { + +using ::cilk::internal::binary_functor; +using ::cilk::internal::typed_indirect_binary_function; +using ::cilk::internal::class_is_empty; + +/** @defgroup ReducersMinMaxIsSet The “is_set optimization” + * + * The obvious definition of the identity value for a max or min reducer is as + * the smallest (or largest) value of the value type. However, for an + * arbitrary comparator and/or an arbitrary value type, the largest / smallest + * value may not be known. It may not even be defined — what is the largest + * string? + * + * Therefore, min/max reducers represent their value internally as a pair + * `(value, is_set)`. When `is_set` is true, the pair represents the known + * value `value`; when `is_set` is false, the pair represents the identity + * value. + * + * This is an effective solution, but the most common use of min/max reducers + * is probably with numeric types and the default definition of minimum or + * maximum (using `std::less`), in which case there are well-defined, knowable + * smallest and largest values. Testing `is_set` for every comparison is then + * unnecessary and wasteful. + * + * The “is_set optimization” just means generating code that doesn’t use + * `is_set` when it isn’t needed. It is implemented using two metaprogramming + * classes: + * + * - do_is_set_optimization tests whether the optimization is applicable. + * - identity_value gets the appropriate identity value for a type. + * + * The is_set optimization is the reason that min/max reducers compiled with + * Cilk library 1.0 are binary-incompatible with the same reducers compiled + * with library 0.9, and therefore the optimization is suppressed when + * compiling in + * ReducersMinMaxBinComp "binary compatibility mode". + * + * @ingroup ReducersMinMax + */ + +/** Test whether the ReducersMinMaxIsSet "is_set optimization" is + * applicable. + * + * The @ref do_is_set_optimization class is used to test whether the is_set + * optimization should be applied for a particular reducer. It is instantiated + * with a value type and a comparator, and defines a boolean constant, + * `value`. Then `%do_is_set_optimization<Type, Comp>::%value` can be used as + * a boolean template parameter to control the specialization of another + * class. + * + * In ReducersMinMaxBinComp "binary compatibility mode", when the + * `CILK_LIBRARY_0_9_REDUCER_MINMAX` macro is defined, `value` will always + * be false. + * + * @tparam Type The value type for the reducer. + * @tparam Compare The comparator type for the reducer. + * + * @result The `value` data member will be `true` if @a Type is a numeric + * type, @a Compare is `std::less<Type>`, and + * `CILK_LIBRARY_0_9_REDUCER_MINMAX` is not defined. + * + * @see ReducersMinMaxIsSet + * @see @ref view_content + * + * @ingroup ReducersMinMaxIsSet + */ +template < typename Type, + typename Compare > +struct do_is_set_optimization +{ + /// `True` if the is_set optimization should be applied to min/max reducers + /// with this value type and comparator; `false` otherwise. + static const bool value = false; +}; + +#ifndef CILK_LIBRARY_0_9_REDUCER_MINMAX +/// @cond +template <typename Type> +struct do_is_set_optimization<Type, std::less<Type> > +{ + /// True in the special case where optimization is possible. + static const bool value = std::numeric_limits<Type>::is_specialized; +}; +/// @endcond +#endif + + +/** Get the identity value when using the ReducersMinMaxIsSet + * "is_set optimization". + * + * This class defines a function which assigns the appropriate identity value + * to a variable when the is_set optimization is applicable. + * + * @tparam Type The value type for the reducer. + * @tparam Compare The comparator type for the reducer. + * @tparam ForMax `true` to get the identity value for a max reducer (i.e., + * the smallest value of @a Type), `false` to get the identity + * value for a min reducer (i.e., the largest value of + * @a Type). + * + * @result If @a Type and @a Compare qualify for the is_set optimization, the + * `set_identity()' function will set its argument variable to the + * smallest or largest value of @a Type, depending on @a ForMax. + * Otherwise, `set_identity()` will be a no-op. + * + * @see ReducersMinMaxIsSet + * + * @ingroup ReducersMinMaxIsSet + * @see @ref view_content + */ +template < typename Type, + typename Compare, + bool ForMax, + bool = std::numeric_limits<Type>::is_specialized, + bool = std::numeric_limits<Type>::has_infinity > +struct identity_value { + /// Assign the identity value to the reference parameter. + static void set_identity(Type&) {} +}; + +/// @cond +template <typename Type> +struct identity_value<Type, std::less<Type>, true, true, true> { + /// Floating max identity is negative infinity. + static void set_identity(Type& id) + { id = -std::numeric_limits<Type>::infinity(); } +}; + +template <typename Type> +struct identity_value<Type, std::less<Type>, true, true, false> { + /// Integer max identity is minimum value of type. + static void set_identity(Type& id) + { id = std::numeric_limits<Type>::min(); } +}; + +template <typename Type> +struct identity_value<Type, std::less<Type>, false, true, true> { + /// Floating min identity is positive infinity. + static void set_identity(Type& id) + { id = std::numeric_limits<Type>::infinity(); } +}; + +template <typename Type> +struct identity_value<Type, std::less<Type>, false, true, false> { + /// Integer min identity is maximum value of type. + static void set_identity(Type& id) + { id = std::numeric_limits<Type>::max(); } +}; + +/// @endcond + + +/** Adapter class to reverse the arguments of a predicate. + * + * Observe that: + * + * (x < y) == (y > x) + * max(x, y) == (x < y) ? y : x + * min(x, y) == (y < x) ? y : x == (x > y) ? y : x + * + * More generally, if `c` is a predicate defining a `Strict Weak Ordering`, + * and `c*(x, y) == c(y, x)`, then + * + * max(x, y, c) == c(x, y) ? y : x + * min(x, y, c) == c(y, x) ? y : x == c*(x, y) ? y : x == max(x, y, c*) + * + * For any predicate `C` with argument type `T`, the template class + * `%reverse_predicate<C, T>` defines a predicate which is identical to `C`, + * except that its arguments are reversed. Thus, for example, we could + * implement `%op_min_view<Type, Compare>` as + * `%op_max_view<Type, %reverse_predicate<Compare, Type> >`. + * (Actually, op_min_view and op_max_view are both implemented as subclasses + * of a common base class, view_base.) + * + * @note If `C` is an empty functor class, then `reverse_predicate(C)` will + * also be an empty functor class. + * + * @tparam Predicate The predicate whose arguments are to be reversed. + * @tparam Argument @a Predicate’s argument type. + * + * @ingroup ReducersMinMax + */ +template <typename Predicate, + typename Argument = typename Predicate::first_argument_type> +class reverse_predicate : private binary_functor<Predicate>::type { + typedef typename binary_functor<Predicate>::type base; +public: + /// Default constructor + reverse_predicate() : base() {} + /// Constructor with predicate object + reverse_predicate(const Predicate& p) : base(p) {} + /// The reversed predicate operation + bool operator()(const Argument& x, const Argument& y) const + { return base::operator()(y, x); } +}; + + +/** Class to represent the comparator for a min/max view class. + * + * This class is intended to accomplish two objectives in the implementation + * of min/max views. + * + * 1. To minimize data bloat, when we have a reducer with a non-stateless + * comparator, we want to keep a single instance of the comparator object + * in the monoid, and just call it from the views. + * 2. In ReducersMinMaxBinComp "binary compatibility mode", views for + * reducers with a stateless comparator must have the same content as in + * Cilk library 0.9 — that is, they must contain only `value` and + * `is_set` data members. + * + * To achieve the first objective, we use the + * @ref internal::typed_indirect_binary_function class defined in + * metaprogramming.h to wrap a pointer to the actual comparator. If no + * pointer is needed because the actual comparator is stateless, the + * `typed_indirect_binary_function` class will be empty, too. + * + * To achieve the second objective, we make the + * `typed_indirect_binary_function` class a base class of the view rather than + * a data member, so the “empty base class” rule will ensure no that no + * additional space is allocated in the view unless it is needed. + * + * We could simply use typed_indirect_binary_function as the base class of the + * view, but this would mean writing comparisons as `(*this)(x, y)`, which is + * just weird. So, instead, we comparator_base as a subclass of + * typed_indirect_binary_function which provides function `compare()` + * as a synonym for `operator()`. + * + * @tparam Type The value type of the comparator class. + * @tparam Compare A predicate class. + * + * @see internal::typed_indirect_binary_function + * + * @ingroup ReducersMinMax + */ +template <typename Type, typename Compare> +class comparator_base : private typed_indirect_binary_function<Compare, Type, Type, bool> +{ + typedef typed_indirect_binary_function<Compare, Type, Type, bool> base; +protected: + comparator_base(const Compare* f) : base(f) {} ///< Constructor. + + /// Comparison function. + bool compare(const Type& a, const Type& b) const + { + return base::operator()(a, b); + } + + /// Get the comparator pointer. + const Compare* compare_pointer() const { return base::pointer(); } +}; + + +/** @defgroup ReducersMinMaxViewContent Content classes for min/max views + * + * @ingroup ReducersMinMax + * + * Minimum and maximum reducer view classes inherit from a “view content” + * class. The content class defines the actual data members for the view, + * and provides typedefs and member functions for accessing the data members + * as needed to support the view functionality. + * + * There are two content classes, which encapsulate the differences between + * simple min/max reducers and min/max with index reducers: + * + * - view_content + * - index_view_content + * + * @note An obvious, and arguably simpler, encapsulation strategy would be + * to just let the `Type` of a min/max view be an (index, value) pair + * structure for min_index and max_index reducers. Then all views + * would just have a `Type` data member and an `is_set` data member, + * and the comparator for min_index and max_index views could be + * customized to consider only the value component of the (index, + * value) `Type` pair. Unfortunately, this would break binary + * compatibility with reducer_max_index and reducer_min_index in + * Cilk library 0.9, because the memory layout of an (index, value) + * pair followed by a `bool` is different from the memory layout of an + * index data member followed by a value data member followed by a + * `bool` data member. The content class is designed to exactly + * replicate the layout of the views in library 0.9 reducers. + * + * A content class `C`, and its objects `c`, must define the following: + * + * Definition | Meaning + * ------------------------------------|-------- + * `C::value_type` | A typedef for `Type` of the view. (A `std::pair<Index, Type>` for min_index and max_index views). + * `C::comp_value_type` | A typedef for the type of value compared by the view’s `compare()` function. + * `C()` | Constructs the content with the identity value. + * `C(const value_type&)` | Constructs the content with a specified value. + * `c.is_set()` | Returns true if the content has a known value. + * `c.value()` | Returns the content’s value. + * `c.set_value(const value_type&)` | Sets the content’s value. (The value becomes known.) + * `c.comp_value()` | Returns a const reference to the value or component of the value that is to be compared by the view’s comparator. + * `C::comp_value(const value_type&)` | Returns a const reference to a value or component of a value that is to be compared by the view’s comparator. + * + * @see view_base + */ + +/** Content class for op_min_view and op_max_view. + * + * @tparam Type The value type of the op_min_view or op_max_view. + * @tparam Compare The comparator class specified for the op_min_view or + * op_max_view. (_Not_ the derived comparator class actually + * used by the view_base. For example, the view_content of an + * `op_min_view<int>` will have `Compare = std::less<int>`, + * but its comparator_base will have + * `Compare = reverse_predicate< std::less<int> >`.) + * @tparam ForMax `true` if this is the content class for an op_max_view, + * `false` if it is for an op_min_view. + * + * @note The general implementation of view_content uses an `is_set` data + * member. There is also a specialization which implements the + * ReducersMinMaxIsSet "is_set optimization". View classes that + * inherit from view_content do not need to know anything about the + * difference, though; the details are abstracted away in the + * view_content interface. + * + * @see ReducersMinMaxViewContent + * + * @ingroup ReducersMinMaxViewContent + * @ingroup ReducersMinMax + */ +template < typename Type + , typename Compare + , bool ForMax + , bool = do_is_set_optimization<Type, Compare>::value + > +class view_content { + Type m_value; + bool m_is_set; +public: + /// The value type of the view. + typedef Type value_type; + + /// The type compared by the view’s `compare()` function (which is the same + /// as the value type for view_content). + typedef Type comp_value_type; + + /// Construct with the identity value. + view_content() : m_value(), m_is_set(false) {} + + /// Construct with a defined value. + view_content(const value_type& value) : m_value(value), m_is_set(true) {} + + /// Get the value. + value_type value() const { return m_value; } + + /// Set the value. + void set_value(const value_type& value) + { + m_value = value; + m_is_set = true; + } + + /// Get the comparison value (which is the same as the value for + /// view_content). + const comp_value_type& comp_value() const { return m_value; } + + /// Given an arbitrary value, get the corresponding comparison value (which + /// is the same as the value for view_content). + static const comp_value_type& comp_value(const value_type& value) + { + return value; + } + + /// Get a const reference to value part of the value (which is the same as + /// the value for view_content). + const Type& get_reference() const { return m_value; } + + /// Get a const reference to the index part of the value (which is + /// meaningless for non-index reducers, but required for view_base. + const Type& get_index_reference() const { return m_value; } + + /// Test if the value is defined. + bool is_set() const { return m_is_set; } +}; + +/// @cond + +/* This is the specialization of the view_content class for cases where + * `AssumeIsSet` is true (i.e., where the is_set optimization is applicable). + */ +template < typename Type + , typename Compare + , bool ForMax + > +class view_content<Type, Compare, ForMax, true> { + typedef identity_value<Type, Compare, ForMax> Identity; + Type m_value; +public: + typedef Type value_type; + typedef Type comp_value_type; + + /// Construct with identity value. + view_content() { Identity::set_identity(m_value); } + + view_content(const value_type& value) : m_value(value) {} + + value_type value() const { return m_value; } + + void set_value(const value_type& value) + { + m_value = value; + } + + const comp_value_type& comp_value() const { return m_value; } + + static const comp_value_type& comp_value(const value_type& value) + { + return value; + } + + const Type& get_reference() const { return m_value; } + + const Type& get_index_reference() const { return m_value; } + + /// Test if the value is defined. + bool is_set() const { return true; } +}; + +/// @endcond + + +/** Content class for op_min_index_view and op_max_index_view. + * + * @tparam Index The index type of the op_min_index_view or + op_max_index_view. + * @tparam Type The value type of the op_min_view or op_max_view. (_Not_ + * the value type of the view, which will be + * `std::pair<Index, Type>`.) + * @tparam Compare The comparator class specified for the op_min_index_view or + * op_max_index_view. (_Not_ the derived comparator class + * actually used by the view_base. For example, the + * index_view_content of an `op_min_index_view<int>` will have + * `Compare = std::less<int>`, but its comparator_base will + * have `Compare = reverse_predicate< std::less<int> >`.) + * @tparam ForMax `true` if this is the content class for an + * op_max_index_view, `false` if it is for an + * op_min_index_view. + * + * @see ReducersMinMaxViewContent + * + * @ingroup ReducersMinMaxViewContent + * @ingroup ReducersMinMax + */ +template < typename Index + , typename Type + , typename Compare + , bool ForMax + > +class index_view_content { + typedef identity_value<Type, Compare, ForMax> Identity; + + Index m_index; + Type m_value; + bool m_is_set; +public: + /// The value type of the view (which is an <index, value> pair for + /// index_view_content). + typedef std::pair<Index, Type> value_type; + + /// The type compared by the view’s `compare()` function (which is the data + /// value type for index_view_content). + typedef Type comp_value_type; + + /// Construct with the identity value. + index_view_content() : m_index(), m_value(), m_is_set(false) {} + + /// Construct with an index/value pair. + index_view_content(const value_type& value) : + m_index(value.first), m_value(value.second), m_is_set(true) {} + + /// Construct with an index and a value. + index_view_content(const Index& index, const Type& value) : + m_index(index), m_value(value), m_is_set(true) {} + + /// Construct with just an index. + index_view_content(const Index& index) : + m_index(index), m_value(), m_is_set(false) {} + + /// Get the value. + value_type value() const { return value_type(m_index, m_value); } + + /// Set value. + void set_value(const value_type& value) + { + m_index = value.first; + m_value = value.second; + m_is_set = true; + } + + /// Get the comparison value (which is the value component of the + /// index/value pair for index_view_content). + const comp_value_type& comp_value() const { return m_value; } + + /// Given an arbitrary value (i.e., index/value pair), get the + /// corresponding comparison value (which is the value component of the + /// index/value pair for index_view_content). + static const comp_value_type& comp_value(const value_type& value) + { return value.second; } + + /// Get a const reference to value part of the value. + const Type& get_reference() const { return m_value; } + + /// Get a const reference to the index part of the value. + const Index& get_index_reference() const { return m_index; } + + /// Test if the value is defined. + bool is_set() const { return m_is_set; } +}; + + +template <typename View> class rhs_proxy; + +/** Create an rhs_proxy. + */ +template <typename View> +inline rhs_proxy<View> +make_proxy(const typename View::value_type& value, const View& view); + +template <typename Content, typename Less, typename Compare> class view_base; + + +/** Class to represent the right-hand side of + * `*reducer = {min|max}_of(*reducer, value)`. + * + * The only assignment operator for a min/max view class takes a rhs_proxy as + * its operand. This results in the syntactic restriction that the only + * expressions that can be assigned to a min/max view are ones which generate + * an rhs_proxy — that is, expressions of the form `max_of(view, value)` and + * `min_of(view, value)`. + * + * @warning + * The lhs and rhs views in such an assignment must be the same; otherwise, + * the behavior will be undefined. (I.e., `*r1 = min_of(*r1, x)` is legal; + * `*r1 = min_of(*r2, x)` is illegal.) This condition will be checked with a + * runtime assertion when compiled in debug mode. + * + * @tparam View The view class (op_{min|max}[_index]_view) that this proxy + * was created from. + * + * @see view_base + * + * @ingroup ReducersMinMax + */ +template <typename View> +class rhs_proxy { + typedef typename View::less_type less_type; + typedef typename View::compare_type compare_type; + typedef typename View::value_type value_type; + typedef typename View::content_type content_type; + typedef typename content_type::comp_value_type comp_value_type; + + friend class view_base<content_type, less_type, compare_type>; + friend rhs_proxy make_proxy<View>( + const typename View::value_type& value, + const View& view); + + typed_indirect_binary_function< + compare_type, comp_value_type, comp_value_type, bool> + m_comp; + const View* m_view; + value_type m_value; + + rhs_proxy& operator=(const rhs_proxy&); // Disable assignment operator + rhs_proxy(); // Disable default constructor + + // Constructor (called from view_base::make_proxy). + rhs_proxy(const View* view, + const value_type& value, + const compare_type* compare) : + m_view(view), m_value(value), m_comp(compare) {} + + // Check matching view, then return value (called from view_base::assign). + value_type value(const typename View::base* view) const + { + __CILKRTS_ASSERT(view == m_view); + return m_value; + } + +public: + + /** Support max_of(max_of(view, value), value) and the like. + */ + rhs_proxy calc(const value_type& x) const + { + return rhs_proxy( + m_view, + m_comp( content_type::comp_value(m_value), + content_type::comp_value(x) + ) ? x : m_value, + m_comp.pointer()); + } +}; + + +template <typename View> +inline rhs_proxy<View> +make_proxy(const typename View::value_type& value, const View& view) +{ + return rhs_proxy<View>(&view, value, view.compare_pointer()); +} + +//@} + +/** Base class for min and max view classes. + * + * This class accumulates the minimum or maximum of a set of values which have + * occurred as arguments to the `calc()` function, as determined by a + * comparator. The accumulated value will be the first `calc()` argument value + * `x` such that `compare(x, y)` is false for every `calc()` argument value + * `y`. + * + * If the comparator is `std::less`, then the accumulated value is the first + * argument value which is not less than any other argument value, i.e., the + * maximum. Similarly, if the comparator is `reverse_predicate<std::less>`, + * which is equivalent to `std::greater`, then the accumulated value is the + * first argument value which is not greater than any other argument value, + * i.e., the minimum. + * + * @note This class provides the definitions that are required for a class + * that will be used as the parameter of a + * min_max_internal::monoid_base specialization. + * + * @tparam Content A content class that provides the value types and data + * members for the view. + * @tparam Less A “less than” binary predicate that defines the min or + * max function. + * @tparam Compare A binary predicate to be used to compare the values. + * (The same as @a Less for max reducers; its reversal for + * min reducers.) + * + * @see ReducersMinMaxViewContent + * @see op_max_view + * @see op_min_view + * @see op_max_index_view + * @see op_min_index_view + * @see monoid_base + * + * @ingroup ReducersMinMax + */ +template <typename Content, typename Less, typename Compare> +class view_base : + // comparator_base comes first to ensure that it will get empty base class + // treatment + private comparator_base<typename Content::comp_value_type, Compare>, + private Content +{ + typedef comparator_base<typename Content::comp_value_type, Compare> base; + using base::compare; + using Content::value; + using Content::set_value; + using Content::comp_value; + typedef Content content_type; + + template <typename View> friend class rhs_proxy; + template <typename View> + friend rhs_proxy<View> make_proxy(const typename View::value_type& value, const View& view); + +public: + + /** @name Monoid support. + */ + //@{ + + /** Value type. Required by @ref monoid_with_view. + */ + typedef typename Content::value_type value_type; + + /** The type of the comparator specified by the user, that defines the + * ordering on @a Type. Required by min_max::monoid_base. + */ + typedef Less less_type; + + /** The type of the comparator actually used by the view. Required by + * min_max::monoid_base. (This is the same as the @ref less_type for a + * max reducer, or `reverse_predicate<less_type>` for a min reducer.) + */ + typedef Compare compare_type; + + /** Reduce operation. Required by @ref monoid_with_view. + */ + void reduce(view_base* other) + { + if ( other->is_set() && + ( !this->is_set() || + compare(this->comp_value(), other->comp_value()) ) ) + { + this->set_value(other->value()); + } + } + + //@} + + /** Default constructor. Initializes to identity value. + */ + explicit view_base(const compare_type* compare) : + base(compare), Content() {} + + /** Value constructor. + */ + template <typename T1> + view_base(const T1& x1, const compare_type* compare) : + base(compare), Content(x1) {} + + /** Value constructor. + */ + template <typename T1, typename T2> + view_base(const T1& x1, const T2& x2, const compare_type* compare) : + base(compare), Content(x1, x2) {} + + + /** Move-in constructor. + */ + explicit view_base(move_in_wrapper<value_type> w, const compare_type* compare) : + base(compare), Content(w.value()) {} + + /** @name Reducer support. + */ + //@{ + + void view_move_in(value_type& v) { set_value(v); } + void view_move_out(value_type& v) { v = value(); } + void view_set_value(const value_type& v) { set_value(v); } + value_type view_get_value() const { return value(); } + // view_get_reference() NOT SUPPORTED + + //@} + + /** Is the value defined? + */ + using Content::is_set; + + /** Reference to contained value data member. + * @deprecated For legacy reducers only. + */ + using Content::get_reference; + + /** Reference to contained index data member. + * (Meaningless for non-index reducers.) + * @deprecated For legacy reducers only. + */ + using Content::get_index_reference; + +protected: + + /** Update the min/max value. + */ + void calc(const value_type& x) + { + if (!is_set() || compare(comp_value(), comp_value(x))) set_value(x); + } + + /** Assign the result of a `{min|max}_of(view, value)` expression to the + * view. + * + * @see rhs_proxy + */ + template <typename View> + void assign(const rhs_proxy<View>& rhs) + { + calc(rhs.value(this)); + } + +}; + + +/** Base class for min and max monoid classes. + * + * The unique characteristic of minimum and maximum reducers is that they + * incorporate a comparator functor that defines what “minimum” or “maximum” + * means. The monoid for a reducer contains the comparator that will be used + * for the reduction. If the comparator is a function or a class with state, + * then each view will have a pointer to the comparator. + * + * This means that the `construct()` functions first construct the monoid + * (possibly with an explicit comparator argument), and then construct the + * view with a pointer to the monoid’s comparator. + * + * @tparam View The view class. + * @tparam Align If true, reducers instantiated on this monoid will be + * aligned. By default, library reducers (unlike legacy + * library reducer _wrappers_) are unaligned. + * + * @see view_base + * + * @ingroup ReducersMinMax + */ +template <typename View, bool Align = false> +class monoid_base : public monoid_with_view<View, Align> +{ + typedef typename View::compare_type compare_type; + typedef typename View::less_type less_type; + const compare_type m_compare; + + const compare_type* compare_pointer() const { return &m_compare; } + + using cilk::monoid_base<typename View::value_type, View>::provisional; + +public: + + /** Default constructor uses default comparator. + */ + monoid_base() : m_compare() {} + + /** Constructor. + * + * @param compare The comparator to use. + */ + monoid_base(const compare_type& compare) : m_compare(compare) {} + + /** Create an identity view. + * + * List view identity constructors take the list allocator as an argument. + * + * @param v The address of the uninitialized memory in which the view + * will be constructed. + */ + void identity(View *v) const { ::new((void*) v) View(compare_pointer()); } + + /** @name construct functions + * + * Min/max monoid `construct()` functions optionally take one or two value + * arguments, a @ref move_in argument, and/or a comparator argument. + */ + //@{ + + template <typename Monoid> + static void construct(Monoid* monoid, View* view) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(monoid->compare_pointer()) ); } + + template <typename Monoid, typename T1> + static void construct(Monoid* monoid, View* view, const T1& x1) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(x1, monoid->compare_pointer()) ); } + + template <typename Monoid, typename T1, typename T2> + static void construct(Monoid* monoid, View* view, const T1& x1, const T2& x2) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(x1, x2, monoid->compare_pointer()) ); } + + template <typename Monoid> + static void construct(Monoid* monoid, View* view, const less_type& compare) + { provisional( new ((void*)monoid) Monoid(compare) ).confirm_if( + new ((void*)view) View(monoid->compare_pointer()) ); } + + template <typename Monoid, typename T1> + static void construct(Monoid* monoid, View* view, const T1& x1, const less_type& compare) + { provisional( new ((void*)monoid) Monoid(compare) ).confirm_if( + new ((void*)view) View(x1, monoid->compare_pointer()) ); } + + template <typename Monoid, typename T1, typename T2> + static void construct(Monoid* monoid, View* view, const T1& x1, const T2& x2, const less_type& compare) + { provisional( new ((void*)monoid) Monoid(compare) ).confirm_if( + new ((void*)view) View(x1, x2, monoid->compare_pointer()) ); } + + //@} +}; + +} //namespace min_max_internal + + +/** @defgroup ReducersMinMaxMaxValue Maximum reducers (value only) + * + * These reducers will find the largest value from a set of values. + * + * @ingroup ReducersMinMax + */ +//@{ + +/** The maximum reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_max<Type, Compare> >`. It accumulates the maximum, + * as determined by a comparator, of a set of values which have occurred as + * arguments to the `calc_max()` function. The accumulated value will be the + * first argument `x` such that `compare(x, y)` is false for every argument + * `y`. + * + * If the comparator is `std::less`, then the accumulated value is the first + * argument value which is not less than any other argument value, i.e., the + * maximum. + * + * @note The reducer “dereference” operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `calc_max()` function would be used in an expression like + * `r->calc_max(a)` where `r` is an op_max reducer variable. + * + * @tparam Type The type of the values compared by the reducer. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * @tparam Compare A `Strict Weak Ordering` whose argument type is @a Type. It + * defines the “less than” relation used to compute the + * maximum. + * + * @see ReducersMinMax + * @see op_max + */ +template <typename Type, typename Compare> +class op_max_view : public min_max_internal::view_base< + min_max_internal::view_content<Type, Compare, true>, + Compare, + Compare> +{ + typedef min_max_internal::view_base< + min_max_internal::view_content<Type, Compare, true>, + Compare, + Compare> base; + using base::calc; + using base::assign; + friend class min_max_internal::rhs_proxy<op_max_view>; + +public: + + /** @name Constructors. + * + * All op_max_view constructors simply pass their arguments on to the + * @ref view_base base class. + */ + //@{ + + op_max_view() : base() {} + + template <typename T1> + op_max_view(const T1& x1) : base(x1) {} + + template <typename T1, typename T2> + op_max_view(const T1& x1, const T2& x2) : base(x1, x2) {} + + //@} + + /** @name View modifier operations. + */ + //@{ + + /** Maximize with a value. + * + * If @a x is greater than the current value of the view (as defined by + * the reducer’s comparator), or if the view was created without an + * initial value and its value has never been updated (with `calc_max()` + * or `= max_of()`), then the value of the view is set to @a x. + * + * @param x The value to maximize the view’s value with. + * + * @return A reference to the view. (Allows chaining + * `view.comp_max(a).comp_max(b)…`.) + */ + op_max_view& calc_max(const Type& x) { calc(x); return *this; } + + /** Assign the result of a `max_of(view, value)` expression to the view. + * + * @param rhs An rhs_proxy value created by a `max_of(view, value)` + * expression. + * + * @return A reference to the view. + * + * @see min_max_internal::view_base::rhs_proxy + */ + op_max_view& operator=(const min_max_internal::rhs_proxy<op_max_view>& rhs) + { assign(rhs); return *this; } + + //@} +}; + + +/** Compute the maximum of the value in an op_max_view and another value. + * + * The result of this computation can only be assigned back to the original + * view or used in another max_of() call. For example, + * + * *reducer = max_of(*reducer, x); + * *reducer = max_of(x, *reducer); + * + * @see min_max_internal::rhs_proxy + */ +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_view<Type, Compare> > +max_of(const op_max_view<Type, Compare>& view, const Type& value) +{ + return min_max_internal::make_proxy(value, view); +} + +/// @copydoc max_of(const op_max_view<Type, Compare>&, const Type&) +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_view<Type, Compare> > +max_of(const Type& value, const op_max_view<Type, Compare>& view) +{ + return min_max_internal::make_proxy(value, view); +} + +/** Nested maximum computation. + * + * Compute the maximum of the result of a max_of() call and another value. + * + * The result of this computation can only be assigned back to the original + * view or wrapper, or used in another max_of() call. For example, + * + * *reducer = max_of(x, max_of(y, *reducer)); + * wrapper = max_of(max_of(wrapper, x), y); + * + * @see min_max_internal::rhs_proxy + */ +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_view<Type, Compare> > +max_of(const min_max_internal::rhs_proxy< op_max_view<Type, Compare> >& proxy, + const Type& value) +{ + return proxy.calc(value); +} + +/// @copydoc max_of(const min_max_internal::rhs_proxy< op_max_view<Type, Compare> >&, const Type&) +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_view<Type, Compare> > +max_of(const Type& value, + const min_max_internal::rhs_proxy< op_max_view<Type, Compare> >& proxy) +{ + return proxy.calc(value); +} + + +/** Monoid class for maximum reductions. Instantiate the cilk::reducer template + * class with an op_max monoid to create a maximum reducer class. For example, + * to compute the maximum of a set of `int` values: + * + * cilk::reducer< cilk::op_max<int> > r; + * + * @see ReducersMinMax + * @see op_max_view + */ +template <typename Type, typename Compare=std::less<Type>, bool Align = false> +class op_max : + public min_max_internal::monoid_base<op_max_view<Type, Compare>, Align> +{ + typedef min_max_internal::monoid_base<op_max_view<Type, Compare>, Align> + base; +public: + /// Construct with default comparator. + op_max() {} + /// Construct with specified comparator. + op_max(const Compare& compare) : base(compare) {} +}; + +//@} + + +/** @defgroup ReducersMinMaxMinValue Minimum reducers (value only) + * + * These reducers will find the smallest value from a set of values. + * + * @ingroup ReducersMinMax + */ +//@{ + +/** The minimum reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_min<Type, Compare> >`. It accumulates the minimum, + * as determined by a comparator, of a set of values which have occurred as + * arguments to the `calc_min()` function. The accumulated value will be the + * first argument `x` such that `compare(y, x)` is false for every argument + * `y`. + * + * If the comparator is `std::less`, then the accumulated value is the first + * argument value which no other argument value is less than, i.e., the + * minimum. + * + * @note The reducer “dereference” operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `calc_min()` function would be used in an expression like + * `r->calc_min(a)` where `r` is an op_min reducer variable. + * + * @tparam Type The type of the values compared by the reducer. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * @tparam Compare A `Strict Weak Ordering` whose argument type is @a Type. It + * defines the “less than” relation used to compute the + * minimum. + * + * @see ReducersMinMax + * @see op_min + */ +template <typename Type, typename Compare> +class op_min_view : public min_max_internal::view_base< + min_max_internal::view_content<Type, Compare, false>, + Compare, + min_max_internal::reverse_predicate<Compare, Type> > +{ + typedef min_max_internal::view_base< + min_max_internal::view_content<Type, Compare, false>, + Compare, + min_max_internal::reverse_predicate<Compare, Type> > base; + using base::calc; + using base::assign; + friend class min_max_internal::rhs_proxy<op_min_view>; + +public: + /** @name Constructors. + * + * All op_min_view constructors simply pass their arguments on to the + * @ref view_base base class. + */ + //@{ + + op_min_view() : base() {} + + template <typename T1> + op_min_view(const T1& x1) : base(x1) {} + + template <typename T1, typename T2> + op_min_view(const T1& x1, const T2& x2) : base(x1, x2) {} + + //@} + + /** @name View modifier operations. + */ + //@{ + + /** Minimize with a value. + * + * If @a x is less than the current value of the view (as defined by the + * reducer’s comparator), or if the view was created without an initial + * value and its value has never been updated (with `calc_min()` or + * `= min_of()`), then the value of the view is set to @a x. + * + * @param x The value to minimize the view’s value with. + * + * @return A reference to the view. (Allows chaining + * `view.comp_min(a).comp_min(b)…`.) + */ + op_min_view& calc_min(const Type& x) { calc(x); return *this; } + + /** Assign the result of a `min_of(view, value)` expression to the view. + * + * @param rhs An rhs_proxy value created by a `min_of(view, value)` + * expression. + * + * @return A reference to the view. + * + * @see min_max_internal::view_base::rhs_proxy + */ + op_min_view& operator=(const min_max_internal::rhs_proxy<op_min_view>& rhs) + { assign(rhs); return *this; } +}; + + +/** Compute the minimum of the value in a view and another value. + * + * The result of this computation can only be assigned back to the original + * view or used in another min_of() call. For example, + * + * *reducer = min_of(*reducer, x); + * *reducer = min_of(x, *reducer); + * + * @see min_max_internal::view_base::rhs_proxy + */ +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_view<Type, Compare> > +min_of(const op_min_view<Type, Compare>& view, const Type& value) +{ + return min_max_internal::make_proxy(value, view); +} + +/// @copydoc min_of(const op_min_view<Type, Compare>&, const Type&) +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_view<Type, Compare> > +min_of(const Type& value, const op_min_view<Type, Compare>& view) +{ + return min_max_internal::make_proxy(value, view); +} + +/** Nested minimum computation. + * + * Compute the minimum of the result of a min_of() call and another value. + * + * The result of this computation can only be assigned back to the original + * view or wrapper, or used in another min_of() call. For example, + * + * *reducer = min_of(x, min_of(y, *reducer)); + * wrapper = min_of(min_of(wrapper, x), y); + * + * @see min_max_internal::rhs_proxy + */ +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_view<Type, Compare> > +min_of(const min_max_internal::rhs_proxy< op_min_view<Type, Compare> >& proxy, + const Type& value) +{ + return proxy.calc(value); +} + +/// @copydoc min_of(const min_max_internal::rhs_proxy< op_min_view<Type, Compare> >&, const Type&) +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_view<Type, Compare> > +min_of(const Type& value, + const min_max_internal::rhs_proxy< op_min_view<Type, Compare> >& proxy) +{ + return proxy.calc(value); +} + + +/** Monoid class for minimum reductions. Instantiate the cilk::reducer template + * class with an op_min monoid to create a minimum reducer class. For example, + * to compute the minimum of a set of `int` values: + * + * cilk::reducer< cilk::op_min<int> > r; + * + * @see ReducersMinMax + * @see op_min_view + */ +template <typename Type, typename Compare=std::less<Type>, bool Align = false> +class op_min : public min_max_internal::monoid_base<op_min_view<Type, Compare>, Align> { + typedef min_max_internal::monoid_base<op_min_view<Type, Compare>, Align> base; +public: + /// Construct with default comparator. + op_min() {} + /// Construct with specified comparator. + op_min(const Compare& compare) : base(compare) {} +}; + +//@} + + +/** @defgroup ReducersMinMaxMaxIndex Maximum reducers (value and index) + * + * These reducers will find the largest value from a set of values, and its + * index in the set. + * + * @ingroup ReducersMinMax + */ +//@{ + +/** The maximum index reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_max_index<Index, Type, Compare> >`. It accumulates + * the maximum, as determined by a comparator, of a set of values which have + * occurred as arguments to the `calc_max()` function, and records the index + * of the maximum value. The accumulated value will be the first argument `x` + * such that `compare(x, y)` is false for every argument `y`. + * + * If the comparator is `std::less`, then the accumulated value is the first + * argument value which is not less than any other argument value, i.e., the + * maximum. + * + * @note The reducer “dereference” operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `calc_max()` function would be used in an expression like + * `r->calc_max(i, a)`where `r` is an op_max_index reducer + * variable. + * + * @note The word “index” suggests an integer index into an array, but there + * is no restriction on the index type or how it should be used. In + * general, it may be convenient to use it for any kind of key that + * can be used to locate the maximum value in the collection that it + * came from — for example: + * - An index into an array. + * - A key into an STL map. + * - An iterator into any STL container. + * + * @note A max_index reducer is essentially a max reducer whose value type + * is a `std::pair<Index, Type>`. This fact is camouflaged in the view + * `calc_max` function, the global `max_of` functions, and the reducer + * value constructor, which can all take an index argument and a value + * argument as an alternative to a single `std::pair` argument. + * However, the reducer `set_value()`, `get_value()`, `move_in()`, and + * `move_out()` functions work only with pairs, not with individual + * value and/or index arguments. + * + * @tparam Index The type of the indices associated with the values. + * @tparam Type The type of the values compared by the reducer. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * @tparam Compare Used to compare the values. It must be a binary predicate. + * If it is omitted, then the view computes the conventional + * arithmetic maximum. + * + * @see ReducersMinMax + * @see op_max_index + */ +template <typename Index, typename Type, typename Compare> +class op_max_index_view : public min_max_internal::view_base< + min_max_internal::index_view_content<Index, Type, Compare, true>, + Compare, + Compare> +{ + typedef min_max_internal::view_base< + min_max_internal::index_view_content<Index, Type, Compare, true>, + Compare, + Compare> base; + using base::calc; + using base::assign; + typedef std::pair<Index, Type> pair_type; + friend class min_max_internal::rhs_proxy<op_max_index_view>; + +public: + /** @name Constructors. + * + * All op_max_index_view constructors simply pass their arguments on to the + * @ref view_base base class, except for the `(index, value [, compare])` + * constructors, which create a `std::pair` containing the index and value. + */ + //@{ + + op_max_index_view() : base() {} + + template <typename T1> + op_max_index_view(const T1& x1) : base(x1) {} + + template <typename T1, typename T2> + op_max_index_view(const T1& x1, const T2& x2) : base(x1, x2) {} + + template <typename T1, typename T2, typename T3> + op_max_index_view(const T1& x1, const T2& x2, const T3& x3) : base(x1, x2, x3) {} + + op_max_index_view(const Index& i, const Type& v) : base(pair_type(i, v)) {} + + op_max_index_view(const Index& i, const Type& v, const typename base::compare_type* c) : + base(pair_type(i, v), c) {} + + //@} + + /** Maximize with a value and index. + * + * If @a x is greater than the current value of the view (as defined by + * the reducer’s comparator), or if the view was created without an + * initial value and its value has never been updated (with `calc_max()` + * or `= max_of()`), then the value of the view is set to @a x, and the + * index is set to @a i.. + * + * @param i The index of the value @a x. + * @param x The value to maximize the view’s value with. + * + * @return A reference to the view. (Allows + * `view.comp_max(i, a).comp_max(j, b)…`.) + */ + op_max_index_view& calc_max(const Index& i, const Type& x) + { calc(pair_type(i, x)); return *this; } + + /** Maximize with an index/value pair. + * + * If @a pair.second is greater than the current value of the view (as + * defined by the reducer’s comparator), or if the view was created + * without an initial value and its value has never been updated (with + * `calc_max()` or `= max_of()`), then the value of the view is set to + * @a pair.second, and the index is set to @a pair.first. + * + * @param pair A pair containing a value to maximize the view’s value + * with and its associated index. + * + * @return A reference to the view. (Allows + * `view.comp_max(p1).comp_max(p2)…`.) + */ + op_max_index_view& calc_max(const pair_type& pair) + { calc(pair); return *this; } + + /** Assign the result of a `max_of(view, index, value)` expression to the + * view. + * + * @param rhs An rhs_proxy value created by a `max_of(view, index, value)` + * expression. + * + * @return A reference to the view. + * + * @see min_max_internal::view_base::rhs_proxy + */ + op_max_index_view& operator=(const min_max_internal::rhs_proxy<op_max_index_view>& rhs) + { assign(rhs); return *this; } +}; + + +/** Compute the maximum of the value in a view and another value. + * + * The result of this computation can only be assigned back to the original + * view or used in another max_of() call. For example, + * + * *reducer = max_of(*reducer, i, x); + * *reducer = max_of(i, x, *reducer); + * + * @see min_max_internal::rhs_proxy + */ +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> > +max_of(const op_max_index_view<Index, Type, Compare>& view, + const Index& index, const Type& value) +{ + return min_max_internal::make_proxy(std::pair<Index, Type>(index, value), view); +} + +/// @copydoc max_of(const op_max_index_view<Index, Type, Compare>&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> > +max_of(const Index& index, const Type& value, + const op_max_index_view<Index, Type, Compare>& view) +{ + return min_max_internal::make_proxy(std::pair<Index, Type>(index, value), view); +} + +/// @copydoc max_of(const op_max_index_view<Index, Type, Compare>&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> > +max_of(const op_max_index_view<Index, Type, Compare>& view, + const std::pair<Index, Type>& pair) +{ + return min_max_internal::make_proxy(pair, view); +} + +/// @copydoc max_of(const op_max_index_view<Index, Type, Compare>&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> > +max_of(const std::pair<Index, Type>& pair, + const op_max_index_view<Index, Type, Compare>& view) +{ + return min_max_internal::make_proxy(pair, view); +} + +/** Nested computation of the maximum of the value in a view and other values. + * + * Compute the maximum of the result of a max_of() call and another value. + * + * The result of this computation can only be assigned back to the original + * view or used in another max_of() call. For example, + * + * *reducer = max_of(x, max_of(y, *reducer)); + * *reducer = max_of(max_of(*reducer, x), y); + * + * @see min_max_internal::rhs_proxy + */ +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> > +max_of(const min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> >& proxy, + const Index& index, const Type& value) +{ + return proxy.calc(std::pair<Index, Type>(index, value)); +} + +/// @copydoc max_of(const min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> >&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> > +max_of(const Index& index, const Type& value, + const min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> >& proxy) +{ + return proxy.calc(std::pair<Index, Type>(index, value)); +} + +/// @copydoc max_of(const min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> >&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> > +max_of(const min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> >& proxy, + const std::pair<Index, Type>& pair) +{ + return proxy.calc(pair); +} + +/// @copydoc max_of(const min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> >&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> > +max_of(const std::pair<Index, Type>& pair, + const min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> >& proxy) +{ + return proxy.calc(pair); +} + + +/** Monoid class for maximum reductions with index. Instantiate the + * cilk::reducer template class with an op_max_index monoid to create a + * max_index reducer class. For example, to compute the maximum of an array of + * `double` values and the array index of the max value: + * + * cilk::reducer< cilk::op_max_index<unsigned, double> > r; + * + * @see ReducersMinMax + * @see op_max_index_view + */ +template < typename Index + , typename Type + , typename Compare=std::less<Type> + , bool Align = false + > +class op_max_index : public min_max_internal::monoid_base<op_max_index_view<Index, Type, Compare>, Align> +{ + typedef min_max_internal::monoid_base< + op_max_index_view<Index, Type, Compare>, Align> base; +public: + /// Construct with default comparator. + op_max_index() {} + /// Construct with specified comparator. + op_max_index(const Compare& compare) : base(compare) {} +}; + +//@} + + + +/** @defgroup ReducersMinMaxMinIndex Minimum reducers (value and index) + * + * These reducers will find the smallest value from a set of values, and its + * index in the set. + * + * @ingroup ReducersMinMax + */ +//@{ + +/** The minimum index reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer<cilk::op_min_index<Index, Type, Compare> >`. It accumulates + * the minimum, as determined by a comparator, of a set of values which have + * occurred as arguments to the `calc_min()` function, and records the index + * of the minimum value. The accumulated value will be the first argument `x` + * such that `compare(y, x)` is false for every argument `y`. + * + * If the comparator is `std::less`, then the accumulated value is the first + * argument value which no other argument value is less than, i.e., the + * minimum. + * + * @note The reducer “dereference” operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `calc_min()` function would be + * used in an expression like `r->calc_min(i, a)`where `r` is an + * op_min_index reducer variable. + * + * @note The word “index” suggests an integer index into an array, but there + * is no restriction on the index type or how it should be used. In + * general, it may be convenient to use it for any kind of key that + * can be used to locate the minimum value in the collection that it + * came from — for example: + * - An index into an array. + * - A key into an STL map. + * - An iterator into any STL container. + * + * @note A min_index reducer is essentially a min reducer whose value type + * is a `std::pair<Index, Type>`. This fact is camouflaged in the view + * `calc_min` function, the global `min_of` functions, and the reducer + * value constructor, which can all take an index argument and a value + * argument as an alternative to a single `std::pair` argument. + * However, the reducer `set_value()`, `get_value()`, `move_in()`, and + * `move_out()` functions work only with pairs, not with individual + * value and/or index arguments. + * + * @tparam Index The type of the indices associated with the values. + * @tparam Type The type of the values compared by the reducer. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * @tparam Compare Used to compare the values. It must be a binary predicate. + * If it is omitted, then the view computes the conventional + * arithmetic minimum. + * + * @see ReducersMinMax + * @see op_min_index + */ +template <typename Index, typename Type, typename Compare> +class op_min_index_view : public min_max_internal::view_base< + min_max_internal::index_view_content<Index, Type, Compare, false>, + Compare, + min_max_internal::reverse_predicate<Compare, Type> > +{ + typedef min_max_internal::view_base< + min_max_internal::index_view_content<Index, Type, Compare, false>, + Compare, + min_max_internal::reverse_predicate<Compare, Type> > base; + using base::calc; + using base::assign; + typedef std::pair<Index, Type> pair_type; + friend class min_max_internal::rhs_proxy<op_min_index_view>; + +public: + /** @name Constructors. + * + * All op_min_index_view constructors simply pass their arguments on to the + * @ref view_base base class, except for the `(index, value [, compare])` + * constructors, which create a `std::pair` containing the index and value. + */ + //@{ + + op_min_index_view() : base() {} + + template <typename T1> + op_min_index_view(const T1& x1) : base(x1) {} + + template <typename T1, typename T2> + op_min_index_view(const T1& x1, const T2& x2) : base(x1, x2) {} + + template <typename T1, typename T2, typename T3> + op_min_index_view(const T1& x1, const T2& x2, const T3& x3) : base(x1, x2, x3) {} + + op_min_index_view(const Index& i, const Type& v) : base(pair_type(i, v)) {} + + op_min_index_view(const Index& i, const Type& v, const typename base::compare_type* c) : + base(pair_type(i, v), c) {} + + //@} + + /** Minimize with a value and index. + * + * If @a x is greater than the current value of the view (as defined by + * the reducer’s comparator), or if the view was created without an + * initial value and its value has never been updated (with `calc_min()` + * or `= min_of()`), then the value of the view is set to @a x, and the + * index is set to @a i.. + * + * @param i The index of the value @a x. + * @param x The value to minimize the view’s value with. + * + * @return A reference to the view. (Allows + * `view.comp_min(i, a).comp_min(j, b)…`.) + */ + op_min_index_view& calc_min(const Index& i, const Type& x) + { calc(pair_type(i, x)); return *this; } + + /** Maximize with an index/value pair. + * + * If @a pair.second is less than the current value of the view (as + * defined by the reducer’s comparator), or if the view was created + * without an initial value and its value has never been updated (with + * `calc_min()` or `= min_of()`), then the value of the view is set to + * @a pair.second, and the index is set to @a pair.first. + * + * @param pair A pair containing a value to minimize the view’s value + * with and its associated index. + * + * @return A reference to the view. (Allows + * `view.comp_min(p1).comp_min(p2)…`.) + */ + op_min_index_view& calc_min(const pair_type& pair) + { calc(pair); return *this; } + + /** Assign the result of a `min_of(view, index, value)` expression to the + * view. + * + * @param rhs An rhs_proxy value created by a `min_of(view, index, value)` + * expression. + * + * @return A reference to the view. + * + * @see min_max_internal::view_base::rhs_proxy + */ + op_min_index_view& operator=(const min_max_internal::rhs_proxy<op_min_index_view>& rhs) + { assign(rhs); return *this; } +}; + + +/** Compute the minimum of the value in a view and another value. + * + * The result of this computation can only be assigned back to the original + * view or used in another min_of() call. For example, + * + * *reducer = min_of(*reducer, i, x); + * *reducer = min_of(i, x, *reducer); + * + * @see min_max_internal::min_min_view_base::rhs_proxy + */ +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> > +min_of(const op_min_index_view<Index, Type, Compare>& view, + const Index& index, const Type& value) +{ + return min_max_internal::make_proxy(std::pair<Index, Type>(index, value), view); +} + +/// @copydoc min_of(const op_min_index_view<Index, Type, Compare>&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> > +min_of(const Index& index, const Type& value, + const op_min_index_view<Index, Type, Compare>& view) +{ + return min_max_internal::make_proxy(std::pair<Index, Type>(index, value), view); +} + +/// @copydoc min_of(const op_min_index_view<Index, Type, Compare>&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> > +min_of(const op_min_index_view<Index, Type, Compare>& view, + const std::pair<Index, Type>& pair) +{ + return min_max_internal::make_proxy(pair, view); +} + +/// @copydoc min_of(const op_min_index_view<Index, Type, Compare>&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> > +min_of(const std::pair<Index, Type>& pair, + const op_min_index_view<Index, Type, Compare>& view) +{ + return min_max_internal::make_proxy(pair, view); +} + +/** Nested computation of the minimum of the value in a view and other values. + * + * Compute the minimum of the result of a min_of() call and another value. + * + * The result of this computation can only be assigned back to the original + * view or used in another min_of() call. For example, + * + * *reducer = min_of(x, min_of(y, *reducer)); + * *reducer = min_of(min_of(*reducer, x), y); + * + * @see min_max_internal::min_min_view_base::rhs_proxy + */ +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> > +min_of(const min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> >& proxy, + const Index& index, const Type& value) +{ + return proxy.calc(std::pair<Index, Type>(index, value)); +} + +/// @copydoc min_of(const min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> >&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> > +min_of(const Index& index, const Type& value, + const min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> >& proxy) +{ + return proxy.calc(std::pair<Index, Type>(index, value)); +} + +/// @copydoc min_of(const min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> >&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> > +min_of(const min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> >& proxy, + const std::pair<Index, Type>& pair) +{ + return proxy.calc(pair); +} + +/// @copydoc min_of(const min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> >&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> > +min_of(const std::pair<Index, Type>& pair, + const min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> >& proxy) +{ + return proxy.calc(pair); +} + + +/** Monoid class for minimum reductions with index. Instantiate the + * cilk::reducer template class with an op_min_index monoid to create a + * min_index reducer class. For example, to compute the minimum of an array of + * `double` values and the array index of the min value: + * + * cilk::reducer< cilk::op_min_index<unsigned, double> > r; + * + * @see ReducersMinMax + * @see op_min_index_view + */ +template < typename Index + , typename Type + , typename Compare=std::less<Type> + , bool Align = false + > +class op_min_index : public min_max_internal::monoid_base<op_min_index_view<Index, Type, Compare>, Align> +{ + typedef min_max_internal::monoid_base< + op_min_index_view<Index, Type, Compare>, Align> base; +public: + /// Construct with default comparator. + op_min_index() {} + /// Construct with specified comparator. + op_min_index(const Compare& compare) : base(compare) {} +}; + +//@} + + +/** Deprecated maximum reducer wrapper class. + * + * reducer_max is the same as @ref reducer<@ref op_max>, except that + * reducer_max is a proxy for the contained view, so that accumulator + * variable update operations can be applied directly to the reducer. For + * example, a value is maximized with a `reducer<%op_max>` with + * `r->calc_max(a)`, but a value can be maximized with a `%reducer_max` with + * `r.calc_max(a)`. + * + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_max. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_max` + * and `reducer<%op_max>`. This allows incremental code + * conversion: old code that used `%reducer_max` can pass a + * `%reducer_max` to a converted function that now expects a + * pointer or reference to a `reducer<%op_max>`, and vice + * versa. **But see @ref redminmax_compatibility.** + * + * @tparam Type The value type of the reducer. + * @tparam Compare The “less than” comparator type for the reducer. + * + * @see op_max + * @see op_max_view + * @see reducer + * @see ReducersMinMax + * @ingroup ReducersMinMaxMaxValue + */ +template <typename Type, typename Compare=std::less<Type> > +class reducer_max : public reducer< op_max<Type, Compare, true> > +{ + __CILKRTS_STATIC_ASSERT( + ::cilk::internal::class_is_empty< + typename ::cilk::internal::binary_functor<Compare>::type >::value, + "cilk::reducer_max<Type, Compare> only works with " + "an empty Compare class"); + typedef reducer< op_max<Type, Compare, true> > base; +public: + + /// Type of data in a reducer_max. + typedef Type basic_value_type; + + /// The view type for the reducer. + typedef typename base::view_type view_type; + + /// The view type for the reducer. + typedef typename base::view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type monoid_type; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + /// The view’s rhs proxy type. + typedef min_max_internal::rhs_proxy<View> rhs_proxy; + + using base::view; + + /** @name Constructors + */ + //@{ + + /// Construct the wrapper in its identity state (either `!is_set()`, or + /// `value() == identity value`). + reducer_max() : base() {} + + /// Construct the wrapper with a specified initial value. + explicit reducer_max(const Type& initial_value) : base(initial_value) {} + + /// Construct the wrapper in its identity state with a specified + /// comparator. + explicit reducer_max(const Compare& comp) : base(comp) {} + + /// Construct the wrapper with a specified initial value and a specified + /// comparator. + reducer_max(const Type& initial_value, const Compare& comp) + : base(initial_value, comp) {} + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_max_view. */ + //@{ + + /// @copydoc cilk_lib_1_0::min_max_internal::view_content::is_set() const + bool is_set() const { return view().is_set(); } + + /// @copydoc op_max_view::calc_max(const Type&) + reducer_max& calc_max(const Type& x) + { view().calc_max(x); return *this; } + + /// @copydoc op_max_view::operator=(const min_max_internal::rhs_proxy<op_max_view>&) + reducer_max& operator=(const rhs_proxy& rhs) + { view() = rhs; return *this; } + + //@} + + /** Allow read-only access to the value within the current view. + * + * @returns A const reference to the value within the current view. + */ + const Type& get_reference() const { return view().get_reference(); } + + /// @name Dereference + /** Dereferencing a wrapper is a no-op. It simply returns the wrapper. + * Combined with the rule that a wrapper forwards view operations to the + * view, this means that view operations can be written the same way on + * reducers and wrappers, which is convenient for incrementally + * converting code using wrappers to code using reducers. That is: + * + * reducer< op_max<int> > r; + * r->calc_max(a); // *r returns the view + * // calc_max is a view member function + * + * reducer_max<int> w; + * w->calc_max(a); // *w returns the wrapper + * // calc_max is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_max& operator*() { return *this; } + reducer_max const& operator*() const { return *this; } + + reducer_max* operator->() { return this; } + reducer_max const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_max<Type, Compare, false> >& () + { + return *reinterpret_cast< reducer< op_max<Type, Compare, false> >* >(this); + } + + operator const reducer< op_max<Type, Compare, false> >& () const + { + return *reinterpret_cast< const reducer< op_max<Type, Compare, false> >* >(this); + } + //@} +}; + + +/// @cond internal +// The legacy definition of max_of(reducer_max, value) has different +// behavior and a different return type than this definition. We add an +// unused third argument to this version of the function to give it a different +// signature, so that they won’t end up sharing a single object file entry. +struct max_of_1_0_t {}; +const max_of_1_0_t max_of_1_0 = {}; +/// @endcond + +/** Compute the maximum of the value in a reducer_max and another value. + * + * @deprecated Because reducer_max is deprecated. + * + * The result of this computation can only be assigned back to the original + * reducer or used in another max_of() call. For example, + * + * reducer = max_of(reducer, x); + * reducer = max_of(x, reducer); + * + * @see min_max_internal::rhs_proxy + * + * @ingroup ReducersMinMaxMaxValue + */ +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_view<Type, Compare> > +max_of(const reducer_max<Type, Compare>& r, const Type& value, + const max_of_1_0_t& = max_of_1_0) +{ + return min_max_internal::make_proxy(value, r.view()); +} + +/// @copydoc max_of(const reducer_max<Type, Compare>&, const Type&, const max_of_1_0_t&) +/// @ingroup ReducersMinMaxMaxValue +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_view<Type, Compare> > +max_of(const Type& value, const reducer_max<Type, Compare>& r, + const max_of_1_0_t& = max_of_1_0) +{ + return min_max_internal::make_proxy(value, r.view()); +} + + +/** Deprecated minimum reducer wrapper class. + * + * reducer_min is the same as @ref reducer<@ref op_min>, except that + * reducer_min is a proxy for the contained view, so that accumulator + * variable update operations can be applied directly to the reducer. For + * example, a value is minimized with a `reducer<%op_min>` with + * `r->calc_min(a)`, but a value can be minimized with a `%reducer_min` with + * `r.calc_min(a)`. + * + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_min. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_min` + * and `reducer<%op_min>`. This allows incremental code + * conversion: old code that used `%reducer_min` can pass a + * `%reducer_min` to a converted function that now expects a + * pointer or reference to a `reducer<%op_min>`, and vice + * versa. **But see @ref redminmax_compatibility.** + * + * @tparam Type The value type of the reducer. + * @tparam Compare The “less than” comparator type for the reducer. + * + * @see op_min + * @see op_min_view + * @see reducer + * @see ReducersMinMax + * @ingroup ReducersMinMaxMinValue + */ +template <typename Type, typename Compare=std::less<Type> > +class reducer_min : public reducer< op_min<Type, Compare, true> > +{ + __CILKRTS_STATIC_ASSERT( + ::cilk::internal::class_is_empty< + typename ::cilk::internal::binary_functor<Compare>::type >::value, + "cilk::reducer_min<Type, Compare> only works with " + "an empty Compare class"); + typedef reducer< op_min<Type, Compare, true> > base; +public: + + /// Type of data in a reducer_min. + typedef Type basic_value_type; + + /// The view type for the reducer. + typedef typename base::view_type view_type; + + /// The view type for the reducer. + typedef typename base::view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type monoid_type; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + /// The view’s rhs proxy type. + typedef min_max_internal::rhs_proxy<View> rhs_proxy; + + using base::view; + + /** @name Constructors + */ + //@{ + + /// Construct the wrapper in its identity state (either `!is_set()`, or + /// `value() == identity value`). + reducer_min() : base() {} + + /// Construct the wrapper with a specified initial value. + explicit reducer_min(const Type& initial_value) : base(initial_value) {} + + /// Construct the wrapper in its identity state with a specified + /// comparator. + explicit reducer_min(const Compare& comp) : base(comp) {} + + /// Construct the wrapper with a specified initial value and a specified + /// comparator. + reducer_min(const Type& initial_value, const Compare& comp) + : base(initial_value, comp) {} + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_min_view. */ + //@{ + + /// @copydoc cilk_lib_1_0::min_max_internal::view_content::is_set() const + bool is_set() const { return view().is_set(); } + + /// @copydoc op_min_view::calc_min(const Type&) + reducer_min& calc_min(const Type& x) + { view().calc_min(x); return *this; } + + /// @copydoc op_min_view::operator=(const min_max_internal::rhs_proxy<op_min_view>&) + reducer_min& operator=(const rhs_proxy& rhs) + { view() = rhs; return *this; } + + //@} + + /** Allow read-only access to the value within the current view. + * + * @returns A const reference to the value within the current view. + */ + const Type& get_reference() const { return view().get_reference(); } + + /// @name Dereference + /** Dereferencing a wrapper is a no-op. It simply returns the wrapper. + * Combined with the rule that a wrapper forwards view operations to the + * view, this means that view operations can be written the same way on + * reducers and wrappers, which is convenient for incrementally + * converting code using wrappers to code using reducers. That is: + * + * reducer< op_min<int> > r; + * r->calc_min(a); // *r returns the view + * // calc_min is a view member function + * + * reducer_min<int> w; + * w->calc_min(a); // *w returns the wrapper + * // calc_min is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_min& operator*() { return *this; } + reducer_min const& operator*() const { return *this; } + + reducer_min* operator->() { return this; } + reducer_min const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_min<Type, Compare, false> >& () + { + return *reinterpret_cast< reducer< op_min<Type, Compare, false> >* >(this); + } + + operator const reducer< op_min<Type, Compare, false> >& () const + { + return *reinterpret_cast< const reducer< op_min<Type, Compare, false> >* >(this); + } + //@} +}; + + +/** Compute the minimum of a reducer and a value. + * + * @deprecated Because reducer_min is deprecated. + */ +//@{ +// The legacy definition of min_of(reducer_min, value) has different +// behavior and a different return type than this definition. We add an +// unused third argument to this version of the function to give it a different +// signature, so that they won’t end up sharing a single object file entry. +struct min_of_1_0_t {}; +const min_of_1_0_t min_of_1_0 = {}; + +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_view<Type, Compare> > +min_of(const reducer_min<Type, Compare>& r, const Type& value, + const min_of_1_0_t& = min_of_1_0) +{ + return min_max_internal::make_proxy(value, r.view()); +} + +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_view<Type, Compare> > +min_of(const Type& value, const reducer_min<Type, Compare>& r, + const min_of_1_0_t& = min_of_1_0) +{ + return min_max_internal::make_proxy(value, r.view()); +} +//@} + + +/** Deprecated maximum with index reducer wrapper class. + * + * reducer_max_index is the same as @ref reducer<@ref op_max_index>, except + * that reducer_max_index is a proxy for the contained view, so that + * accumulator variable update operations can be applied directly to the + * reducer. For example, a value is maximized with a `reducer<%op_max_index>` + * with `r->calc_max(i, a)`, but a value can be maximized with a + * `%reducer_max` with `r.calc_max(i, aa)`. + * + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_max. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_max_index` + * and `reducer<%op_max_index>`. This allows incremental code + * conversion: old code that used `%reducer_max_index` can pass a + * `%reducer_max_index` to a converted function that now expects a + * pointer or reference to a `reducer<%op_max_index>`, and vice + * versa. **But see @ref redminmax_compatibility.** + * + * @tparam Index The index type of the reducer. + * @tparam Type The value type of the reducer. + * @tparam Compare The “less than” comparator type for the reducer. + * + * @see op_max_index + * @see op_max_index_view + * @see reducer + * @see ReducersMinMax + * @ingroup ReducersMinMaxMaxIndex + */ +template < typename Index + , typename Type + , typename Compare = std::less<Type> + > +class reducer_max_index : + public reducer< op_max_index<Index, Type, Compare, true> > +{ + __CILKRTS_STATIC_ASSERT( + ::cilk::internal::class_is_empty< + typename ::cilk::internal::binary_functor<Compare>::type >::value, + "cilk::reducer_max_index<Type, Compare> only works with " + "an empty Compare class"); + typedef reducer< op_max_index<Index, Type, Compare, true> > base; +public: + + /// Type of data in a reducer_max_index. + typedef Type basic_value_type; + + /// The view type for the reducer. + typedef typename base::view_type view_type; + + /// The view type for the reducer. + typedef typename base::view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type monoid_type; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + /// The view’s rhs proxy type. + typedef min_max_internal::rhs_proxy<View> rhs_proxy; + + using base::view; + + /** @name Constructors + */ + //@{ + + /// Construct the wrapper in its identity state (`!is_set()`). + reducer_max_index() : base() {} + + /// Construct with a specified initial index and value. + reducer_max_index(const Index& initial_index, + const Type& initial_value) + : base(initial_index, initial_value) {} + + /// Construct the wrapper with a specified comparator. + explicit reducer_max_index(const Compare& comp) : base(comp) {} + + /// Construct the wrapper with a specified initial index, value, + /// and comparator. + reducer_max_index(const Index& initial_index, + const Type& initial_value, + const Compare& comp) + : base(initial_index, initial_value, comp) {} + + //@} + + /** @name Set / Get + */ + //@{ + + /// Set the index and value of this object. + void set_value(const Index& index, const Type& value) + { base::set_value(std::make_pair(index, value)); } + + /// Return the maximum value. + const Type& get_value() const + { return view().get_reference(); } + + /// Return the maximum index. + const Index& get_index() const + { return view().get_index_reference(); } + + /// Return a const reference to value data member in the view. + const Type& get_reference() const + { return view().get_reference(); } + + /// Return a const reference to index data member in the view. + const Index& get_index_reference() const + { return view().get_index_reference(); } + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_max_view. */ + //@{ + + /// @copydoc cilk_lib_1_0::min_max_internal::view_content::is_set() const + bool is_set() const { return view().is_set(); } + + /// @copydoc op_max_index_view::calc_max(const Index&, const Type&) + reducer_max_index& calc_max(const Index& i, const Type& x) + { view().calc_max(i, x); return *this; } + + /// @copydoc op_max_view::operator=(const min_max_internal::rhs_proxy<op_max_view>&) + reducer_max_index& operator=(const rhs_proxy& rhs) + { view() = rhs; return *this; } + + //@} + + /// @name Dereference + /** Dereferencing a wrapper is a no-op. It simply returns the wrapper. + * Combined with the rule that a wrapper forwards view operations to the + * view, this means that view operations can be written the same way on + * reducers and wrappers, which is convenient for incrementally + * converting code using wrappers to code using reducers. That is: + * + * reducer< op_max_index<int, int> > r; + * r->calc_max(i, a); // *r returns the view + * // calc_max is a view member function + * + * reducer_max_index<int, int> w; + * w->calc_max(i, a); // *w returns the wrapper + * // calc_max is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_max_index& operator*() { return *this; } + reducer_max_index const& operator*() const { return *this; } + + reducer_max_index* operator->() { return this; } + reducer_max_index const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_max_index<Index, Type, Compare, false> >& () + { + return *reinterpret_cast< reducer< op_max_index<Index, Type, Compare, false> >* >(this); + } + + operator const reducer< op_max_index<Index, Type, Compare, false> >& () const + { + return *reinterpret_cast< const reducer< op_max_index<Index, Type, Compare, false> >* >(this); + } + //@} + +}; + + +/** Deprecated minimum with index reducer wrapper class. + * + * reducer_min_index is the same as @ref reducer<@ref op_min_index>, except + * that reducer_min_index is a proxy for the contained view, so that + * accumulator variable update operations can be applied directly to the + * reducer. For example, a value is minimized with a `reducer<%op_min_index>` + * with `r->calc_min(i, a)`, but a value can be minimized with a + * `%reducer_min` with `r.calc_min(i, aa)`. + * + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_min. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_min_index` + * and `reducer<%op_min_index>`. This allows incremental code + * conversion: old code that used `%reducer_min_index` can pass a + * `%reducer_min_index` to a converted function that now expects a + * pointer or reference to a `reducer<%op_min_index>`, and vice + * versa. **But see @ref redminmax_compatibility.** + * + * @tparam Index The index type of the reducer. + * @tparam Type The value type of the reducer. + * @tparam Compare The “less than” comparator type for the reducer. + * + * @see op_min_index + * @see op_min_index_view + * @see reducer + * @see ReducersMinMax + * @ingroup ReducersMinMaxMinIndex + */ +template < typename Index + , typename Type + , typename Compare = std::less<Type> + > +class reducer_min_index : + public reducer< op_min_index<Index, Type, Compare, true> > +{ + __CILKRTS_STATIC_ASSERT( + ::cilk::internal::class_is_empty< + typename ::cilk::internal::binary_functor<Compare>::type >::value, + "cilk::reducer_min_index<Type, Compare> only works with " + "an empty Compare class"); + typedef reducer< op_min_index<Index, Type, Compare, true> > base; +public: + + /// Type of data in a reducer_min_index. + typedef Type basic_value_type; + + /// The view type for the reducer. + typedef typename base::view_type view_type; + + /// The view type for the reducer. + typedef typename base::view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type monoid_type; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + /// The view’s rhs proxy type. + typedef min_max_internal::rhs_proxy<View> rhs_proxy; + + using base::view; + + /** @name Constructors + */ + //@{ + + /// Construct the wrapper in its identity state (`!is_set()`). + reducer_min_index() : base() {} + + /// Construct with a specified initial index and value. + reducer_min_index(const Index& initial_index, + const Type& initial_value) + : base(initial_index, initial_value) {} + + /// Construct the wrapper with a specified comparator. + explicit reducer_min_index(const Compare& comp) : base(comp) {} + + /// Construct the wrapper with a specified initial index, value, + /// and comparator. + reducer_min_index(const Index& initial_index, + const Type& initial_value, + const Compare& comp) + : base(initial_index, initial_value, comp) {} + + //@} + + /** @name Set / Get + */ + //@{ + + /// Set the index and value of this object. + void set_value(const Index& index, const Type& value) + { base::set_value(std::make_pair(index, value)); } + + /// Return the minimum value. + const Type& get_value() const + { return view().get_reference(); } + + /// Return the minimum index. + const Index& get_index() const + { return view().get_index_reference(); } + + /// Return a const reference to value data member in the view. + const Type& get_reference() const + { return view().get_reference(); } + + /// Return a const reference to index data member in the view. + const Index& get_index_reference() const + { return view().get_index_reference(); } + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_min_view. */ + //@{ + + /// @copydoc cilk_lib_1_0::min_max_internal::view_content::is_set() const + bool is_set() const { return view().is_set(); } + + /// @copydoc op_min_index_view::calc_min(const Index&, const Type&) + reducer_min_index& calc_min(const Index& i, const Type& x) + { view().calc_min(i, x); return *this; } + + /// @copydoc op_min_view::operator=(const min_max_internal::rhs_proxy<op_min_view>&) + reducer_min_index& operator=(const rhs_proxy& rhs) + { view() = rhs; return *this; } + + //@} + + /// @name Dereference + /** Dereferencing a wrapper is a no-op. It simply returns the wrapper. + * Combined with the rule that a wrapper forwards view operations to the + * view, this means that view operations can be written the same way on + * reducers and wrappers, which is convenient for incrementally + * converting code using wrappers to code using reducers. That is: + * + * reducer< op_min_index<int, int> > r; + * r->calc_min(i, a); // *r returns the view + * // calc_min is a view member function + * + * reducer_min_index<int, int> w; + * w->calc_min(i, a); // *w returns the wrapper + * // calc_min is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_min_index& operator*() { return *this; } + reducer_min_index const& operator*() const { return *this; } + + reducer_min_index* operator->() { return this; } + reducer_min_index const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_min_index<Index, Type, Compare, false> >& () + { + return *reinterpret_cast< reducer< op_min_index<Index, Type, Compare, false> >* >(this); + } + + operator const reducer< op_min_index<Index, Type, Compare, false> >& () const + { + return *reinterpret_cast< const reducer< op_min_index<Index, Type, Compare, false> >* >(this); + } + //@} + +}; + + +#ifndef CILK_LIBRARY_0_9_REDUCER_MINMAX +} // namespace cilk_lib_1_0 +using namespace cilk_lib_1_0; +#endif + + +/// @cond internal +/** Metafunction specialization for reducer conversion. + * + * These specializations of the @ref legacy_reducer_downcast template class + * defined in reducer.h causes each `reducer< op_xxxx<Type> >` classes to have + * an `operator reducer_xxxx<Type>& ()` conversion operator that statically + * downcasts the `reducer<op_xxxx>` to the corresponding `reducer_xxxx` type. + * (The reverse conversion, from `reducer_xxxx` to `reducer<op_xxxx>`, is just + * an upcast, which is provided for free by the language.) + */ +template <typename Type, typename Compare, bool Align> +struct legacy_reducer_downcast< reducer< op_max<Type, Compare, Align> > > +{ + typedef reducer_max<Type> type; +}; + +template <typename Type, typename Compare, bool Align> +struct legacy_reducer_downcast< reducer< op_min<Type, Compare, Align> > > +{ + typedef reducer_min<Type> type; +}; + +template <typename Index, typename Type, typename Compare, bool Align> +struct legacy_reducer_downcast< reducer< op_max_index<Index, Type, Compare, Align> > > +{ + typedef reducer_max_index<Index, Type> type; +}; + +template <typename Index, typename Type, typename Compare, bool Align> +struct legacy_reducer_downcast< reducer< op_min_index<Index, Type, Compare, Align> > > +{ + typedef reducer_min_index<Index, Type> type; +}; +/// @endcond + +} // namespace cilk + +#endif // __cplusplus + + +/** @name C language reducer macros + * + * These macros are used to declare and work with numeric minimum and maximum reducers in C + * code. + * + * @see @ref page_reducers_in_c + */ + //@{ + + +#ifdef CILK_C_DEFINE_REDUCERS + +/* Integer min/max constants */ +#include <limits.h> + +/* Wchar_t min/max constants */ +#if defined(_MSC_VER) || defined(ANDROID) +# include <wchar.h> +#else +# include <stdint.h> +#endif + +/* Floating-point min/max constants */ +#include <math.h> +#ifndef HUGE_VALF + static const unsigned int __huge_valf[] = {0x7f800000}; +# define HUGE_VALF (*((const float *)__huge_valf)) +#endif + +#ifndef HUGE_VALL + static const unsigned int __huge_vall[] = {0, 0, 0x00007f80, 0}; +# define HUGE_VALL (*((const long double *)__huge_vall)) +#endif + +#endif + +/** Max reducer type name. + * + * This macro expands into the identifier which is the name of the max reducer + * type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying the type of the + * reducer. + * + * @see @ref reducers_c_predefined + */ +#define CILK_C_REDUCER_MAX_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_max_,tn) + +/** Declare a max reducer object. + * + * This macro expands into a declaration of a max reducer object for a specified numeric + * type. For example: + * + * CILK_C_REDUCER_MAX(my_reducer, double, -DBL_MAX); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying the type of the + * reducer. + * @param v The initial value for the reducer. (A value which can be assigned to the + * numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + */ +#define CILK_C_REDUCER_MAX(obj,tn,v) \ + CILK_C_REDUCER_MAX_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_max_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_max_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, v) + +/** Maximize with a value. + * + * `CILK_C_REDUCER_MAX_CALC(reducer, v)` sets the current view of the + * reducer to the max of its previous value and a specified new value. + * This is equivalent to + * + * REDUCER_VIEW(reducer) = max(REDUCER_VIEW(reducer), v) + * + * @param reducer The reducer whose contained value is to be updated. + * @param v The value that it is to be maximized with. + */ +#define CILK_C_REDUCER_MAX_CALC(reducer, v) do { \ + _Typeof((reducer).value)* view = &(REDUCER_VIEW(reducer)); \ + _Typeof(v) __value = (v); \ + if (*view < __value) { \ + *view = __value; \ + } } while (0) + +/// @cond internal + +/** Declare the max reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which implement + * the reducer functionality for the max reducer type for a specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer type name, + * function names, etc. + */ +#define CILK_C_REDUCER_MAX_DECLARATION(t,tn,id) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_MAX_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_max,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_max,tn); + +/** Define the max reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement the + * reducer functionality for the max reducer type for a specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer type name, + * function names, etc. + */ +#define CILK_C_REDUCER_MAX_DEFINITION(t,tn,id) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_MAX_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_max,tn,l,r) \ + { if (*(t*)l < *(t*)r) *(t*)l = *(t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_max,tn) \ + { *(t*)v = id; } + +//@{ +/** @def CILK_C_REDUCER_MAX_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` will be defined, and + * this macro will generate reducer implementation functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` + * will be undefined, and this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_MAX_INSTANCE(t,tn,id) \ + CILK_C_REDUCER_MAX_DEFINITION(t,tn,id) +#else +# define CILK_C_REDUCER_MAX_INSTANCE(t,tn,id) \ + CILK_C_REDUCER_MAX_DECLARATION(t,tn,id) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for each + * numeric type. + */ +__CILKRTS_BEGIN_EXTERN_C +CILK_C_REDUCER_MAX_INSTANCE(char, char, CHAR_MIN) +CILK_C_REDUCER_MAX_INSTANCE(unsigned char, uchar, 0) +CILK_C_REDUCER_MAX_INSTANCE(signed char, schar, SCHAR_MIN) +CILK_C_REDUCER_MAX_INSTANCE(wchar_t, wchar_t, WCHAR_MIN) +CILK_C_REDUCER_MAX_INSTANCE(short, short, SHRT_MIN) +CILK_C_REDUCER_MAX_INSTANCE(unsigned short, ushort, 0) +CILK_C_REDUCER_MAX_INSTANCE(int, int, INT_MIN) +CILK_C_REDUCER_MAX_INSTANCE(unsigned int, uint, 0) +CILK_C_REDUCER_MAX_INSTANCE(unsigned int, unsigned, 0) // alternate name +CILK_C_REDUCER_MAX_INSTANCE(long, long, LONG_MIN) +CILK_C_REDUCER_MAX_INSTANCE(unsigned long, ulong, 0) +CILK_C_REDUCER_MAX_INSTANCE(long long, longlong, LLONG_MIN) +CILK_C_REDUCER_MAX_INSTANCE(unsigned long long, ulonglong, 0) +CILK_C_REDUCER_MAX_INSTANCE(float, float, -HUGE_VALF) +CILK_C_REDUCER_MAX_INSTANCE(double, double, -HUGE_VAL) +CILK_C_REDUCER_MAX_INSTANCE(long double, longdouble, -HUGE_VALL) +__CILKRTS_END_EXTERN_C + +/// @endcond + +/** Max_index reducer type name. + * + * This macro expands into the identifier which is the name of the max_index reducer + * type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying the type of the + * reducer. + * + * @see @ref reducers_c_predefined + */ +#define CILK_C_REDUCER_MAX_INDEX_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_max_index_,tn) + +/** Declare an op_max_index reducer object. + * + * This macro expands into a declaration of a max_index reducer object for a specified + * numeric type. For example: + * + * CILK_C_REDUCER_MAX_INDEX(my_reducer, double, -DBL_MAX_INDEX); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying the type of the + * reducer. + * @param v The initial value for the reducer. (A value which can be assigned to the + * numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + */ +#define CILK_C_REDUCER_MAX_INDEX(obj,tn,v) \ + CILK_C_REDUCER_MAX_INDEX_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_max_index_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_max_index_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, {0, v}) + +/** Maximize with a value. + * + * `CILK_C_REDUCER_MAX_INDEX_CALC(reducer, i, v)` sets the current view of the + * reducer to the max of its previous value and a specified new value. + * This is equivalent to + * + * REDUCER_VIEW(reducer) = max_index(REDUCER_VIEW(reducer), v) + * + * If the value of the reducer is changed to @a v, then the index of the reducer is + * changed to @a i. + * + * @param reducer The reducer whose contained value and index are to be updated. + * @param i The index associated with the new value. + * @param v The value that it is to be maximized with. + */ +#define CILK_C_REDUCER_MAX_INDEX_CALC(reducer, i, v) do { \ + _Typeof((reducer).value)* view = &(REDUCER_VIEW(reducer)); \ + _Typeof(v) __value = (v); \ + if (view->value < __value) { \ + view->index = (i); \ + view->value = __value; \ + } } while (0) + +/// @cond internal + +/** Declare the max_index view type. + * + * The view of a max_index reducer is a structure containing both the + * maximum value for the reducer and the index that was associated with + * that value in the sequence of input values. + */ +#define CILK_C_REDUCER_MAX_INDEX_VIEW(t,tn) \ + typedef struct { \ + __STDNS ptrdiff_t index; \ + t value; \ + } __CILKRTS_MKIDENT(cilk_c_reducer_max_index_view_,tn) + +/** Declare the max_index reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which implement + * the reducer functionality for the max_index reducer type for a specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer type name, + * function names, etc. + */ +#define CILK_C_REDUCER_MAX_INDEX_DECLARATION(t,tn,id) \ + CILK_C_REDUCER_MAX_INDEX_VIEW(t,tn); \ + typedef CILK_C_DECLARE_REDUCER( \ + __CILKRTS_MKIDENT(cilk_c_reducer_max_index_view_,tn)) \ + CILK_C_REDUCER_MAX_INDEX_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_max_index,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_max_index,tn); + +/** Define the max_index reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement the + * reducer functionality for the max_index reducer type for a specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer type name, + * function names, etc. + */ +#define CILK_C_REDUCER_MAX_INDEX_DEFINITION(t,tn,id) \ + CILK_C_REDUCER_MAX_INDEX_VIEW(t,tn); \ + typedef CILK_C_DECLARE_REDUCER( \ + __CILKRTS_MKIDENT(cilk_c_reducer_max_index_view_,tn)) \ + CILK_C_REDUCER_MAX_INDEX_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_max_index,tn,l,r) \ + { typedef __CILKRTS_MKIDENT(cilk_c_reducer_max_index_view_,tn) view_t; \ + if (((view_t*)l)->value < ((view_t*)r)->value) \ + *(view_t*)l = *(view_t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_max_index,tn) \ + { typedef __CILKRTS_MKIDENT(cilk_c_reducer_max_index_view_,tn) view_t; \ + ((view_t*)v)->index = 0; ((view_t*)v)->value = id; } + +//@{ +/** @def CILK_C_REDUCER_MAX_INDEX_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` will be defined, and + * this macro will generate reducer implementation functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` + * will be undefined, and this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_MAX_INDEX_INSTANCE(t,tn,id) \ + CILK_C_REDUCER_MAX_INDEX_DEFINITION(t,tn,id) +#else +# define CILK_C_REDUCER_MAX_INDEX_INSTANCE(t,tn,id) \ + CILK_C_REDUCER_MAX_INDEX_DECLARATION(t,tn,id) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for each + * numeric type. + */ +__CILKRTS_BEGIN_EXTERN_C +CILK_C_REDUCER_MAX_INDEX_INSTANCE(char, char, CHAR_MIN) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(unsigned char, uchar, 0) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(signed char, schar, SCHAR_MIN) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(wchar_t, wchar_t, WCHAR_MIN) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(short, short, SHRT_MIN) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(unsigned short, ushort, 0) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(int, int, INT_MIN) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(unsigned int, uint, 0) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(unsigned int, unsigned, 0) // alternate name +CILK_C_REDUCER_MAX_INDEX_INSTANCE(long, long, LONG_MIN) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(unsigned long, ulong, 0) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(long long, longlong, LLONG_MIN) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(unsigned long long, ulonglong, 0) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(float, float, -HUGE_VALF) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(double, double, -HUGE_VAL) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(long double, longdouble, -HUGE_VALL) +__CILKRTS_END_EXTERN_C + +/// @endcond + +/** Min reducer type name. + * + * This macro expands into the identifier which is the name of the min reducer + * type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying the type of the + * reducer. + * + * @see @ref reducers_c_predefined + */ +#define CILK_C_REDUCER_MIN_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_min_,tn) + +/** Declare a min reducer object. + * + * This macro expands into a declaration of a min reducer object for a specified numeric + * type. For example: + * + * CILK_C_REDUCER_MIN(my_reducer, double, DBL_MAX); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying the type of the + * reducer. + * @param v The initial value for the reducer. (A value which can be assigned to the + * numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + */ +#define CILK_C_REDUCER_MIN(obj,tn,v) \ + CILK_C_REDUCER_MIN_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_min_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_min_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, v) + +/** Minimize with a value. + * + * `CILK_C_REDUCER_MIN_CALC(reducer, v)` sets the current view of the + * reducer to the min of its previous value and a specified new value. + * This is equivalent to + * + * REDUCER_VIEW(reducer) = min(REDUCER_VIEW(reducer), v) + * + * @param reducer The reducer whose contained value is to be updated. + * @param v The value that it is to be minimized with. + */ +#define CILK_C_REDUCER_MIN_CALC(reducer, v) do { \ + _Typeof((reducer).value)* view = &(REDUCER_VIEW(reducer)); \ + _Typeof(v) __value = (v); \ + if (*view > __value) { \ + *view = __value; \ + } } while (0) + +/// @cond internal + +/** Declare the min reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which implement + * the reducer functionality for the min reducer type for a specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer type name, + * function names, etc. + */ +#define CILK_C_REDUCER_MIN_DECLARATION(t,tn,id) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_MIN_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_min,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_min,tn); + +/** Define the min reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement the + * reducer functionality for the min reducer type for a specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer type name, + * function names, etc. + */ +#define CILK_C_REDUCER_MIN_DEFINITION(t,tn,id) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_MIN_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_min,tn,l,r) \ + { if (*(t*)l > *(t*)r) *(t*)l = *(t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_min,tn) \ + { *(t*)v = id; } + +//@{ +/** @def CILK_C_REDUCER_MIN_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` will be defined, and + * this macro will generate reducer implementation functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` + * will be undefined, and this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_MIN_INSTANCE(t,tn,id) \ + CILK_C_REDUCER_MIN_DEFINITION(t,tn,id) +#else +# define CILK_C_REDUCER_MIN_INSTANCE(t,tn,id) \ + CILK_C_REDUCER_MIN_DECLARATION(t,tn,id) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for each + * numeric type. + */ +__CILKRTS_BEGIN_EXTERN_C +CILK_C_REDUCER_MIN_INSTANCE(char, char, CHAR_MAX) +CILK_C_REDUCER_MIN_INSTANCE(unsigned char, uchar, CHAR_MAX) +CILK_C_REDUCER_MIN_INSTANCE(signed char, schar, SCHAR_MAX) +CILK_C_REDUCER_MIN_INSTANCE(wchar_t, wchar_t, WCHAR_MAX) +CILK_C_REDUCER_MIN_INSTANCE(short, short, SHRT_MAX) +CILK_C_REDUCER_MIN_INSTANCE(unsigned short, ushort, USHRT_MAX) +CILK_C_REDUCER_MIN_INSTANCE(int, int, INT_MAX) +CILK_C_REDUCER_MIN_INSTANCE(unsigned int, uint, UINT_MAX) +CILK_C_REDUCER_MIN_INSTANCE(unsigned int, unsigned, UINT_MAX) // alternate name +CILK_C_REDUCER_MIN_INSTANCE(long, long, LONG_MAX) +CILK_C_REDUCER_MIN_INSTANCE(unsigned long, ulong, ULONG_MAX) +CILK_C_REDUCER_MIN_INSTANCE(long long, longlong, LLONG_MAX) +CILK_C_REDUCER_MIN_INSTANCE(unsigned long long, ulonglong, ULLONG_MAX) +CILK_C_REDUCER_MIN_INSTANCE(float, float, HUGE_VALF) +CILK_C_REDUCER_MIN_INSTANCE(double, double, HUGE_VAL) +CILK_C_REDUCER_MIN_INSTANCE(long double, longdouble, HUGE_VALL) +__CILKRTS_END_EXTERN_C + +/// @endcond + +/** Min_index reducer type name. + * + * This macro expands into the identifier which is the name of the min_index reducer + * type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying the type of the + * reducer. + * + * @see @ref reducers_c_predefined + */ +#define CILK_C_REDUCER_MIN_INDEX_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_min_index_,tn) + +/** Declare an op_min_index reducer object. + * + * This macro expands into a declaration of a min_index reducer object for a specified + * numeric type. For example: + * + * CILK_C_REDUCER_MIN_INDEX(my_reducer, double, -DBL_MIN_INDEX); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying the type of the + * reducer. + * @param v The initial value for the reducer. (A value which can be assigned to the + * numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + */ +#define CILK_C_REDUCER_MIN_INDEX(obj,tn,v) \ + CILK_C_REDUCER_MIN_INDEX_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_min_index_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_min_index_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, {0, v}) + +/** Minimize with a value. + * + * `CILK_C_REDUCER_MIN_INDEX_CALC(reducer, i, v)` sets the current view of the + * reducer to the min of its previous value and a specified new value. + * This is equivalent to + * + * REDUCER_VIEW(reducer) = min_index(REDUCER_VIEW(reducer), v) + * + * If the value of the reducer is changed to @a v, then the index of the reducer is + * changed to @a i. + * + * @param reducer The reducer whose contained value and index are to be updated. + * @param i The index associated with the new value. + * @param v The value that it is to be minimized with. + */ +#define CILK_C_REDUCER_MIN_INDEX_CALC(reducer, i, v) do { \ + _Typeof((reducer).value)* view = &(REDUCER_VIEW(reducer)); \ + _Typeof(v) __value = (v); \ + if (view->value > __value) { \ + view->index = (i); \ + view->value = __value; \ + } } while (0) + +/// @cond internal + +/** Declare the min_index view type. + * + * The view of a min_index reducer is a structure containing both the + * minimum value for the reducer and the index that was associated with + * that value in the sequence of input values. + */ +#define CILK_C_REDUCER_MIN_INDEX_VIEW(t,tn) \ + typedef struct { \ + __STDNS ptrdiff_t index; \ + t value; \ + } __CILKRTS_MKIDENT(cilk_c_reducer_min_index_view_,tn) + +/** Declare the min_index reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which implement + * the reducer functionality for the min_index reducer type for a specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer type name, + * function names, etc. + */ +#define CILK_C_REDUCER_MIN_INDEX_DECLARATION(t,tn,id) \ + CILK_C_REDUCER_MIN_INDEX_VIEW(t,tn); \ + typedef CILK_C_DECLARE_REDUCER( \ + __CILKRTS_MKIDENT(cilk_c_reducer_min_index_view_,tn)) \ + CILK_C_REDUCER_MIN_INDEX_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_min_index,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_min_index,tn); + +/** Define the min_index reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement the + * reducer functionality for the min_index reducer type for a specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer type name, + * function names, etc. + */ +#define CILK_C_REDUCER_MIN_INDEX_DEFINITION(t,tn,id) \ + CILK_C_REDUCER_MIN_INDEX_VIEW(t,tn); \ + typedef CILK_C_DECLARE_REDUCER( \ + __CILKRTS_MKIDENT(cilk_c_reducer_min_index_view_,tn)) \ + CILK_C_REDUCER_MIN_INDEX_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_min_index,tn,l,r) \ + { typedef __CILKRTS_MKIDENT(cilk_c_reducer_min_index_view_,tn) view_t; \ + if (((view_t*)l)->value > ((view_t*)r)->value) \ + *(view_t*)l = *(view_t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_min_index,tn) \ + { typedef __CILKRTS_MKIDENT(cilk_c_reducer_min_index_view_,tn) view_t; \ + ((view_t*)v)->index = 0; ((view_t*)v)->value = id; } + +//@{ +/** @def CILK_C_REDUCER_MIN_INDEX_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` will be defined, and + * this macro will generate reducer implementation functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` + * will be undefined, and this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_MIN_INDEX_INSTANCE(t,tn,id) \ + CILK_C_REDUCER_MIN_INDEX_DEFINITION(t,tn,id) +#else +# define CILK_C_REDUCER_MIN_INDEX_INSTANCE(t,tn,id) \ + CILK_C_REDUCER_MIN_INDEX_DECLARATION(t,tn,id) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for each + * numeric type. + */ +__CILKRTS_BEGIN_EXTERN_C +CILK_C_REDUCER_MIN_INDEX_INSTANCE(char, char, CHAR_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(unsigned char, uchar, CHAR_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(signed char, schar, SCHAR_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(wchar_t, wchar_t, WCHAR_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(short, short, SHRT_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(unsigned short, ushort, USHRT_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(int, int, INT_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(unsigned int, uint, UINT_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(unsigned int, unsigned, UINT_MAX) // alternate name +CILK_C_REDUCER_MIN_INDEX_INSTANCE(long, long, LONG_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(unsigned long, ulong, ULONG_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(long long, longlong, LLONG_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(unsigned long long, ulonglong, ULLONG_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(float, float, HUGE_VALF) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(double, double, HUGE_VAL) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(long double, longdouble, HUGE_VALL) +__CILKRTS_END_EXTERN_C + +/// @endcond + +//@} + +#endif // defined REDUCER_MAX_H_INCLUDED diff --git a/libcilkrts/include/cilk/reducer_opadd.h b/libcilkrts/include/cilk/reducer_opadd.h new file mode 100644 index 00000000000..4b7a83f845d --- /dev/null +++ b/libcilkrts/include/cilk/reducer_opadd.h @@ -0,0 +1,690 @@ +/* reducer_opadd.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_opadd.h + * + * @brief Defines classes for doing parallel addition reductions. + * + * @ingroup ReducersAdd + * + * @see ReducersAdd + */ + +#ifndef REDUCER_OPADD_H_INCLUDED +#define REDUCER_OPADD_H_INCLUDED + +#include <cilk/reducer.h> + +/** @defgroup ReducersAdd Addition Reducers + * + * Addition reducers allow the computation of the sum of a set of values in + * parallel. + * + * @ingroup Reducers + * + * You should be familiar with @ref pagereducers "Cilk reducers", described in + * file `reducers.md`, and particularly with @ref reducers_using, before trying + * to use the information in this file. + * + * @section redopadd_usage Usage Example + * + * cilk::reducer< cilk::op_add<int> > r; + * cilk_for (int i = 0; i != N; ++i) { + * *r += a[i]; + * } + * return r.get_value(); + * + * @section redopadd_monoid The Monoid + * + * @subsection redopadd_monoid_values Value Set + * + * The value set of an addition reducer is the set of values of `Type`, which + * is expected to be a builtin numeric type (or something like it, such as + * `std::complex`). + * + * @subsection redopadd_monoid_operator Operator + * + * The operator of an addition reducer is the addition operator, defined by + * the “`+`” binary operator on `Type`. + * + * @subsection redopadd_monoid_identity Identity + * + * The identity value of the reducer is the numeric value “`0`”. This is + * expected to be the value of the default constructor `Type()`. + * + * @section redopadd_operations Operations + * + * @subsection redopadd_constructors Constructors + * + * reducer() // identity + * reducer(const Type& value) + * reducer(move_in(Type& variable)) + * + * @subsection redopadd_get_set Set and Get + * + * r.set_value(const Type& value) + * const Type& = r.get_value() const + * r.move_in(Type& variable) + * r.move_out(Type& variable) + * + * @subsection redopadd_initial Initial Values + * + * If an addition reducer is constructed without an explicit initial value, + * then its initial value will be its identity value, as long as `Type` + * satisfies the requirements of @ref redopadd_types. + * + * @subsection redopadd_view_ops View Operations + * + * *r += a + * *r -= a + * ++*r + * --*r + * (*r)++ + * (*r)-- + * *r = *r + a + * *r = *r - a + * *r = *r ± a1 ± a2 … ± an + * + * The post-increment and post-decrement operations do not return a value. (If + * they did, they would expose the value contained in the view, which is + * non-deterministic in the middle of a reduction.) + * + * Note that subtraction operations are allowed on an addition reducer because + * subtraction is equivalent to addition with a negated operand. It is true + * that `(x - y) - z` is not equivalent to `x - (y - z)`, but + * `(x + (-y)) + (-z)` _is_ equivalent to `x + ((-y) + (-z))`. + * + * @section redopadd_floating_point Issues with Floating-Point Types + * + * Because of precision and round-off issues, floating-point addition is not + * really associative. For example, `(1e30 + -1e30) + 1 == 1`, but + * `1e30 + (-1e30 + 1) == 0`. + * + * In many cases, this won’t matter, but computations which have been + * carefully ordered to control round-off errors may not deal well with + * being reassociated. In general, you should be sure to understand the + * floating-point behavior of your program before doing any transformation + * that will reassociate its computations. + * + * @section redopadd_types Type and Operator Requirements + * + * `Type` must be `Copy Constructible`, `Default Constructible`, and + * `Assignable`. + * + * The operator “`+=`” must be defined on `Type`, with `x += a` having the + * same meaning as `x = x + a`. In addition, if the code uses the “`-=`”, + * pre-increment, post-increment, pre-decrement, or post-decrement operators, + * then the corresponding operators must be defined on `Type`. + * + * The expression `Type()` must be a valid expression which yields the + * identity value (the value of `Type` whose numeric value is zero). + * + * @section redopadd_in_c Addition Reducers in C + * + * The @ref CILK_C_REDUCER_OPADD and @ref CILK_C_REDUCER_OPADD_TYPE macros can + * be used to do addition reductions in C. For example: + * + * CILK_C_REDUCER_OPADD(r, double, 0); + * CILK_C_REGISTER_REDUCER(r); + * cilk_for(int i = 0; i != n; ++i) { + * REDUCER_VIEW(r) += a[i]; + * } + * CILK_C_UNREGISTER_REDUCER(r); + * printf("The sum of the elements of a is %f\n", REDUCER_VIEW(r)); + * + * See @ref reducers_c_predefined. + */ + +#ifdef __cplusplus + +namespace cilk { + +/** The addition reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_add<Type> >`. It holds the accumulator variable + * for the reduction, and allows only addition and subtraction operations to + * be performed on it. + * + * @note The reducer “dereference” operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `+=` operation would be used in an expression like `*r += a`, where + * `r` is an op_add reducer variable. + * + * @tparam Type The type of the contained accumulator variable. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * + * @see ReducersAdd + * @see op_add + * + * @ingroup ReducersAdd + */ +template <typename Type> +class op_add_view : public scalar_view<Type> +{ + typedef scalar_view<Type> base; + +public: + /** Class to represent the right-hand side of + * `*reducer = *reducer ± value`. + * + * The only assignment operator for the op_add_view class takes an + * rhs_proxy as its operand. This results in the syntactic restriction + * that the only expressions that can be assigned to an op_add_view are + * ones which generate an rhs_proxy — that is, expressions of the form + * `op_add_view ± value ... ± value`. + * + * @warning + * The lhs and rhs views in such an assignment must be the same; + * otherwise, the behavior will be undefined. (I.e., `v1 = v1 + x` is + * legal; `v1 = v2 + x` is illegal.) This condition will be checked with a + * runtime assertion when compiled in debug mode. + * + * @see op_add_view + */ + class rhs_proxy { + friend class op_add_view; + + const op_add_view* m_view; + Type m_value; + + // Constructor is invoked only from op_add_view::operator+() and + // op_add_view::operator-(). + // + rhs_proxy(const op_add_view* view, const Type& value) : + m_view(view), m_value(value) {} + + rhs_proxy& operator=(const rhs_proxy&); // Disable assignment operator + rhs_proxy(); // Disable default constructor + + public: + //@{ + /** Add or subtract an additional rhs value. If `v` is an op_add_view + * and `a1` is a value, then the expression `v + a1` invokes the view’s + * `operator+()` to create an rhs_proxy for `(v, a1)`; then + * `v + a1 + a2` invokes the rhs_proxy’s `operator+()` to create a new + * rhs_proxy for `(v, a1+a2)`. This allows the right-hand side of an + * assignment to be not just `view ± value`, but + * `view ± value ± value ... ± value`. The effect is that + * + * v = v ± a1 ± a2 ... ± an; + * + * is evaluated as + * + * v = v ± (±a1 ± a2 ... ± an); + */ + rhs_proxy& operator+(const Type& x) { m_value += x; return *this; } + rhs_proxy& operator-(const Type& x) { m_value -= x; return *this; } + //@} + }; + + + /** Default/identity constructor. This constructor initializes the + * contained value to `Type()`, which is expected to be the identity value + * for addition on `Type`. + */ + op_add_view() : base() {} + + /** Construct with a specified initial value. + */ + explicit op_add_view(const Type& v) : base(v) {} + + /** Reduction operation. + * + * This function is invoked by the @ref op_add monoid to combine the views + * of two strands when the right strand merges with the left one. It adds + * the value contained in the right-strand view to the value contained in + * the left-strand view, and leaves the value in the right-strand view + * undefined. + * + * @param right A pointer to the right-strand view. (`this` points to + * the left-strand view.) + * + * @note Used only by the @ref op_add monoid to implement the monoid + * reduce operation. + */ + void reduce(op_add_view* right) { this->m_value += right->m_value; } + + /** @name Accumulator variable updates. + * + * These functions support the various syntaxes for incrementing or + * decrementing the accumulator variable contained in the view. + */ + //@{ + + /** Increment the accumulator variable by @a x. + */ + op_add_view& operator+=(const Type& x) { this->m_value += x; return *this; } + + /** Decrement the accumulator variable by @a x. + */ + op_add_view& operator-=(const Type& x) { this->m_value -= x; return *this; } + + /** Pre-increment. + */ + op_add_view& operator++() { ++this->m_value; return *this; } + + /** Post-increment. + * + * @note Conventionally, post-increment operators return the old value + * of the incremented variable. However, reducer views do not + * expose their contained values, so `view++` does not have a + * return value. + */ + void operator++(int) { this->m_value++; } + + /** Pre-decrement. + */ + op_add_view& operator--() { --this->m_value; return *this; } + + /** Post-decrement. + * + * @note Conventionally, post-decrement operators return the old value + * of the decremented variable. However, reducer views do not + * expose their contained values, so `view--` does not have a + * return value. + */ + void operator--(int) { this->m_value--; } + + /** Create an object representing `*this + x`. + * + * @see rhs_proxy + */ + rhs_proxy operator+(const Type& x) const { return rhs_proxy(this, x); } + + /** Create an object representing `*this - x`. + * + * @see rhs_proxy + */ + rhs_proxy operator-(const Type& x) const { return rhs_proxy(this, -x); } + + /** Assign the result of a `view ± value` expression to the view. Note that + * this is the only assignment operator for this class. + * + * @see rhs_proxy + */ + op_add_view& operator=(const rhs_proxy& rhs) { + __CILKRTS_ASSERT(this == rhs.m_view); + this->m_value += rhs.m_value; + return *this; + } + + //@} +}; + + +/** Monoid class for addition reductions. Instantiate the cilk::reducer + * template class with an op_add monoid to create an addition reducer class. + * For example, to compute + * the sum of a set of `int` values: + * + * cilk::reducer< cilk::op_add<int> > r; + * + * @tparam Type The reducer value type. + * @tparam Align If `false` (the default), reducers instantiated on this + * monoid will be naturally aligned (the Cilk library 1.0 + * behavior). If `true`, reducers instantiated on this monoid + * will be cache-aligned for binary compatibility with + * reducers in Cilk library version 0.9. + * + * @see ReducersAdd + * @see op_add_view + * + * @ingroup ReducersAdd + */ +template <typename Type, bool Align = false> +struct op_add : public monoid_with_view<op_add_view<Type>, Align> {}; + +/** **Deprecated** addition reducer wrapper class. + * + * reducer_opadd is the same as @ref reducer<@ref op_add>, except that + * reducer_opadd is a proxy for the contained view, so that accumulator + * variable update operations can be applied directly to the reducer. For + * example, a value is added to a `reducer<%op_add>` with `*r += a`, but a + * value can be added to a `%reducer_opadd` with `r += a`. + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_opadd. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_opadd` + * and `reducer<%op_add>`. This allows incremental code + * conversion: old code that used `%reducer_opadd` can pass a + * `%reducer_opadd` to a converted function that now expects a + * pointer or reference to a `reducer<%op_add>`, and vice + * versa. + * + * @tparam Type The value type of the reducer. + * + * @see op_add + * @see reducer + * @see ReducersAdd + * + * @ingroup ReducersAdd + */ +template <typename Type> +class reducer_opadd : public reducer< op_add<Type, true> > +{ + typedef reducer< op_add<Type, true> > base; + using base::view; + + public: + /// The view type for the reducer. + typedef typename base::view_type view_type; + + /// The view’s rhs proxy type. + typedef typename view_type::rhs_proxy rhs_proxy; + + /// The view type for the reducer. + typedef view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + /** @name Constructors + */ + //@{ + + /** Default (identity) constructor. + * + * Constructs the wrapper with the default initial value of `Type()`. + */ + reducer_opadd() {} + + /** Value constructor. + * + * Constructs the wrapper with a specified initial value. + */ + explicit reducer_opadd(const Type& initial_value) : base(initial_value) {} + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_add_view. */ + //@{ + + /// @copydoc op_add_view::operator+=(const Type&) + reducer_opadd& operator+=(const Type& x) { view() += x; return *this; } + + /// @copydoc op_add_view::operator-=(const Type&) + reducer_opadd& operator-=(const Type& x) { view() -= x; return *this; } + + /// @copydoc op_add_view::operator++() + reducer_opadd& operator++() { ++view(); return *this; } + + /// @copydoc op_add_view::operator++(int) + void operator++(int) { view()++; } + + /// @copydoc op_add_view::operator-\-() + reducer_opadd& operator--() { --view(); return *this; } + + /// @copydoc op_add_view::operator-\-(int) + void operator--(int) { view()--; } + + // The legacy definitions of reducer_opadd::operator+() and + // reducer_opadd::operator-() have different behavior and a different + // return type than this definition. The legacy version is defined as a + // member function, so this new version is defined as a free function to + // give it a different signature, so that they won’t end up sharing a + // single object file entry. + + /// @copydoc op_add_view::operator+(const Type&) const + friend rhs_proxy operator+(const reducer_opadd& r, const Type& x) + { + return r.view() + x; + } + /// @copydoc op_add_view::operator-(const Type&) const + friend rhs_proxy operator-(const reducer_opadd& r, const Type& x) + { + return r.view() - x; + } + /// @copydoc op_add_view::operator=(const rhs_proxy&) + reducer_opadd& operator=(const rhs_proxy& temp) + { + view() = temp; + return *this; + } + //@} + + /** @name Dereference + * @details Dereferencing a wrapper is a no-op. It simply returns the + * wrapper. Combined with the rule that the wrapper forwards view + * operations to its contained view, this means that view operations can + * be written the same way on reducers and wrappers, which is convenient + * for incrementally converting old code using wrappers to use reducers + * instead. That is: + * + * reducer< op_add<int> > r; + * *r += a; // *r returns the view + * // operator += is a view member function + * + * reducer_opadd<int> w; + * *w += a; // *w returns the wrapper + * // operator += is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_opadd& operator*() { return *this; } + reducer_opadd const& operator*() const { return *this; } + + reducer_opadd* operator->() { return this; } + reducer_opadd const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_add<Type, false> >& () + { + return *reinterpret_cast< reducer< op_add<Type, false> >* >(this); + } + operator const reducer< op_add<Type, false> >& () const + { + return *reinterpret_cast< const reducer< op_add<Type, false> >* >(this); + } + //@} +}; + +/// @cond internal +/** Metafunction specialization for reducer conversion. + * + * This specialization of the @ref legacy_reducer_downcast template class + * defined in reducer.h causes the `reducer< op_add<Type> >` class to have an + * `operator reducer_opadd<Type>& ()` conversion operator that statically + * downcasts the `reducer<op_add>` to the corresponding `reducer_opadd` type. + * (The reverse conversion, from `reducer_opadd` to `reducer<op_add>`, is just + * an upcast, which is provided for free by the language.) + * + * @ingroup ReducersAdd + */ +template <typename Type, bool Align> +struct legacy_reducer_downcast<reducer<op_add<Type, Align> > > +{ + typedef reducer_opadd<Type> type; +}; +/// @endcond + +} // namespace cilk + +#endif // __cplusplus + + +/** @ingroup ReducersAdd + */ +//@{ + +/** @name C Language Reducer Macros + * + * These macros are used to declare and work with numeric op_add reducers in + * C code. + * + * @see @ref page_reducers_in_c + */ + //@{ + +__CILKRTS_BEGIN_EXTERN_C + +/** Opadd reducer type name. + * + * This macro expands into the identifier which is the name of the op_add + * reducer type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * + * @see @ref reducers_c_predefined + * @see ReducersAdd + */ +#define CILK_C_REDUCER_OPADD_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_opadd_,tn) + +/** Declare an op_add reducer object. + * + * This macro expands into a declaration of an op_add reducer object for a + * specified numeric type. For example: + * + * CILK_C_REDUCER_OPADD(my_reducer, double, 0.0); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * @param v The initial value for the reducer. (A value which can be + * assigned to the numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + * @see ReducersAdd + */ +#define CILK_C_REDUCER_OPADD(obj,tn,v) \ + CILK_C_REDUCER_OPADD_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opadd_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opadd_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, v) + +/// @cond internal + +/** Declare the op_add reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which + * implement the reducer functionality for the op_add reducer type for a + * specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPADD_DECLARATION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPADD_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opadd,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opadd,tn); + +/** Define the op_add reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement + * the reducer functionality for the op_add reducer type for a specified + * numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPADD_DEFINITION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPADD_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opadd,tn,l,r) \ + { *(t*)l += *(t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opadd,tn) \ + { *(t*)v = 0; } + +//@{ +/** @def CILK_C_REDUCER_OPADD_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` + * will be defined, and this macro will generate reducer implementation + * functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` will be undefined, + * and this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_OPADD_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPADD_DEFINITION(t,tn) +#else +# define CILK_C_REDUCER_OPADD_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPADD_DECLARATION(t,tn) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for each + * numeric type. + */ +CILK_C_REDUCER_OPADD_INSTANCE(char, char) +CILK_C_REDUCER_OPADD_INSTANCE(unsigned char, uchar) +CILK_C_REDUCER_OPADD_INSTANCE(signed char, schar) +CILK_C_REDUCER_OPADD_INSTANCE(wchar_t, wchar_t) +CILK_C_REDUCER_OPADD_INSTANCE(short, short) +CILK_C_REDUCER_OPADD_INSTANCE(unsigned short, ushort) +CILK_C_REDUCER_OPADD_INSTANCE(int, int) +CILK_C_REDUCER_OPADD_INSTANCE(unsigned int, uint) +CILK_C_REDUCER_OPADD_INSTANCE(unsigned int, unsigned) /* alternate name */ +CILK_C_REDUCER_OPADD_INSTANCE(long, long) +CILK_C_REDUCER_OPADD_INSTANCE(unsigned long, ulong) +CILK_C_REDUCER_OPADD_INSTANCE(long long, longlong) +CILK_C_REDUCER_OPADD_INSTANCE(unsigned long long, ulonglong) +CILK_C_REDUCER_OPADD_INSTANCE(float, float) +CILK_C_REDUCER_OPADD_INSTANCE(double, double) +CILK_C_REDUCER_OPADD_INSTANCE(long double, longdouble) + +//@endcond + +__CILKRTS_END_EXTERN_C + +//@} + +//@} + +#endif /* REDUCER_OPADD_H_INCLUDED */ diff --git a/libcilkrts/include/cilk/reducer_opand.h b/libcilkrts/include/cilk/reducer_opand.h new file mode 100644 index 00000000000..8a086c91818 --- /dev/null +++ b/libcilkrts/include/cilk/reducer_opand.h @@ -0,0 +1,604 @@ +/* reducer_opand.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_opand.h + * + * @brief Defines classes for doing parallel bitwise and reductions. + * + * @ingroup ReducersAnd + * + * @see ReducersAnd + */ + +#ifndef REDUCER_OPAND_H_INCLUDED +#define REDUCER_OPAND_H_INCLUDED + +#include <cilk/reducer.h> + +/** @defgroup ReducersAnd Bitwise And Reducers + * + * Bitwise and reducers allow the computation of the bitwise and of a set of + * values in parallel. + * + * @ingroup Reducers + * + * You should be familiar with @ref pagereducers "Cilk reducers", described in + * file `reducers.md`, and particularly with @ref reducers_using, before trying + * to use the information in this file. + * + * @section redopand_usage Usage Example + * + * cilk::reducer< cilk::op_and<unsigned> > r; + * cilk_for (int i = 0; i != N; ++i) { + * *r &= a[i]; + * } + * unsigned result; + * r.move_out(result); + * + * @section redopand_monoid The Monoid + * + * @subsection redopand_monoid_values Value Set + * + * The value set of a bitwise and reducer is the set of values of `Type`, + * which is expected to be a builtin integer type which has a representation + * as a sequence of bits (or something like it, such as `bool` or + * `std::bitset`). + * + * @subsection redopand_monoid_operator Operator + * + * The operator of a bitwise and reducer is the bitwise and operator, defined + * by the “`&`” binary operator on `Type`. + * + * @subsection redopand_monoid_identity Identity + * + * The identity value of the reducer is the value whose representation + * contains all 1-bits. This is expected to be the value of the expression + * `~Type()` (i.e., the bitwise negation operator applied to the default value + * of the value type). + * + * @section redopand_operations Operations + * + * @subsection redopand_constructors Constructors + * + * reducer() // identity + * reducer(const Type& value) + * reducer(move_in(Type& variable)) + * + * @subsection redopand_get_set Set and Get + * + * r.set_value(const Type& value) + * const Type& = r.get_value() const + * r.move_in(Type& variable) + * r.move_out(Type& variable) + * + * @subsection redopand_initial Initial Values + * + * If a bitwise and reducer is constructed without an explicit initial value, + * then its initial value will be its identity value, as long as `Type` + * satisfies the requirements of @ref redopand_types. + * + * @subsection redopand_view_ops View Operations + * + * *r &= a + * *r = *r & a + * *r = *r & a1 & a2 … & an + * + * @section redopand_types Type and Operator Requirements + * + * `Type` must be `Copy Constructible`, `Default Constructible`, and + * `Assignable`. + * + * The operator “`&=`” must be defined on `Type`, with `x &= a` having the + * same meaning as `x = x & a`. + * + * The expression `~ Type()` must be a valid expression which yields the + * identity value (the value of `Type` whose representation consists of all + * 1-bits). + * + * @section redopand_in_c Bitwise And Reducers in C + * + * The @ref CILK_C_REDUCER_OPAND and @ref CILK_C_REDUCER_OPAND_TYPE macros can + * be used to do bitwise and reductions in C. For example: + * + * CILK_C_REDUCER_OPAND(r, uint, ~0); + * CILK_C_REGISTER_REDUCER(r); + * cilk_for(int i = 0; i != n; ++i) { + * REDUCER_VIEW(r) &= a[i]; + * } + * CILK_C_UNREGISTER_REDUCER(r); + * printf("The bitwise AND of the elements of a is %x\n", REDUCER_VIEW(r)); + * + * See @ref reducers_c_predefined. + */ + +#ifdef __cplusplus + +namespace cilk { + +/** The bitwise and reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_and<Type> >`. It holds the accumulator variable + * for the reduction, and allows only `and` operations to be performed on it. + * + * @note The reducer “dereference” operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `&=` operation would be used in an expression like `*r &= a`, where + * `r` is an opmod reducer variable. + * + * @tparam Type The type of the contained accumulator variable. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * + * @see ReducersAnd + * @see op_and + * + * @ingroup ReducersAnd + */ +template <typename Type> +class op_and_view : public scalar_view<Type> +{ + typedef scalar_view<Type> base; + +public: + /** Class to represent the right-hand side of `*reducer = *reducer & value`. + * + * The only assignment operator for the op_and_view class takes an + * rhs_proxy as its operand. This results in the syntactic restriction + * that the only expressions that can be assigned to an op_and_view are + * ones which generate an rhs_proxy — that is, expressions of the form + * `op_and_view & value ... & value`. + * + * @warning + * The lhs and rhs views in such an assignment must be the same; + * otherwise, the behavior will be undefined. (I.e., `v1 = v1 & x` is + * legal; `v1 = v2 & x` is illegal.) This condition will be checked with + * a runtime assertion when compiled in debug mode. + * + * @see op_and_view + */ + class rhs_proxy { + private: + friend class op_and_view; + + const op_and_view* m_view; + Type m_value; + + // Constructor is invoked only from op_and_view::operator&(). + // + rhs_proxy(const op_and_view* view, const Type& value) : m_view(view), m_value(value) {} + + rhs_proxy& operator=(const rhs_proxy&); // Disable assignment operator + rhs_proxy(); // Disable default constructor + + public: + /** Bitwise and with an additional rhs value. If `v` is an op_and_view + * and `a1` is a value, then the expression `v & a1` invokes the + * view’s `operator&()` to create an rhs_proxy for `(v, a1)`; then + * `v & a1 & a2` invokes the rhs_proxy’s `operator&()` to create a new + * rhs_proxy for `(v, a1&a2)`. This allows the right-hand side of an + * assignment to be not just `view & value`, but + * `view & value & value ... & value`. The effect is that + * + * v = v & a1 & a2 ... & an; + * + * is evaluated as + * + * v = v & (a1 & a2 ... & an); + */ + rhs_proxy& operator&(const Type& x) { m_value &= x; return *this; } + }; + + + /** Default/identity constructor. This constructor initializes the + * contained value to `~ Type()`. + */ + op_and_view() : base(~Type()) {} + + /** Construct with a specified initial value. + */ + explicit op_and_view(const Type& v) : base(v) {} + + + /** Reduction operation. + * + * This function is invoked by the @ref op_and monoid to combine the views + * of two strands when the right strand merges with the left one. It + * “ands” the value contained in the left-strand view with the value + * contained in the right-strand view, and leaves the value in the + * right-strand view undefined. + * + * @param right A pointer to the right-strand view. (`this` points to + * the left-strand view.) + * + * @note Used only by the @ref op_and monoid to implement the monoid + * reduce operation. + */ + void reduce(op_and_view* right) { this->m_value &= right->m_value; } + + /** @name Accumulator variable updates. + * + * These functions support the various syntaxes for “anding” the + * accumulator variable contained in the view with some value. + */ + //@{ + + /** And the accumulator variable with @a x. + */ + op_and_view& operator&=(const Type& x) { this->m_value &= x; return *this; } + + /** Create an object representing `*this & x`. + * + * @see rhs_proxy + */ + rhs_proxy operator&(const Type& x) const { return rhs_proxy(this, x); } + + /** Assign the result of a `view & value` expression to the view. Note that + * this is the only assignment operator for this class. + * + * @see rhs_proxy + */ + op_and_view& operator=(const rhs_proxy& rhs) { + __CILKRTS_ASSERT(this == rhs.m_view); + this->m_value &= rhs.m_value; + return *this; + } + + //@} +}; + +/** Monoid class for bitwise and reductions. Instantiate the cilk::reducer + * template class with an op_and monoid to create a bitwise and reducer + * class. For example, to compute the bitwise and of a set of `unsigned long` + * values: + * + * cilk::reducer< cilk::op_and<unsigned long> > r; + * + * @tparam Type The reducer value type. + * @tparam Align If `false` (the default), reducers instantiated on this + * monoid will be naturally aligned (the Cilk library 1.0 + * behavior). If `true`, reducers instantiated on this monoid + * will be cache-aligned for binary compatibility with + * reducers in Cilk library version 0.9. + * + * @see ReducersAnd + * @see op_and_view + * + * @ingroup ReducersAnd + */ +template <typename Type, bool Align = false> +struct op_and : public monoid_with_view<op_and_view<Type>, Align> {}; + +/** Deprecated bitwise and reducer class. + * + * reducer_opand is the same as @ref reducer<@ref op_and>, except that + * reducer_opand is a proxy for the contained view, so that accumulator + * variable update operations can be applied directly to the reducer. For + * example, a value is anded with a `reducer<%op_and>` with `*r &= a`, but a + * value can be anded with a `%reducer_opand` with `r &= a`. + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_opand. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_opand` + * and `reducer<%op_and>`. This allows incremental code + * conversion: old code that used `%reducer_opand` can pass a + * `%reducer_opand` to a converted function that now expects a + * pointer or reference to a `reducer<%op_and>`, and vice + * versa. + * + * @tparam Type The value type of the reducer. + * + * @see op_and + * @see reducer + * @see ReducersAnd + * + * @ingroup ReducersAnd + */ +template <typename Type> +class reducer_opand : public reducer< op_and<Type, true> > +{ + typedef reducer< op_and<Type, true> > base; + using base::view; + +public: + /// The view type for the reducer. + typedef typename base::view_type view_type; + + /// The view’s rhs proxy type. + typedef typename view_type::rhs_proxy rhs_proxy; + + /// The view type for the reducer. + typedef view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + /** @name Constructors + */ + //@{ + + /** Default constructor. + * + * Constructs the wrapper with the default initial value of `Type()` + * (not the identity value). + */ + reducer_opand() : base(Type()) {} + + /** Value constructor. + * + * Constructs the wrapper with a specified initial value. + */ + explicit reducer_opand(const Type& initial_value) : base(initial_value) {} + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_and_view. */ + //@{ + + /// @copydoc op_and_view::operator&=(const Type&) + reducer_opand& operator&=(const Type& x) + { + view() &= x; + return *this; + } + + // The legacy definition of reducer_opand::operator&() has different + // behavior and a different return type than this definition. The legacy + // version is defined as a member function, so this new version is defined + // as a free function to give it a different signature, so that they won’t + // end up sharing a single object file entry. + + /// @copydoc op_and_view::operator&(const Type&) const + friend rhs_proxy operator&(const reducer_opand& r, const Type& x) + { + return r.view() & x; + } + + /// @copydoc op_and_view::operator=(const rhs_proxy&) + reducer_opand& operator=(const rhs_proxy& temp) + { + view() = temp; + return *this; + } + //@} + + /** @name Dereference + * @details Dereferencing a wrapper is a no-op. It simply returns the + * wrapper. Combined with the rule that the wrapper forwards view + * operations to its contained view, this means that view operations can + * be written the same way on reducers and wrappers, which is convenient + * for incrementally converting old code using wrappers to use reducers + * instead. That is: + * + * reducer< op_and<int> > r; + * *r &= a; // *r returns the view + * // operator &= is a view member function + * + * reducer_opand<int> w; + * *w &= a; // *w returns the wrapper + * // operator &= is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_opand& operator*() { return *this; } + reducer_opand const& operator*() const { return *this; } + + reducer_opand* operator->() { return this; } + reducer_opand const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_and<Type, false> >& () + { + return *reinterpret_cast< reducer< op_and<Type, false> >* >(this); + } + operator const reducer< op_and<Type, false> >& () const + { + return *reinterpret_cast< const reducer< op_and<Type, false> >* >(this); + } + //@} +}; + +/// @cond internal +/** Metafunction specialization for reducer conversion. + * + * This specialization of the @ref legacy_reducer_downcast template class + * defined in reducer.h causes the `reducer< op_and<Type> >` class to have an + * `operator reducer_opand<Type>& ()` conversion operator that statically + * downcasts the `reducer<op_and>` to the corresponding `reducer_opand` type. + * (The reverse conversion, from `reducer_opand` to `reducer<op_and>`, is just + * an upcast, which is provided for free by the language.) + * + * @ingroup ReducersAnd + */ +template <typename Type, bool Align> +struct legacy_reducer_downcast<reducer<op_and<Type, Align> > > +{ + typedef reducer_opand<Type> type; +}; +/// @endcond + +} // namespace cilk + +#endif // __cplusplus + + +/** @ingroup ReducersAdd + */ +//@{ + +/** @name C language reducer macros + * + * These macros are used to declare and work with op_and reducers in C code. + * + * @see @ref page_reducers_in_c + */ + //@{ + +__CILKRTS_BEGIN_EXTERN_C + +/** Opand reducer type name. + * + * This macro expands into the identifier which is the name of the op_and + * reducer type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * + * @see @ref reducers_c_predefined + * @see ReducersAnd + */ +#define CILK_C_REDUCER_OPAND_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_opand_,tn) + +/** Declare an op_and reducer object. + * + * This macro expands into a declaration of an op_and reducer object for a + * specified numeric type. For example: + * + * CILK_C_REDUCER_OPAND(my_reducer, ulong, ~0UL); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * @param v The initial value for the reducer. (A value which can be + * assigned to the numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + * @see ReducersAnd + */ +#define CILK_C_REDUCER_OPAND(obj,tn,v) \ + CILK_C_REDUCER_OPAND_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opand_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opand_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, v) + +/// @cond internal + +/** Declare the op_and reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which + * implement the reducer functionality for the op_and reducer type for a + * specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPAND_DECLARATION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPAND_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opand,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opand,tn); + +/** Define the op_and reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement + * the reducer functionality for the op_and reducer type for a specified + * numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPAND_DEFINITION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPAND_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opand,tn,l,r) \ + { *(t*)l &= *(t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opand,tn) \ + { *(t*)v = ~((t)0); } + +//@{ +/** @def CILK_C_REDUCER_OPAND_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` + * will be defined, and this macro will generate reducer implementation + * functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` will be undefined, and + * this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_OPAND_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPAND_DEFINITION(t,tn) +#else +# define CILK_C_REDUCER_OPAND_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPAND_DECLARATION(t,tn) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for + * each numeric type. + */ +CILK_C_REDUCER_OPAND_INSTANCE(char, char) +CILK_C_REDUCER_OPAND_INSTANCE(unsigned char, uchar) +CILK_C_REDUCER_OPAND_INSTANCE(signed char, schar) +CILK_C_REDUCER_OPAND_INSTANCE(wchar_t, wchar_t) +CILK_C_REDUCER_OPAND_INSTANCE(short, short) +CILK_C_REDUCER_OPAND_INSTANCE(unsigned short, ushort) +CILK_C_REDUCER_OPAND_INSTANCE(int, int) +CILK_C_REDUCER_OPAND_INSTANCE(unsigned int, uint) +CILK_C_REDUCER_OPAND_INSTANCE(unsigned int, unsigned) /* alternate name */ +CILK_C_REDUCER_OPAND_INSTANCE(long, long) +CILK_C_REDUCER_OPAND_INSTANCE(unsigned long, ulong) +CILK_C_REDUCER_OPAND_INSTANCE(long long, longlong) +CILK_C_REDUCER_OPAND_INSTANCE(unsigned long long, ulonglong) + +//@endcond + +__CILKRTS_END_EXTERN_C + +//@} + +//@} + +#endif /* REDUCER_OPAND_H_INCLUDED */ diff --git a/libcilkrts/include/cilk/reducer_opmul.h b/libcilkrts/include/cilk/reducer_opmul.h new file mode 100644 index 00000000000..271529d787b --- /dev/null +++ b/libcilkrts/include/cilk/reducer_opmul.h @@ -0,0 +1,442 @@ +/* reducer_opmul.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2012-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_opmul.h + * + * @brief Defines classes for doing parallel multiplication reductions. + * + * @ingroup ReducersMul + * + * @see ReducersMul + */ + +#ifndef REDUCER_OPMUL_H_INCLUDED +#define REDUCER_OPMUL_H_INCLUDED + +#include <cilk/reducer.h> + +/** @defgroup ReducersMul Multiplication Reducers + * + * Multiplication reducers allow the computation of the product of a set of + * values in parallel. + * + * @ingroup Reducers + * + * You should be familiar with @ref pagereducers "Cilk reducers", described in + * file `reducers.md`, and particularly with @ref reducers_using, before trying + * to use the information in this file. + * + * @section redopmul_usage Usage Example + * + * cilk::reducer< cilk::op_mul<double> > r; + * cilk_for (int i = 0; i != N; ++i) { + * *r *= a[i]; + * } + * double product; + * r.move_out(product); + * + * @section redopmul_monoid The Monoid + * + * @subsection redopmul_monoid_values Value Set + * + * The value set of a multiplication reducer is the set of values of `Type`, + * which is expected to be a builtin numeric type (or something like it, such + * as `std::complex`). + * + * @subsection redopmul_monoid_operator Operator + * + * The operator of a multiplication reducer is the multiplication operation, + * defined by the “`*`” binary operator on `Type`. + * + * @subsection redopmul_monoid_identity Identity + * + * The identity value of the reducer is the numeric value “`1`”. This is + * expected to be the value of the expression `Type(1)`. + * + * @section redopmul_operations Operations + * + * @subsection redopmul_constructors Constructors + * + * reducer() // identity + * reducer(const Type& value) + * reducer(move_in(Type& variable)) + * + * @subsection redopmul_get_set Set and Get + * + * r.set_value(const Type& value) + * const Type& = r.get_value() const + * r.move_in(Type& variable) + * r.move_out(Type& variable) + * + * @subsection redopmul_initial Initial Values + * + * If a multiplication reducer is constructed without an explicit initial + * value, then its initial value will be its identity value, as long as `Type` + * satisfies the requirements of @ref redopmul_types. + * + * @subsection redopmul_view_ops View Operations + * + * *r *= a + * *r = *r * a + * *r = *r * a1 * a2 … * an + * + * @section redopmul_floating_point Issues with Floating-Point Types + * + * Because of overflow and underflow issues, floating-point multiplication is + * not really associative. For example, `(1e200 * 1e-200) * 1e-200 == 1e-200`, + * but `1e200 * (1e-200 * 1e-200 == 0. + * + * In many cases, this won’t matter, but computations which have been + * carefully ordered to control overflow and underflow may not deal well with + * being reassociated. In general, you should be sure to understand the + * floating-point behavior of your program before doing any transformation + * that will reassociate its computations. + * + * @section redopmul_types Type and Operator Requirements + * + * `Type` must be `Copy Constructible`, `Default Constructible`, and + * `Assignable`. + * + * The operator “`*=`” must be defined on `Type`, with `x *= a` having the same + * meaning as `x = x * a`. + * + * The expression `Type(1)` must be a valid expression which yields the + * identity value (the value of `Type` whose numeric value is `1`). + * + * @section redopmul_in_c Multiplication Reducers in C + * + * The @ref CILK_C_REDUCER_OPMUL and @ref CILK_C_REDUCER_OPMUL_TYPE macros can + * be used to do multiplication reductions in C. For example: + * + * CILK_C_REDUCER_OPMUL(r, double, 1); + * CILK_C_REGISTER_REDUCER(r); + * cilk_for(int i = 0; i != n; ++i) { + * REDUCER_VIEW(r) *= a[i]; + * } + * CILK_C_UNREGISTER_REDUCER(r); + * printf("The product of the elements of a is %f\n", REDUCER_VIEW(r)); + * + * See @ref reducers_c_predefined. + */ + +#ifdef __cplusplus + +namespace cilk { + +/** The multiplication reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_mul<Type> >`. It holds the accumulator variable + * for the reduction, and allows only multiplication operations to be + * performed on it. + * + * @note The reducer “dereference” operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `*=` operation would be used in an expression like `*r *= a`, where + * `r` is an op_mul reducer variable. + * + * @tparam Type The type of the contained accumulator variable. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * + * @see ReducersMul + * @see op_mul + * + * @ingroup ReducersMul + */ +template <typename Type> +class op_mul_view : public scalar_view<Type> +{ + typedef scalar_view<Type> base; + +public: + /** Class to represent the right-hand side of `*reducer = *reducer * value`. + * + * The only assignment operator for the op_mul_view class takes an + * rhs_proxy as its operand. This results in the syntactic restriction + * that the only expressions that can be assigned to an op_mul_view are + * ones which generate an rhs_proxy — that is, expressions of the form + * `op_mul_view * value ... * value`. + * + * @warning + * The lhs and rhs views in such an assignment must be the same; + * otherwise, the behavior will be undefined. (I.e., `v1 = v1 * x` is + * legal; `v1 = v2 * x` is illegal.) This condition will be checked with a + * runtime assertion when compiled in debug mode. + * + * @see op_mul_view + */ + class rhs_proxy { + friend class op_mul_view; + + const op_mul_view* m_view; + Type m_value; + + // Constructor is invoked only from op_mul_view::operator*(). + // + rhs_proxy(const op_mul_view* view, const Type& value) : m_view(view), m_value(value) {} + + rhs_proxy& operator=(const rhs_proxy&); // Disable assignment operator + rhs_proxy(); // Disable default constructor + + public: + /** Multiply by an additional rhs value. If `v` is an op_mul_view and + * `a1` is a value, then the expression `v * a1` invokes the view’s + * `operator*()` to create an rhs_proxy for `(v, a1)`; then + * `v * a1 * a2` invokes the rhs_proxy’s `operator*()` to create a + * new rhs_proxy for `(v, a1*a2)`. This allows the right-hand side of + * an assignment to be not just `view * value`, but + * `view * value * value ... * value`. The effect is that + * + * v = v * a1 * a2 ... * an; + * + * is evaluated as + * + * v = v * (a1 * a2 ... * an); + */ + rhs_proxy& operator*(const Type& x) { m_value *= x; return *this; } + }; + + + /** Default/identity constructor. This constructor initializes the + * contained value to `Type(1)`, which is expected to be the identity + * value for multiplication on `Type`. + */ + op_mul_view() : base(Type(1)) {} + + /** Construct with a specified initial value. + */ + explicit op_mul_view(const Type& v) : base(v) {} + + /** Reduction operation. + * + * This function is invoked by the @ref op_mul monoid to combine the views + * of two strands when the right strand merges with the left one. It + * multiplies the value contained in the left-strand view by the value + * contained in the right-strand view, and leaves the value in the + * right-strand view undefined. + * + * @param right A pointer to the right-strand view. (`this` points to + * the left-strand view.) + * + * @note Used only by the @ref op_mul monoid to implement the monoid + * reduce operation. + */ + void reduce(op_mul_view* right) { this->m_value *= right->m_value; } + + /** @name Accumulator variable updates. + * + * These functions support the various syntaxes for multiplying the + * accumulator variable contained in the view by some value. + */ + //@{ + + /** Multiply the accumulator variable by @a x. + */ + op_mul_view& operator*=(const Type& x) { this->m_value *= x; return *this; } + + /** Create an object representing `*this * x`. + * + * @see rhs_proxy + */ + rhs_proxy operator*(const Type& x) const { return rhs_proxy(this, x); } + + /** Assign the result of a `view * value` expression to the view. Note that + * this is the only assignment operator for this class. + * + * @see rhs_proxy + */ + op_mul_view& operator=(const rhs_proxy& rhs) { + __CILKRTS_ASSERT(this == rhs.m_view); + this->m_value *= rhs.m_value; + return *this; + } + + //@} +}; + +/** Monoid class for multiplication reductions. Instantiate the cilk::reducer + * template class with an op_mul monoid to create a multiplication reducer + * class. For example, to compute the product of a set of `double` values: + * + * cilk::reducer< cilk::op_mul<double> > r; + * + * @see ReducersMul + * @see op_mul_view + * + * @ingroup ReducersMul + */ +template <typename Type> +struct op_mul : public monoid_with_view< op_mul_view<Type> > {}; + +} // namespace cilk + +#endif // __cplusplus + + +/** @ingroup ReducersAdd + */ +//@{ + +/** @name C language reducer macros + * + * These macros are used to declare and work with numeric op_mul reducers in + * C code. + * + * @see @ref page_reducers_in_c + */ + //@{ + +__CILKRTS_BEGIN_EXTERN_C + +/** Opmul reducer type name. + * + * This macro expands into the identifier which is the name of the op_mul + * reducer type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * + * @see @ref reducers_c_predefined + * @see ReducersMul + */ +#define CILK_C_REDUCER_OPMUL_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_opmul_,tn) + +/** Declare an op_mul reducer object. + * + * This macro expands into a declaration of an op_mul reducer object for a + * specified numeric type. For example: + * + * CILK_C_REDUCER_OPMUL(my_reducer, double, 1.0); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * @param v The initial value for the reducer. (A value which can be + * assigned to the numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + * @see ReducersMul + */ +#define CILK_C_REDUCER_OPMUL(obj,tn,v) \ + CILK_C_REDUCER_OPMUL_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opmul_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opmul_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, v) + +/// @cond internal + +/** Declare the op_mul reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which + * implement the reducer functionality for the op_mul reducer type for a + * specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPMUL_DECLARATION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPMUL_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opmul,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opmul,tn); + +/** Define the op_mul reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement + * the reducer functionality for the op_mul reducer type for a specified + * numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPMUL_DEFINITION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPMUL_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opmul,tn,l,r) \ + { *(t*)l *= *(t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opmul,tn) \ + { *(t*)v = 1; } + +//@{ +/** @def CILK_C_REDUCER_OPMUL_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` + * will be defined, and this macro will generate reducer implementation + * functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` will be undefined, and + * this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_OPMUL_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPMUL_DEFINITION(t,tn) +#else +# define CILK_C_REDUCER_OPMUL_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPMUL_DECLARATION(t,tn) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for each + * numeric type. + */ +CILK_C_REDUCER_OPMUL_INSTANCE(char, char) +CILK_C_REDUCER_OPMUL_INSTANCE(unsigned char, uchar) +CILK_C_REDUCER_OPMUL_INSTANCE(signed char, schar) +CILK_C_REDUCER_OPMUL_INSTANCE(wchar_t, wchar_t) +CILK_C_REDUCER_OPMUL_INSTANCE(short, short) +CILK_C_REDUCER_OPMUL_INSTANCE(unsigned short, ushort) +CILK_C_REDUCER_OPMUL_INSTANCE(int, int) +CILK_C_REDUCER_OPMUL_INSTANCE(unsigned int, uint) +CILK_C_REDUCER_OPMUL_INSTANCE(unsigned int, unsigned) /* alternate name */ +CILK_C_REDUCER_OPMUL_INSTANCE(long, long) +CILK_C_REDUCER_OPMUL_INSTANCE(unsigned long, ulong) +CILK_C_REDUCER_OPMUL_INSTANCE(long long, longlong) +CILK_C_REDUCER_OPMUL_INSTANCE(unsigned long long, ulonglong) +CILK_C_REDUCER_OPMUL_INSTANCE(float, float) +CILK_C_REDUCER_OPMUL_INSTANCE(double, double) +CILK_C_REDUCER_OPMUL_INSTANCE(long double, longdouble) + +//@endcond + +__CILKRTS_END_EXTERN_C + +//@} + +//@} + +#endif /* REDUCER_OPMUL_H_INCLUDED */ diff --git a/libcilkrts/include/cilk/reducer_opor.h b/libcilkrts/include/cilk/reducer_opor.h new file mode 100644 index 00000000000..5c8e7bd972e --- /dev/null +++ b/libcilkrts/include/cilk/reducer_opor.h @@ -0,0 +1,598 @@ +/* reducer_opor.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_opor.h + * + * @brief Defines classes for doing parallel bitwise or reductions. + * + * @ingroup ReducersOr + * + * @see ReducersOr + */ + +#ifndef REDUCER_OPOR_H_INCLUDED +#define REDUCER_OPOR_H_INCLUDED + +#include <cilk/reducer.h> + +/** @defgroup ReducersOr Bitwise Or Reducers + * + * Bitwise and reducers allow the computation of the bitwise and of a set of + * values in parallel. + * + * @ingroup Reducers + * + * You should be familiar with @ref pagereducers "Cilk reducers", described in + * file `reducers.md`, and particularly with @ref reducers_using, before trying + * to use the information in this file. + * + * @section redopor_usage Usage Example + * + * cilk::reducer< cilk::op_or<unsigned> > r; + * cilk_for (int i = 0; i != N; ++i) { + * *r |= a[i]; + * } + * unsigned result; + * r.move_out(result); + * + * @section redopor_monoid The Monoid + * + * @subsection redopor_monoid_values Value Set + * + * The value set of a bitwise or reducer is the set of values of `Type`, which + * is expected to be a builtin integer type which has a representation as a + * sequence of bits (or something like it, such as `bool` or `std::bitset`). + * + * @subsection redopor_monoid_operator Operator + * + * The operator of a bitwise or reducer is the bitwise or operator, defined by + * the “`|`” binary operator on `Type`. + * + * @subsection redopor_monoid_identity Identity + * + * The identity value of the reducer is the value whose representation + * contains all 0-bits. This is expected to be the value of the default + * constructor `Type()`. + * + * @section redopor_operations Operations + * + * @subsection redopor_constructors Constructors + * + * reducer() // identity + * reducer(const Type& value) + * reducer(move_in(Type& variable)) + * + * @subsection redopor_get_set Set and Get + * + * r.set_value(const Type& value) + * const Type& = r.get_value() const + * r.move_in(Type& variable) + * r.move_out(Type& variable) + * + * @subsection redopor_initial Initial Values + * + * If a bitwise or reducer is constructed without an explicit initial value, + * then its initial value will be its identity value, as long as `Type` + * satisfies the requirements of @ref redopor_types. + * + * @subsection redopor_view_ops View Operations + * + * *r |= a + * *r = *r | a + * *r = *r | a1 | a2 … | an + * + * @section redopor_types Type and Operator Requirements + * + * `Type` must be `Copy Constructible`, `Default Constructible`, and + * `Assignable`. + * + * The operator “`|=`” must be defined on `Type`, with `x |= a` having the + * same meaning as `x = x | a`. + * + * The expression `Type()` must be a valid expression which yields the + * identity value (the value of `Type` whose representation consists of all + * 0-bits). + * + * @section redopor_in_c Bitwise Or Reducers in C + * + * The @ref CILK_C_REDUCER_OPOR and @ref CILK_C_REDUCER_OPOR_TYPE macros can + * be used to do bitwise or reductions in C. For example: + * + * CILK_C_REDUCER_OPOR(r, uint, 0); + * CILK_C_REGISTER_REDUCER(r); + * cilk_for(int i = 0; i != n; ++i) { + * REDUCER_VIEW(r) |= a[i]; + * } + * CILK_C_UNREGISTER_REDUCER(r); + * printf("The bitwise OR of the elements of a is %x\n", REDUCER_VIEW(r)); + * + * See @ref reducers_c_predefined. + */ + +#ifdef __cplusplus + +namespace cilk { + +/** The bitwise or reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_or<Type> >`. It holds the accumulator variable for + * the reduction, and allows only `or` operations to be performed on it. + * + * @note The reducer “dereference” operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `|=` operation would be used in an expression like `*r |= a`, where + * `r` is an opmod reducer variable. + * + * @tparam Type The type of the contained accumulator variable. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * + * @see ReducersOr + * @see op_or + * + * @ingroup ReducersOr + */ +template <typename Type> +class op_or_view : public scalar_view<Type> +{ + typedef scalar_view<Type> base; + +public: + /** Class to represent the right-hand side of `*reducer = *reducer | value`. + * + * The only assignment operator for the op_or_view class takes an + * rhs_proxy as its operand. This results in the syntactic restriction + * that the only expressions that can be assigned to an op_or_view are + * ones which generate an rhs_proxy — that is, expressions of the form + * `op_or_view | value ... | value`. + * + * @warning + * The lhs and rhs views in such an assignment must be the same; + * otherwise, the behavior will be undefined. (I.e., `v1 = v1 | x` is + * legal; `v1 = v2 | x` is illegal.) This condition will be checked with + * a runtime assertion when compiled in debug mode. + * + * @see op_or_view + */ + class rhs_proxy { + friend class op_or_view; + + const op_or_view* m_view; + Type m_value; + + // Constructor is invoked only from op_or_view::operator|(). + // + rhs_proxy(const op_or_view* view, const Type& value) : m_view(view), m_value(value) {} + + rhs_proxy& operator=(const rhs_proxy&); // Disable assignment operator + rhs_proxy(); // Disable default constructor + + public: + /** Bitwise or with an additional rhs value. If `v` is an op_or_view + * and `a1` is a value, then the expression `v | a1` invokes the + * view’s `operator|()` to create an rhs_proxy for `(v, a1)`; then + * `v | a1 | a2` invokes the rhs_proxy’s `operator|()` to create a new + * rhs_proxy for `(v, a1|a2)`. This allows the right-hand side of an + * assignment to be not just `view | value`, but + ( `view | value | value ... | value`. The effect is that + * + * v = v | a1 | a2 ... | an; + * + * is evaluated as + * + * v = v | (a1 | a2 ... | an); + */ + rhs_proxy& operator|(const Type& x) { m_value |= x; return *this; } + }; + + + /** Default/identity constructor. This constructor initializes the + * contained value to `Type()`. + */ + op_or_view() : base() {} + + /** Construct with a specified initial value. + */ + explicit op_or_view(const Type& v) : base(v) {} + + /** Reduction operation. + * + * This function is invoked by the @ref op_or monoid to combine the views + * of two strands when the right strand merges with the left one. It + * “ors” the value contained in the left-strand view by the value + * contained in the right-strand view, and leaves the value in the + * right-strand view undefined. + * + * @param right A pointer to the right-strand view. (`this` points to + * the left-strand view.) + * + * @note Used only by the @ref op_or monoid to implement the monoid + * reduce operation. + */ + void reduce(op_or_view* right) { this->m_value |= right->m_value; } + + /** @name Accumulator variable updates. + * + * These functions support the various syntaxes for “oring” the + * accumulator variable contained in the view with some value. + */ + //@{ + + /** Or the accumulator variable with @a x. + */ + op_or_view& operator|=(const Type& x) { this->m_value |= x; return *this; } + + /** Create an object representing `*this | x`. + * + * @see rhs_proxy + */ + rhs_proxy operator|(const Type& x) const { return rhs_proxy(this, x); } + + /** Assign the result of a `view | value` expression to the view. Note that + * this is the only assignment operator for this class. + * + * @see rhs_proxy + */ + op_or_view& operator=(const rhs_proxy& rhs) { + __CILKRTS_ASSERT(this == rhs.m_view); + this->m_value |= rhs.m_value; + return *this; + } + + //@} +}; + +/** Monoid class for bitwise or reductions. Instantiate the cilk::reducer + * template class with an op_or monoid to create a bitwise or reducer + * class. For example, to compute the bitwise or of a set of `unsigned long` + * values: + * + * cilk::reducer< cilk::op_or<unsigned long> > r; + * + * @tparam Type The reducer value type. + * @tparam Align If `false` (the default), reducers instantiated on this + * monoid will be naturally aligned (the Cilk library 1.0 + * behavior). If `true`, reducers instantiated on this monoid + * will be cache-aligned for binary compatibility with + * reducers in Cilk library version 0.9. + * + * @see ReducersOr + * @see op_or_view + * + * @ingroup ReducersOr + */ +template <typename Type, bool Align = false> +struct op_or : public monoid_with_view<op_or_view<Type>, Align> {}; + +/** Deprecated bitwise or reducer class. + * + * reducer_opor is the same as @ref reducer<@ref op_or>, except that + * reducer_opor is a proxy for the contained view, so that accumulator + * variable update operations can be applied directly to the reducer. For + * example, a value is ored with a `reducer<%op_or>` with `*r |= a`, but a + * value can be ored with a `%reducer_opor` with `r |= a`. + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_opor. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_opor` + * and `reducer<%op_or>`. This allows incremental code + * conversion: old code that used `%reducer_opor` can pass a + * `%reducer_opor` to a converted function that now expects a + * pointer or reference to a `reducer<%op_or>`, and vice + * versa. + * + * @tparam Type The value type of the reducer. + * + * @see op_or + * @see reducer + * @see ReducersOr + * + * @ingroup ReducersOr + */ +template <typename Type> +class reducer_opor : public reducer< op_or<Type, true> > +{ + typedef reducer< op_or<Type, true> > base; + using base::view; + + public: + /// The view type for the reducer. + typedef typename base::view_type view_type; + + /// The view’s rhs proxy type. + typedef typename view_type::rhs_proxy rhs_proxy; + + /// The view type for the reducer. + typedef view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + /** @name Constructors + */ + //@{ + + /** Default (identity) constructor. + * + * Constructs the wrapper with the default initial value of `Type()`. + */ + reducer_opor() {} + + /** Value constructor. + * + * Constructs the wrapper with a specified initial value. + */ + explicit reducer_opor(const Type& initial_value) : base(initial_value) {} + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_and_view. */ + //@{ + + /// @copydoc op_or_view::operator|=(const Type&) + reducer_opor& operator|=(const Type& x) + { + view() |= x; return *this; + } + + // The legacy definition of reducer_opor::operator|() has different + // behavior and a different return type than this definition. The legacy + // version is defined as a member function, so this new version is defined + // as a free function to give it a different signature, so that they won’t + // end up sharing a single object file entry. + + /// @copydoc op_or_view::operator|(const Type&) const + friend rhs_proxy operator|(const reducer_opor& r, const Type& x) + { + return r.view() | x; + } + + /// @copydoc op_and_view::operator=(const rhs_proxy&) + reducer_opor& operator=(const rhs_proxy& temp) + { + view() = temp; return *this; + } + //@} + + /** @name Dereference + * @details Dereferencing a wrapper is a no-op. It simply returns the + * wrapper. Combined with the rule that the wrapper forwards view + * operations to its contained view, this means that view operations can + * be written the same way on reducers and wrappers, which is convenient + * for incrementally converting old code using wrappers to use reducers + * instead. That is: + * + * reducer< op_and<int> > r; + * *r &= a; // *r returns the view + * // operator &= is a view member function + * + * reducer_opand<int> w; + * *w &= a; // *w returns the wrapper + * // operator &= is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_opor& operator*() { return *this; } + reducer_opor const& operator*() const { return *this; } + + reducer_opor* operator->() { return this; } + reducer_opor const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_or<Type, false> >& () + { + return *reinterpret_cast< reducer< op_or<Type, false> >* >(this); + } + operator const reducer< op_or<Type, false> >& () const + { + return *reinterpret_cast< const reducer< op_or<Type, false> >* >(this); + } + //@} + +}; + +/// @cond internal +/** Metafunction specialization for reducer conversion. + * + * This specialization of the @ref legacy_reducer_downcast template class + * defined in reducer.h causes the `reducer< op_or<Type> >` class to have an + * `operator reducer_opor<Type>& ()` conversion operator that statically + * downcasts the `reducer<op_or>` to the corresponding `reducer_opor` type. + * (The reverse conversion, from `reducer_opor` to `reducer<op_or>`, is just + * an upcast, which is provided for free by the language.) + * + * @ingroup ReducersOr + */ +template <typename Type, bool Align> +struct legacy_reducer_downcast<reducer<op_or<Type, Align> > > +{ + typedef reducer_opor<Type> type; +}; +/// @endcond + +} // namespace cilk + +#endif /* __cplusplus */ + + +/** @ingroup ReducersOr + */ +//@{ + +/** @name C language reducer macros + * + * These macros are used to declare and work with op_or reducers in C code. + * + * @see @ref page_reducers_in_c + */ + //@{ + +__CILKRTS_BEGIN_EXTERN_C + +/** Opor reducer type name. + * + * This macro expands into the identifier which is the name of the op_or + * reducer type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * + * @see @ref reducers_c_predefined + * @see ReducersOr + */ +#define CILK_C_REDUCER_OPOR_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_opor_,tn) + +/** Declare an op_or reducer object. + * + * This macro expands into a declaration of an op_or reducer object for a + * specified numeric type. For example: + * + * CILK_C_REDUCER_OPOR(my_reducer, ulong, 0); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * @param v The initial value for the reducer. (A value which can be + * assigned to the numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + * @see ReducersOr + */ +#define CILK_C_REDUCER_OPOR(obj,tn,v) \ + CILK_C_REDUCER_OPOR_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opor_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opor_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, v) + +/// @cond internal + +/** Declare the op_or reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which + * implement the reducer functionality for the op_or reducer type for a + * specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPOR_DECLARATION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPOR_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opor,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opor,tn); + +/** Define the op_or reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement + * the reducer functionality for the op_or reducer type for a specified + * numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPOR_DEFINITION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPOR_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opor,tn,l,r) \ + { *(t*)l |= *(t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opor,tn) \ + { *(t*)v = 0; } + +//@{ +/** @def CILK_C_REDUCER_OPOR_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` + * will be defined, and this macro will generate reducer implementation + * functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` will be undefined, and + * this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_OPOR_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPOR_DEFINITION(t,tn) +#else +# define CILK_C_REDUCER_OPOR_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPOR_DECLARATION(t,tn) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for each + * numeric type. + */ +CILK_C_REDUCER_OPOR_INSTANCE(char, char) +CILK_C_REDUCER_OPOR_INSTANCE(unsigned char, uchar) +CILK_C_REDUCER_OPOR_INSTANCE(signed char, schar) +CILK_C_REDUCER_OPOR_INSTANCE(wchar_t, wchar_t) +CILK_C_REDUCER_OPOR_INSTANCE(short, short) +CILK_C_REDUCER_OPOR_INSTANCE(unsigned short, ushort) +CILK_C_REDUCER_OPOR_INSTANCE(int, int) +CILK_C_REDUCER_OPOR_INSTANCE(unsigned int, uint) +CILK_C_REDUCER_OPOR_INSTANCE(unsigned int, unsigned) /* alternate name */ +CILK_C_REDUCER_OPOR_INSTANCE(long, long) +CILK_C_REDUCER_OPOR_INSTANCE(unsigned long, ulong) +CILK_C_REDUCER_OPOR_INSTANCE(long long, longlong) +CILK_C_REDUCER_OPOR_INSTANCE(unsigned long long, ulonglong) + +//@endcond + +__CILKRTS_END_EXTERN_C + +//@} + +//@} + +#endif /* REDUCER_OPOR_H_INCLUDED */ diff --git a/libcilkrts/include/cilk/reducer_opxor.h b/libcilkrts/include/cilk/reducer_opxor.h new file mode 100644 index 00000000000..fed49943ef6 --- /dev/null +++ b/libcilkrts/include/cilk/reducer_opxor.h @@ -0,0 +1,598 @@ +/* reducer_opxor.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_opxor.h + * + * @brief Defines classes for doing parallel bitwise or reductions. + * + * @ingroup ReducersXor + * + * @see ReducersXor + */ + +#ifndef REDUCER_OPXOR_H_INCLUDED +#define REDUCER_OPXOR_H_INCLUDED + +#include <cilk/reducer.h> + +/** @defgroup ReducersXor Bitwise Xor Reducers + * + * Bitwise and reducers allow the computation of the bitwise and of a set of + * values in parallel. + * + * @ingroup Reducers + * + * You should be familiar with @ref pagereducers "Cilk reducers", described in + * file `reducers.md`, and particularly with @ref reducers_using, before trying + * to use the information in this file. + * + * @section redopxor_usage Usage Example + * + * cilk::reducer< cilk::op_xor<unsigned> > r; + * cilk_for (int i = 0; i != N; ++i) { + * *r ^= a[i]; + * } + * unsigned result; + * r.move_out(result); + * + * @section redopxor_monoid The Monoid + * + * @subsection redopxor_monoid_values Value Set + * + * The value set of a bitwise xor reducer is the set of values of `Type`, which + * is expected to be a builtin integer type which has a representation as a + * sequence of bits (or something like it, such as `bool` or `std::bitset`). + * + * @subsection redopxor_monoid_operator Operator + * + * The operator of a bitwise xor reducer is the bitwise xor operator, defined + * by the “`^`” binary operator on `Type`. + * + * @subsection redopxor_monoid_identity Identity + * + * The identity value of the reducer is the value whose representation + * contains all 0-bits. This is expected to be the value of the default + * constructor `Type()`. + * + * @section redopxor_operations Operations + * + * @subsection redopxor_constructors Constructors + * + * reducer() // identity + * reducer(const Type& value) + * reducer(move_in(Type& variable)) + * + * @subsection redopxor_get_set Set and Get + * + * r.set_value(const Type& value) + * const Type& = r.get_value() const + * r.move_in(Type& variable) + * r.move_out(Type& variable) + * + * @subsection redopxor_initial Initial Values + * + * If a bitwise xor reducer is constructed without an explicit initial value, + * then its initial value will be its identity value, as long as `Type` + * satisfies the requirements of @ref redopxor_types. + * + * @subsection redopxor_view_ops View Operations + * + * *r ^= a + * *r = *r ^ a + * *r = *r ^ a1 ^ a2 … ^ an + * + * @section redopxor_types Type and Operator Requirements + * + * `Type` must be `Copy Constructible`, `Default Constructible`, and + * `Assignable`. + * + * The operator “`^=`” must be defined on `Type`, with `x ^= a` having the + * same meaning as `x = x ^ a`. + * + * The expression `Type()` must be a valid expression which yields the + * identity value (the value of `Type` whose representation consists of all + * 0-bits). + * + * @section redopxor_in_c Bitwise Xor Reducers in C + * + * The @ref CILK_C_REDUCER_OPXOR and @ref CILK_C_REDUCER_OPXOR_TYPE macros can + * be used to do bitwise xor reductions in C. For example: + * + * CILK_C_REDUCER_OPXOR(r, uint, 0); + * CILK_C_REGISTER_REDUCER(r); + * cilk_for(int i = 0; i != n; ++i) { + * REDUCER_VIEW(r) ^= a[i]; + * } + * CILK_C_UNREGISTER_REDUCER(r); + * printf("The bitwise XOR of the elements of a is %x\n", REDUCER_VIEW(r)); + * + * See @ref reducers_c_predefined. + */ + +#ifdef __cplusplus + +namespace cilk { + +/** The bitwise xor reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_xor<Type> >`. It holds the accumulator variable + * for the reduction, and allows only `xor` operations to be performed on it. + * + * @note The reducer “dereference” operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `^=` operation would be used in an expression like `*r ^= a`, where + * `r` is an opmod reducer variable. + * + * @tparam Type The type of the contained accumulator variable. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * + * @see ReducersXor + * @see op_xor + * + * @ingroup ReducersXor + */ +template <typename Type> +class op_xor_view : public scalar_view<Type> +{ + typedef scalar_view<Type> base; + +public: + /** Class to represent the right-hand side of `*reducer = *reducer ^ value`. + * + * The only assignment operator for the op_xor_view class takes an + * rhs_proxy as its operand. This results in the syntactic restriction + * that the only expressions that can be assigned to an op_xor_view are + * ones which generate an rhs_proxy — that is, expressions of the form + * `op_xor_view ^ value ... ^ value`. + * + * @warning + * The lhs and rhs views in such an assignment must be the same; + * otherwise, the behavior will be undefined. (I.e., `v1 = v1 ^ x` is + * legal; `v1 = v2 ^ x` is illegal.) This condition will be checked with + * a runtime assertion when compiled in debug mode. + * + * @see op_xor_view + */ + class rhs_proxy { + friend class op_xor_view; + + const op_xor_view* m_view; + Type m_value; + + // Constructor is invoked only from op_xor_view::operator^(). + // + rhs_proxy(const op_xor_view* view, const Type& value) : m_view(view), m_value(value) {} + + rhs_proxy& operator=(const rhs_proxy&); // Disable assignment operator + rhs_proxy(); // Disable default constructor + + public: + /** Bitwise xor with an additional rhs value. If `v` is an op_xor_view + * and `a1` is a value, then the expression `v ^ a1` invokes the + * view’s `operator^()` to create an rhs_proxy for `(v, a1)`; then + * `v ^ a1 ^ a2` invokes the rhs_proxy’s `operator^()` to create a new + * rhs_proxy for `(v, a1^a2)`. This allows the right-hand side of an + * assignment to be not just `view ^ value`, but + ( `view ^ value ^ value ... ^ value`. The effect is that + * + * v = v ^ a1 ^ a2 ... ^ an; + * + * is evaluated as + * + * v = v ^ (a1 ^ a2 ... ^ an); + */ + rhs_proxy& operator^(const Type& x) { m_value ^= x; return *this; } + }; + + + /** Default/identity constructor. This constructor initializes the + * contained value to `Type()`. + */ + op_xor_view() : base() {} + + /** Construct with a specified initial value. + */ + explicit op_xor_view(const Type& v) : base(v) {} + + /** Reduction operation. + * + * This function is invoked by the @ref op_xor monoid to combine the views + * of two strands when the right strand merges with the left one. It + * “xors” the value contained in the left-strand view by the value + * contained in the right-strand view, and leaves the value in the + * right-strand view undefined. + * + * @param right A pointer to the right-strand view. (`this` points to + * the left-strand view.) + * + * @note Used only by the @ref op_xor monoid to implement the monoid + * reduce operation. + */ + void reduce(op_xor_view* right) { this->m_value ^= right->m_value; } + + /** @name Accumulator variable updates. + * + * These functions support the various syntaxes for “xoring” the + * accumulator variable contained in the view with some value. + */ + //@{ + + /** Xor the accumulator variable with @a x. + */ + op_xor_view& operator^=(const Type& x) { this->m_value ^= x; return *this; } + + /** Create an object representing `*this ^ x`. + * + * @see rhs_proxy + */ + rhs_proxy operator^(const Type& x) const { return rhs_proxy(this, x); } + + /** Assign the result of a `view ^ value` expression to the view. Note that + * this is the only assignment operator for this class. + * + * @see rhs_proxy + */ + op_xor_view& operator=(const rhs_proxy& rhs) { + __CILKRTS_ASSERT(this == rhs.m_view); + this->m_value ^= rhs.m_value; + return *this; + } + + //@} +}; + +/** Monoid class for bitwise xor reductions. Instantiate the cilk::reducer + * template class with an op_xor monoid to create a bitwise xor reducer + * class. For example, to compute the bitwise xor of a set of `unsigned long` + * values: + * + * cilk::reducer< cilk::op_xor<unsigned long> > r; + * + * @tparam Type The reducer value type. + * @tparam Align If `false` (the default), reducers instantiated on this + * monoid will be naturally aligned (the Cilk library 1.0 + * behavior). If `true`, reducers instantiated on this monoid + * will be cache-aligned for binary compatibility with + * reducers in Cilk library version 0.9. + * + * @see ReducersXor + * @see op_xor_view + * + * @ingroup ReducersXor + */ +template <typename Type, bool Align = false> +struct op_xor : public monoid_with_view<op_xor_view<Type>, Align> {}; + +/** Deprecated bitwise xor reducer class. + * + * reducer_opxor is the same as @ref reducer<@ref op_xor>, except that + * reducer_opxor is a proxy for the contained view, so that accumulator + * variable update operations can be applied directly to the reducer. For + * example, a value is xored with a `reducer<%op_xor>` with `*r ^= a`, but a + * value can be xored with a `%reducer_opxor` with `r ^= a`. + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_opand. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_opxor` + * and `reducer<%op_xor>`. This allows incremental code + * conversion: old code that used `%reducer_opxor` can pass a + * `%reducer_opxor` to a converted function that now expects a + * pointer or reference to a `reducer<%op_xor>`, and vice + * versa. + * + * @tparam Type The value type of the reducer. + * + * @see op_xor + * @see reducer + * @see ReducersXor + * + * @ingroup ReducersXor + */ +template <typename Type> +class reducer_opxor : public reducer< op_xor<Type, true> > +{ + typedef reducer< op_xor<Type, true> > base; + using base::view; + + public: + /// The view type for the reducer. + typedef typename base::view_type view_type; + + /// The view’s rhs proxy type. + typedef typename view_type::rhs_proxy rhs_proxy; + + /// The view type for the reducer. + typedef view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + /** @name Constructors + */ + //@{ + + /** Default (identity) constructor. + * + * Constructs the wrapper with the default initial value of `Type()`. + */ + reducer_opxor() {} + + /** Value constructor. + * + * Constructs the wrapper with a specified initial value. + */ + explicit reducer_opxor(const Type& initial_value) : base(initial_value) {} + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_and_view. */ + //@{ + + /// @copydoc op_xor_view::operator^=(const Type&) + reducer_opxor& operator^=(const Type& x) + { + view() ^= x; return *this; + } + + // The legacy definition of reducer_opxor::operator^() has different + // behavior and a different return type than this definition. The legacy + // version is defined as a member function, so this new version is defined + // as a free function to give it a different signature, so that they won’t + // end up sharing a single object file entry. + + /// @copydoc op_xor_view::operator^(const Type&) const + friend rhs_proxy operator^(const reducer_opxor& r, const Type& x) + { + return r.view() ^ x; + } + + /// @copydoc op_and_view::operator=(const rhs_proxy&) + reducer_opxor& operator=(const rhs_proxy& temp) + { + view() = temp; return *this; + } + //@} + + /** @name Dereference + * @details Dereferencing a wrapper is a no-op. It simply returns the + * wrapper. Combined with the rule that the wrapper forwards view + * operations to its contained view, this means that view operations can + * be written the same way on reducers and wrappers, which is convenient + * for incrementally converting old code using wrappers to use reducers + * instead. That is: + * + * reducer< op_and<int> > r; + * *r &= a; // *r returns the view + * // operator &= is a view member function + * + * reducer_opand<int> w; + * *w &= a; // *w returns the wrapper + * // operator &= is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_opxor& operator*() { return *this; } + reducer_opxor const& operator*() const { return *this; } + + reducer_opxor* operator->() { return this; } + reducer_opxor const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_xor<Type, false> >& () + { + return *reinterpret_cast< reducer< op_xor<Type, false> >* >(this); + } + operator const reducer< op_xor<Type, false> >& () const + { + return *reinterpret_cast< const reducer< op_xor<Type, false> >* >(this); + } + //@} + +}; + +/// @cond internal +/** Metafunction specialization for reducer conversion. + * + * This specialization of the @ref legacy_reducer_downcast template class + * defined in reducer.h causes the `reducer< op_xor<Type> >` class to have an + * `operator reducer_opxor<Type>& ()` conversion operator that statically + * downcasts the `reducer<op_xor>` to the corresponding `reducer_opxor` type. + * (The reverse conversion, from `reducer_opxor` to `reducer<op_xor>`, is just + * an upcast, which is provided for free by the language.) + * + * @ingroup ReducersXor + */ +template <typename Type, bool Align> +struct legacy_reducer_downcast<reducer<op_xor<Type, Align> > > +{ + typedef reducer_opxor<Type> type; +}; +/// @endcond + +} // namespace cilk + +#endif /* __cplusplus */ + + +/** @ingroup ReducersXor + */ +//@{ + +/** @name C language reducer macros + * + * These macros are used to declare and work with op_xor reducers in C code. + * + * @see @ref page_reducers_in_c + */ + //@{ + +__CILKRTS_BEGIN_EXTERN_C + +/** Opxor reducer type name. + * + * This macro expands into the identifier which is the name of the op_xor + * reducer type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * + * @see @ref reducers_c_predefined + * @see ReducersXor + */ +#define CILK_C_REDUCER_OPXOR_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_opxor_,tn) + +/** Declare an op_xor reducer object. + * + * This macro expands into a declaration of an op_xor reducer object for a + * specified numeric type. For example: + * + * CILK_C_REDUCER_OPXOR(my_reducer, ulong, 0); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * @param v The initial value for the reducer. (A value which can be + * assigned to the numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + * @see ReducersXor + */ +#define CILK_C_REDUCER_OPXOR(obj,tn,v) \ + CILK_C_REDUCER_OPXOR_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opxor_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opxor_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, v) + +/// @cond internal + +/** Declare the op_xor reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which + * implement the reducer functionality for the op_xor reducer type for a + * specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPXOR_DECLARATION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPXOR_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opxor,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opxor,tn); + +/** Define the op_xor reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement + * the reducer functionality for the op_xor reducer type for a specified + * numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name” identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPXOR_DEFINITION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPXOR_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opxor,tn,l,r) \ + { *(t*)l ^= *(t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opxor,tn) \ + { *(t*)v = 0; } + +//@{ +/** @def CILK_C_REDUCER_OPXOR_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` + * will be defined, and this macro will generate reducer implementation + * functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` will be undefined, and + * this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_OPXOR_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPXOR_DEFINITION(t,tn) +#else +# define CILK_C_REDUCER_OPXOR_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPXOR_DECLARATION(t,tn) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for each + * numeric type. + */ +CILK_C_REDUCER_OPXOR_INSTANCE(char, char) +CILK_C_REDUCER_OPXOR_INSTANCE(unsigned char, uchar) +CILK_C_REDUCER_OPXOR_INSTANCE(signed char, schar) +CILK_C_REDUCER_OPXOR_INSTANCE(wchar_t, wchar_t) +CILK_C_REDUCER_OPXOR_INSTANCE(short, short) +CILK_C_REDUCER_OPXOR_INSTANCE(unsigned short, ushort) +CILK_C_REDUCER_OPXOR_INSTANCE(int, int) +CILK_C_REDUCER_OPXOR_INSTANCE(unsigned int, uint) +CILK_C_REDUCER_OPXOR_INSTANCE(unsigned int, unsigned) /* alternate name */ +CILK_C_REDUCER_OPXOR_INSTANCE(long, long) +CILK_C_REDUCER_OPXOR_INSTANCE(unsigned long, ulong) +CILK_C_REDUCER_OPXOR_INSTANCE(long long, longlong) +CILK_C_REDUCER_OPXOR_INSTANCE(unsigned long long, ulonglong) + +//@endcond + +__CILKRTS_END_EXTERN_C + +//@} + +//@} + +#endif /* REDUCER_OPXOR_H_INCLUDED */ diff --git a/libcilkrts/include/cilk/reducer_ostream.h b/libcilkrts/include/cilk/reducer_ostream.h new file mode 100644 index 00000000000..d9addeee89f --- /dev/null +++ b/libcilkrts/include/cilk/reducer_ostream.h @@ -0,0 +1,293 @@ +/* + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * reducer_ostream.h + * + * Purpose: Hyper-object to write to 'std::ostream's + * + * Classes: reducer_ostream + * + * Description: + * ============ + * Output streams ('std::ostream's) are a convenient means of writing text to + * files, the user console, or sockets. In a serial program, text is written + * to an ostream in a specific, logical order. For example, computing while + * traversing a data structure and printing them to an 'ostream' will result + * in the values being printed in the order of traversal. In a parallel + * version of the same program, however, different parts of the data structure + * may be traversed in a different order, resulting in a non-deterministic + * ordering of the stream. Worse, multiple strands may write to the same + * stream simultaneously, resulting in a data race. Replacing the + * 'std::ostream' with a 'cilk::reducer_ostream' will solve both problems: Data + * will appeaer in the stream in the same order as it would for the serial + * program, and there will be no races (no locks) on the common stream. + * + * Usage Example: + * ============== + * Assume we wish to traverse an array of objects, performing an operation on + * each object and writing the result to a file. Without a reducer_ostream, + * we have a race on the 'output' file stream: + *.. + * void compute(std::ostream& os, double x) + * { + * // Perform some significant computation and print the result: + * os << std::asin(x); + * } + * + * int test() + * { + * const std::size_t ARRAY_SIZE = 1000000; + * extern double myArray[ARRAY_SIZE]; + * + * std::ofstream output("output.txt"); + * cilk_for (std::size_t i = 0; i < ARRAY_SIZE; ++i) + * { + * compute(output, myArray[i]); + * } + * + * return 0; + * } + *.. + * The race is solved by using a reducer_ostream to proxy the 'output' file: + *.. + * void compute(cilk::reducer_ostream& os, double x) + * { + * // Perform some significant computation and print the result: + * *os << std::asin(x); + * } + * + * int test() + * { + * const std::size_t ARRAY_SIZE = 1000000; + * extern double myArray[ARRAY_SIZE]; + * + * std::ofstream output("output.txt"); + * cilk::reducer_ostream hyper_output(output); + * cilk_for (std::size_t i = 0; i < ARRAY_SIZE; ++i) + * { + * compute(hyper_output, myArray[i]); + * } + * + * return 0; + * } + *.. + * + * Limitations: + * ============ + * There are two possible values for the formatting flags immediately after a + * 'cilk_spawn' statement: they may either have the value that was set by the + * spawn function, or they may have default values. Because of + * non-determinism in the processor scheduling, there is no way to determine + * which it will be. Similarly, the formatting flags after a 'cilk_sync' may + * or may not have the same value as before the sync. Therefore, one must use + * a disciplined coding style to avoid formatting errors. There are two + * approaches to mitigating the problem: The first is to eliminate the + * difference between the two possible outcomes by ensuring that the spawned + * function always returns the flags to their initial state: + *.. + * void compute(cilk::reducer_ostream& os, double x) + * { + * // Perform some significant computation and print the result: + * int saveprec = os.precision(5); + * os << std::asin(x); + * os.precision(saveprec); + * } + *.. + * The second approach is to write your streaming operations such that they + * don't depend on the previous state of the formatting flags by setting any + * important flags before every block of output: + *.. + * cilk_spawn compute(hyper_output, value); + * + * hyper_output->precision(2); // Don't depend on previous precision + * *hyper_output << f(); + * *hyper_output << g(); + *.. + * Another concern is memory usage. A reducer_ostream will buffer as much text + * as necessary to ensure that the order of output matches that of the serial + * version of the program. If all spawn branches perform an equal amount of + * output, then one can expect that half of the output before a sync will be + * buffered in memory. This hyperobject is therefore not well suited for + * serializing very large quantities of text output. + */ + +#ifndef REDUCER_OSTREAM_H_INCLUDED +#define REDUCER_OSTREAM_H_INCLUDED + +#include <cilk/reducer.h> +#include <iostream> +#include <sstream> + +namespace cilk { + +/** + * @brief Class 'reducer_ostream' is the representation of a hyperobject for + * output text streaming. + */ +class reducer_ostream +{ +public: + /// Internal representation of the per-strand view of the data for reducer_ostream + class View: public std::ostream + { + public: + /// Type of the std::stream reducer_ostream is based on + typedef std::ostream Base; + + friend class reducer_ostream; + + View(): + std::ostream(0) + { + Base::rdbuf(&strbuf_); + }; + + private: + void use_ostream (const std::ostream &os) + { + Base::rdbuf(os.rdbuf()); + Base::flags(os.flags()); // Copy formatting flags + Base::setstate(os.rdstate()); // Copy error state + } + + private: + std::stringbuf strbuf_; + }; + +public: + /// Definition of data view, operation, and identity for reducer_ostream + struct Monoid: monoid_base< View > + { + static void reduce (View *left, View *right); + }; + +private: + // Hyperobject to serve up views + reducer<Monoid> imp_; + + // Methods that provide the API for the reducer +public: + + // Construct an initial 'reducer_ostream' from an 'std::ostream'. The + // specified 'os' stream is used as the eventual destination for all + // text streamed to this hyperobject. + explicit reducer_ostream(const std::ostream &os); + + // Return a modifiable reference to the underlying 'ostream' object. + std::ostream& get_reference(); + + /** + * Append data from some type to the reducer_ostream + * + * @param v Value to be appended to the reducer_ostream + */ + template<typename T> + std::ostream & + operator<< (const T &v) + { + return imp_.view() << v; + } + + /** + * Append data from a std::ostream to the reducer_ostream + * + * @param _Pfn std::ostream to copy from + */ + std::ostream & + operator<< (std::ostream &(*_Pfn)(std::ostream &)) + { + View &v = imp_.view(); + + return ((*_Pfn)(v)); + } + + reducer_ostream& operator*() { return *this; } + reducer_ostream const& operator*() const { return *this; } + + reducer_ostream* operator->() { return this; } + reducer_ostream const* operator->() const { return this; } +}; + + +// ------------------------------------------- +// class reducer_ostream::Monoid +// ------------------------------------------- + +/** + * Appends string from "right" reducer_basic_string onto the end of + * the "left". When done, the "right" reducer_basic_string is empty. + */ +void +reducer_ostream::Monoid::reduce(View *left, View *right) +{ + left->operator<< (&right->strbuf_); +} + +// -------------------------- +// class reducer_ostream +// -------------------------- + +/** + * Construct a reducer_ostream which will write to the specified std::ostream + * + * @param os std::ostream to write to + */ +inline +reducer_ostream::reducer_ostream(const std::ostream &os) : + imp_() +{ + View &v = imp_.view(); + + v.use_ostream(os); +} + +/** + * Get a reference to the std::ostream + */ +inline +std::ostream & +reducer_ostream::get_reference() +{ + View &v = imp_.view(); + + return v; +} + +} // namespace cilk + +#endif // REDUCER_OSTREAM_H_INCLUDED + diff --git a/libcilkrts/include/cilk/reducer_string.h b/libcilkrts/include/cilk/reducer_string.h new file mode 100644 index 00000000000..0d70dd8b30a --- /dev/null +++ b/libcilkrts/include/cilk/reducer_string.h @@ -0,0 +1,729 @@ +/* reducer_string.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_string.h + * + * @brief Defines classes for doing parallel string creation by appending. + * + * @ingroup ReducersString + * + * @see ReducersString + */ + +#ifndef REDUCER_STRING_H_INCLUDED +#define REDUCER_STRING_H_INCLUDED + +#include <cilk/reducer.h> +#include <string> +#include <list> + +/** @defgroup ReducersString String Reducers + * + * String reducers allow the creation of a string by concatenating a set of + * strings or characters in parallel. + * + * @ingroup Reducers + * + * You should be familiar with @ref pagereducers "Cilk reducers", described in + * file reducers.md, and particularly with @ref reducers_using, before trying + * to use the information in this file. + * + * @section redstring_usage Usage Example + * + * vector<Data> data; + * void expensive_string_computation(const Data& x, string& s); + * cilk::reducer<cilk::op_string> r; + * cilk_for (int i = 0; i != data.size(); ++i) { + * string temp; + * expensive_string_computation(data[i], temp); + * *r += temp; + * } + * string result; + * r.move_out(result); + * + * @section redstring_monoid The Monoid + * + * @subsection redstring_monoid_values Value Set + * + * The value set of a string reducer is the set of values of the class + * `std::basic_string<Char, Traits, Alloc>`, which we refer to as “the + * reducer’s string type”. + * + * @subsection redstring_monoid_operator Operator + * + * The operator of a string reducer is the string concatenation operator, + * defined by the “`+`” binary operator on the reducer’s string type. + * + * @subsection redstring_monoid_identity Identity + * + * The identity value of a string reducer is the empty string, which is the + * value of the expression + * `std::basic_string<Char, Traits, Alloc>([allocator])`. + * + * @section redstring_operations Operations + * + * In the operation descriptions below, the type name `String` refers to the + * reducer’s string type, `std::basic_string<Char, Traits, Alloc>`. + * + * @subsection redstring_constructors Constructors + * + * Any argument list which is valid for a `std::basic_string` constructor is + * valid for a string reducer constructor. The usual move-in constructor is + * also provided: + * + * reducer(move_in(String& variable)) + * + * @subsection redstring_get_set Set and Get + * + * r.set_value(const String& value) + * const String& = r.get_value() const + * r.move_in(String& variable) + * r.move_out(String& variable) + * + * @subsection redstring_initial Initial Values + * + * A string reducer with no constructor arguments, or with only an allocator + * argument, will initially contain the identity value, an empty string. + * + * @subsection redstring_view_ops View Operations + * + * *r += a + * r->append(a) + * r->append(a, b) + * r->push_back(a) + * + * These operations on string reducer views are the same as the corresponding + * operations on strings. + * + * @section redstring_performance Performance Considerations + * + * String reducers work by creating a string for each view, collecting those + * strings in a list, and then concatenating them into a single result string + * at the end of the computation. This last step takes place in serial code, + * and necessarily takes time proportional to the length of the result string. + * Thus, a parallel string reducer cannot actually speed up the time spent + * directly creating the string. This trivial example would probably be slower + * (because of reducer overhead) than the corresponding serial code: + * + * vector<string> a; + * reducer<op_string> r; + * cilk_for (int i = 0; i != a.length(); ++i) { + * *r += a[i]; + * } + * string result; + * r.move_out(result); + * + * What a string reducer _can_ do is to allow the _remainder_ of the + * computation to be done in parallel, without having to worry about managing + * the string computation. + * + * The strings for new views are created (by the view identity constructor) + * using the same allocator as the string that was created when the reducer + * was constructed. Note that this allocator is determined when the reducer is + * constructed. The following two examples may have very different behavior: + * + * string<Char, Traits, Allocator> a_string; + * + * reducer< op_string<Char, Traits, Allocator> reducer1(move_in(a_string)); + * ... parallel computation ... + * reducer1.move_out(a_string); + * + * reducer< op_string<Char, Traits, Allocator> reducer2; + * reducer2.move_in(a_string); + * ... parallel computation ... + * reducer2.move_out(a_string); + * + * * `reducer1` will be constructed with the same allocator as `a_string`, + * because the string was specified in the constructor. The `move_in` + * and `move_out` can therefore be done with a `swap` in constant time. + * * `reducer2` will be constructed with a _default_ allocator of type + * `Allocator`, which may not be the same as the allocator of `a_string`. + * Therefore, the `move_in` and `move_out` may have to be done with a copy + * in _O(N)_ time. + * + * (All instances of an allocator type with no internal state (like + * `std::allocator`) are “the same”. You only need to worry about the “same + * allocator” issue when you create string reducers with custom allocator + * types.) + * + * @section redstring_types Type and Operator Requirements + * + * `std::basic_string<Char, Traits, Alloc>` must be a valid type. +*/ + +namespace cilk { + +/** @ingroup ReducersString */ +//@{ + +/** The string append reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_basic_string<Type, Traits, Allocator> >`. It holds + * the accumulator variable for the reduction, and allows only append + * operations to be performed on it. + * + * @note The reducer “dereference” operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `append` operation would be used in an expression like + * `r->append(a)`, where `r` is a string append reducer variable. + * + * @tparam Char The string element type (not the string type). + * @tparam Traits The character traits type. + * @tparam Alloc The string allocator type. + * + * @see ReducersString + * @see op_basic_string + */ +template<typename Char, typename Traits, typename Alloc> +class op_basic_string_view +{ + typedef std::basic_string<Char, Traits, Alloc> string_type; + typedef std::list<string_type> list_type; + typedef typename string_type::size_type size_type; + + // The view's value is represented by a list of strings and a single + // string. The value is the concatenation of the strings in the list with + // the single string at the end. All string operations apply to the single + // string; reduce operations cause lists of partial strings from multiple + // strands to be combined. + // + mutable string_type m_string; + mutable list_type m_list; + + // Before returning the value of the reducer, concatenate all the strings + // in the list with the single string. + // + void flatten() const + { + if (m_list.empty()) return; + + typename list_type::iterator i; + + size_type len = m_string.size(); + for (i = m_list.begin(); i != m_list.end(); ++i) + len += i->size(); + + string_type result(get_allocator()); + result.reserve(len); + + for (i = m_list.begin(); i != m_list.end(); ++i) + result += *i; + m_list.clear(); + + result += m_string; + result.swap(m_string); + } + +public: + + /** @name Monoid support. + */ + //@{ + + /// Required by @ref monoid_with_view + typedef string_type value_type; + + /// Required by @ref op_string + Alloc get_allocator() const + { + return m_string.get_allocator(); + } + + /** Reduction operation. + * + * This function is invoked by the @ref op_basic_string monoid to combine + * the views of two strands when the right strand merges with the left + * one. It appends the value contained in the right-strand view to the + * value contained in the left-strand view, and leaves the value in the + * right-strand view undefined. + * + * @param right A pointer to the right-strand view. (`this` points to + * the left-strand view.) + * + * @note Used only by the @ref op_basic_string monoid to implement the + * monoid reduce operation. + */ + void reduce(op_basic_string_view* right) + { + if (!right->m_string.empty() || !right->m_list.empty()) { + // (list, string) + (right_list, right_string) => + // (list + {string} + right_list, right_string) + if (!m_string.empty()) { + // simulate m_list.push_back(std::move(m_string)) + m_list.push_back(string_type(get_allocator())); + m_list.back().swap(m_string); + } + m_list.splice(m_list.end(), right->m_list); + m_string.swap(right->m_string); + } + } + + //@} + + /** @name Pass constructor arguments through to the string constructor. + */ + //@{ + + op_basic_string_view() : m_string() {} + + template <typename T1> + op_basic_string_view(const T1& x1) : m_string(x1) {} + + template <typename T1, typename T2> + op_basic_string_view(const T1& x1, const T2& x2) : m_string(x1, x2) {} + + template <typename T1, typename T2, typename T3> + op_basic_string_view(const T1& x1, const T2& x2, const T3& x3) : m_string(x1, x2, x3) {} + + template <typename T1, typename T2, typename T3, typename T4> + op_basic_string_view(const T1& x1, const T2& x2, const T3& x3, const T4& x4) : + m_string(x1, x2, x3, x4) {} + + //@} + + /** Move-in constructor. + */ + explicit op_basic_string_view(move_in_wrapper<value_type> w) + : m_string(w.value().get_allocator()) + { + m_string.swap(w.value()); + } + + /** @name @ref reducer support. + */ + //@{ + + void view_move_in(string_type& s) + { + m_list.clear(); + if (m_string.get_allocator() == s.get_allocator()) + // Equal allocators. Do a (fast) swap. + m_string.swap(s); + else + // Unequal allocators. Do a (slow) copy. + m_string = s; + s.clear(); + } + + void view_move_out(string_type& s) + { + flatten(); + if (m_string.get_allocator() == s.get_allocator()) + // Equal allocators. Do a (fast) swap. + m_string.swap(s); + else + // Unequal allocators. Do a (slow) copy. + s = m_string; + m_string.clear(); + } + + void view_set_value(const string_type& s) + { m_list.clear(); m_string = s; } + + string_type const& view_get_value() const + { flatten(); return m_string; } + + string_type & view_get_reference() + { flatten(); return m_string; } + + string_type const& view_get_reference() const + { flatten(); return m_string; } + + //@} + + /** @name View modifier operations. + * + * @details These simply wrap the corresponding operations on the underlying string. + */ + //@{ + + template <typename T> + op_basic_string_view& operator +=(const T& x) + { m_string += x; return *this; } + + template <typename T1> + op_basic_string_view& append(const T1& x1) + { m_string.append(x1); return *this; } + + template <typename T1, typename T2> + op_basic_string_view& append(const T1& x1, const T2& x2) + { m_string.append(x1, x2); return *this; } + + template <typename T1, typename T2, typename T3> + op_basic_string_view& append(const T1& x1, const T2& x2, const T3& x3) + { m_string.append(x1, x2, x3); return *this; } + + void push_back(const Char x) { m_string.push_back(x); } + + //@} +}; + + +/** String append monoid class. Instantiate the cilk::reducer template class + * with an op_basic_string monoid to create a string append reducer class. For + * example, to concatenate a collection of standard strings: + * + * cilk::reducer< cilk::op_basic_string<char> > r; + * + * @tparam Char The string element type (not the string type). + * @tparam Traits The character traits type. + * @tparam Alloc The string allocator type. + * @tparam Align If `false` (the default), reducers instantiated on this + * monoid will be naturally aligned (the Cilk library 1.0 + * behavior). If `true`, reducers instantiated on this monoid + * will be cache-aligned for binary compatibility with + * reducers in Cilk library version 0.9. + * + * @see ReducersString + * @see op_basic_string_view + * @see reducer_basic_string + * @see op_string + * @see op_wstring + */ +template<typename Char, + typename Traits = std::char_traits<Char>, + typename Alloc = std::allocator<Char>, + bool Align = false> +class op_basic_string : + public monoid_with_view< op_basic_string_view<Char, Traits, Alloc>, Align > +{ + typedef monoid_with_view< op_basic_string_view<Char, Traits, Alloc>, Align > + base; + Alloc m_allocator; + +public: + + /** View type of the monoid. + */ + typedef typename base::view_type view_type; + + /** Constructor. + * + * There is no default constructor for string monoids, because the + * allocator must always be specified. + * + * @param allocator The list allocator to be used when + * identity-constructing new views. + */ + op_basic_string(const Alloc& allocator = Alloc()) : m_allocator(allocator) + {} + + /** Create an identity view. + * + * String view identity constructors take the string allocator as an + * argument. + * + * @param v The address of the uninitialized memory in which the view + * will be constructed. + */ + void identity(view_type *v) const { ::new((void*) v) view_type(m_allocator); } + + /** @name Construct functions + * + * A string append reduction monoid must have a copy of the allocator of + * the leftmost view’s string, so that it can use it in the `identity` + * operation. This, in turn, requires that string reduction monoids have a + * specialized `construct()` function. + * + * All string reducer monoid `construct()` functions first construct the + * leftmost view, using the arguments that were passed in from the reducer + * constructor. They then call the view’s `get_allocator()` function to + * get the string allocator from the string in the leftmost view, and pass + * that to the monoid constructor. + */ + //@{ + + static void construct(op_basic_string* monoid, view_type* view) + { provisional( new ((void*)view) view_type() ).confirm_if( + new ((void*)monoid) op_basic_string(view->get_allocator()) ); } + + template <typename T1> + static void construct(op_basic_string* monoid, view_type* view, const T1& x1) + { provisional( new ((void*)view) view_type(x1) ).confirm_if( + new ((void*)monoid) op_basic_string(view->get_allocator()) ); } + + template <typename T1, typename T2> + static void construct(op_basic_string* monoid, view_type* view, const T1& x1, const T2& x2) + { provisional( new ((void*)view) view_type(x1, x2) ).confirm_if( + new ((void*)monoid) op_basic_string(view->get_allocator()) ); } + + template <typename T1, typename T2, typename T3> + static void construct(op_basic_string* monoid, view_type* view, const T1& x1, const T2& x2, + const T3& x3) + { provisional( new ((void*)view) view_type(x1, x2, x3) ).confirm_if( + new ((void*)monoid) op_basic_string(view->get_allocator()) ); } + + template <typename T1, typename T2, typename T3, typename T4> + static void construct(op_basic_string* monoid, view_type* view, const T1& x1, const T2& x2, + const T3& x3, const T4& x4) + { provisional( new ((void*)view) view_type(x1, x2, x3, x4) ).confirm_if( + new ((void*)monoid) op_basic_string(view->get_allocator()) ); } + + //@} +}; + + +/** Convenience typedef for 8-bit strings + */ +typedef op_basic_string<char> op_string; + +/** Convenience typedef for 16-bit strings + */ +typedef op_basic_string<wchar_t> op_wstring; + + +/** Deprecated string append reducer class. + * + * reducer_basic_string is the same as @ref reducer<@ref op_basic_string>, + * except that reducer_basic_string is a proxy for the contained view, so that + * accumulator variable update operations can be applied directly to the + * reducer. For example, a value is appended to a `reducer<%op_basic_string>` + * with `r->push_back(a)`, but a value can be appended to a `%reducer_opand` + * with `r.push_back(a)`. + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_basic_string. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_basic_string` + * and `reducer<%op_basic_string>`. This allows incremental code + * conversion: old code that used `%reducer_basic_string` can pass a + * `%reducer_basic_string` to a converted function that now expects a + * pointer or reference to a `reducer<%op_basic_string>`, and vice + * versa. + * + * @tparam Char The string element type (not the string type). + * @tparam Traits The character traits type. + * @tparam Alloc The string allocator type. + * + * @see op_basic_string + * @see reducer + * @see ReducersString + */ +template<typename Char, + typename Traits = std::char_traits<Char>, + typename Alloc = std::allocator<Char> > +class reducer_basic_string : + public reducer< op_basic_string<Char, Traits, Alloc, true> > +{ + typedef reducer< op_basic_string<Char, Traits, Alloc, true> > base; + using base::view; +public: + + /// The reducer’s string type. + typedef typename base::value_type string_type; + + /// The reducer’s primitive component type. + typedef Char basic_value_type; + + /// The string size type. + typedef typename string_type::size_type size_type; + + /// The view type for the reducer. + typedef typename base::view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + + /** @name Constructors + */ + //@{ + + /** @name Forward constructor calls to the base class. + * + * All basic_string constructor forms are supported. + */ + //@{ + reducer_basic_string() {} + + template <typename T1> + reducer_basic_string(const T1& x1) : + base(x1) {} + + template <typename T1, typename T2> + reducer_basic_string(const T1& x1, const T2& x2) : + base(x1, x2) {} + + template <typename T1, typename T2, typename T3> + reducer_basic_string(const T1& x1, const T2& x2, const T3& x3) : + base(x1, x2, x3) {} + + template <typename T1, typename T2, typename T3, typename T4> + reducer_basic_string(const T1& x1, const T2& x2, const T3& x3, const T4& x4) : + base(x1, x2, x3, x4) {} + //@} + + /** Allow mutable access to the string within the current view. + * + * @warning If this method is called before the parallel calculation is + * complete, the string returned by this method will be a + * partial result. + * + * @returns A mutable reference to the string within the current view. + */ + string_type &get_reference() + { return view().view_get_reference(); } + + /** Allow read-only access to the string within the current view. + * + * @warning If this method is called before the parallel calculation is + * complete, the string returned by this method will be a + * partial result. + * + * @returns A const reference to the string within the current view. + */ + string_type const &get_reference() const + { return view().view_get_reference(); } + + /** @name Append to the string. + * + * These operations are simply forwarded to the view. + */ + //@{ + void append(const Char *ptr) + { view().append(ptr); } + void append(const Char *ptr, size_type count) + { view().append(ptr, count); } + void append(const string_type &str, size_type offset, size_type count) + { view().append(str, offset, count); } + void append(const string_type &str) + { view().append(str); } + void append(size_type count, Char ch) + { view().append(count, ch); } + + // Append to the string + reducer_basic_string<Char, Traits, Alloc> &operator+=(Char ch) + { view() += ch; return *this; } + reducer_basic_string<Char, Traits, Alloc> &operator+=(const Char *ptr) + { view() += ptr; return *this; } + reducer_basic_string<Char, Traits, Alloc> &operator+=(const string_type &right) + { view() += right; return *this; } + //@} + + /** @name Dereference + * @details Dereferencing a wrapper is a no-op. It simply returns the + * wrapper. Combined with the rule that the wrapper forwards view + * operations to its contained view, this means that view operations can + * be written the same way on reducers and wrappers, which is convenient + * for incrementally converting old code using wrappers to use reducers + * instead. That is: + * + * reducer<op_string> r; + * r->push_back(a); // r-> returns the view + * // push_back() is a view member function + * + * reducer_string w; + * w->push_back(a); // *w returns the wrapper + * // push_back() is a wrapper member function + * // that calls the corresponding view function + */ + //@{ + reducer_basic_string& operator*() { return *this; } + reducer_basic_string const& operator*() const { return *this; } + + reducer_basic_string* operator->() { return this; } + reducer_basic_string const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_basic_string<Char, Traits, Alloc, false> >& () + { + return *reinterpret_cast< reducer< + op_basic_string<Char, Traits, Alloc, false> >* + >(this); + } + operator const reducer< op_basic_string<Char, Traits, Alloc, false> >& () const + { + return *reinterpret_cast< const reducer< + op_basic_string<Char, Traits, Alloc, false> >* + >(this); + } + //@} +}; + + +/** Convenience typedef for 8-bit strings + */ +typedef reducer_basic_string<char> reducer_string; + +/** Convenience typedef for 16-bit strings + */ +typedef reducer_basic_string<wchar_t> reducer_wstring; + +/// @cond internal + +/// @cond internal +/** Metafunction specialization for reducer conversion. + * + * This specialization of the @ref legacy_reducer_downcast template class + * defined in reducer.h causes the `reducer< op_basic_string<Char> >` class to + * have an `operator reducer_basic_string<Char>& ()` conversion operator that + * statically downcasts the `reducer<op_basic_string>` to the corresponding + * `reducer_basic_string` type. (The reverse conversion, from + * `reducer_basic_string` to `reducer<op_basic_string>`, is just an upcast, + * which is provided for free by the language.) + * + * @ingroup ReducersString + */ +template<typename Char, typename Traits, typename Alloc, bool Align> +struct legacy_reducer_downcast< + reducer<op_basic_string<Char, Traits, Alloc, Align> > > +{ + typedef reducer_basic_string<Char, Traits, Alloc> type; +}; + +/// @endcond + +//@} + +} // namespace cilk + +#endif // REDUCER_STRING_H_INCLUDED diff --git a/libcilkrts/include/cilktools/cilkscreen.h b/libcilkrts/include/cilktools/cilkscreen.h new file mode 100644 index 00000000000..c6986ae7b08 --- /dev/null +++ b/libcilkrts/include/cilktools/cilkscreen.h @@ -0,0 +1,108 @@ +/* cilkscreen.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2010-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +#ifndef INCLUDED_CILKSCREEN_H +#define INCLUDED_CILKSCREEN_H + +#include <cilk/cilk_api.h> + +/* + * Cilkscreen "functions". These macros generate metadata in your application + * to notify Cilkscreen of program state changes + */ + +#if ! defined(CILK_STUB) && defined(__INTEL_COMPILER) +# define __cilkscreen_metacall(annotation,expr) \ + __notify_zc_intrinsic((char *)annotation, expr) +#else +# define __cilkscreen_metacall(annotation,expr) ((void)annotation, (void)(expr)) +#endif + +/* Call once when a user thread enters a spawning function */ +#define __cilkscreen_enable_instrumentation() \ + __cilkscreen_metacall("cilkscreen_enable_instrumentation", 0) + +/* Call once when a user thread exits a spawning function */ +#define __cilkscreen_disable_instrumentation() \ + __cilkscreen_metacall("cilkscreen_disable_instrumentation", 0) + +/* Call to temporarily disable cilkscreen instrumentation */ +#define __cilkscreen_enable_checking() \ + __cilkscreen_metacall("cilkscreen_enable_checking", 0) + +/* Call to re-enable temporarily-disabled cilkscreen instrumentation */ +#define __cilkscreen_disable_checking() \ + __cilkscreen_metacall("cilkscreen_disable_checking", 0) + +/* Inform cilkscreen that memory from begin to end can be reused without + * causing races (e.g., for memory that comes from a memory allocator) */ +#define __cilkscreen_clean(begin, end) \ + do { \ + void *__data[2] = { (begin), (end) }; \ + __cilkscreen_metacall("cilkscreen_clean", &__data); \ + } while(0) + +/* Inform cilkscreen that a lock is being acquired. + * If the lock type is not a handle, then the caller should take its address + * and pass the pointer to the lock. Otherwise, the caller should pass the + * lock handle directly. + */ +#define __cilkscreen_acquire_lock(lock) \ + __cilkscreen_metacall("cilkscreen_acquire_lock", (lock)) + +#define __cilkscreen_release_lock(lock) \ + __cilkscreen_metacall("cilkscreen_release_lock", (lock)) + +/* + * Metacall data + * + * A metacall is a way to pass data to a function implemented by a tool. + * Metacalls are always instrumented when the tool is loaded. + */ + +// Tool code for Cilkscreen +#define METACALL_TOOL_CILKSCREEN 1 + +// Metacall codes implemented by Cilkscreen +#define CS_METACALL_PUTS 0 // Write string to the Cilkscreen log + +#define __cilkscreen_puts(text) \ + __cilkrts_metacall(METACALL_TOOL_CILKSCREEN, CS_METACALL_PUTS, (void *)(const char *)text) + +#endif /* defined(INCLUDED_CILKSCREEN_H) */ diff --git a/libcilkrts/include/cilktools/cilkview.h b/libcilkrts/include/cilktools/cilkview.h new file mode 100644 index 00000000000..eb7d9d8c0e4 --- /dev/null +++ b/libcilkrts/include/cilktools/cilkview.h @@ -0,0 +1,278 @@ +/* cilkview.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2010-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +#ifndef INCLUDED_CILKVIEW_H +#define INCLUDED_CILKVIEW_H + +#include <cilk/cilk_api.h> + +#ifdef _WIN32 +# ifndef _WINBASE_ +__CILKRTS_BEGIN_EXTERN_C +unsigned long __stdcall GetTickCount(); +__CILKRTS_END_EXTERN_C +# endif +#endif // _WIN32 + +#if defined __unix__ || defined __APPLE__ || defined __VXWORKS__ +# include <sys/time.h> +#endif // defined __unix__ || defined __APPLE__ + +/// @brief Return the system clock with millisecond resolution +/// +/// This function returns a long integer representing the number of +/// milliseconds since an arbitrary starting point, e.g., since the system was +/// started or since the Unix Epoch. The result is meaningless by itself, but +/// the difference between two sequential calls to __cilkview_getticks() +/// represents the time interval that elapsed between them (in ms). +static inline unsigned long long __cilkview_getticks() +{ +#if __INTEL_COMPILER > 1200 + // When inlined, prevent code motion around this call + __notify_zc_intrinsic((void*) "test_getticks_start", 0); +#endif + +#ifdef _WIN32 + // Return milliseconds elapsed since the system started + return GetTickCount(); +#elif defined(__unix__) || defined(__APPLE__) || defined __VXWORKS__ + // Return milliseconds elapsed since the Unix Epoch + // (1-Jan-1970 00:00:00.000 UTC) + struct timeval t; + gettimeofday(&t, 0); + return t.tv_sec * 1000ULL + t.tv_usec / 1000; +#else +# error test_getticks() not implemented for this OS +#endif + +#if __INTEL_COMPILER > 1200 + // When inlined, prevent code motion around this call + __notify_zc_intrinsic((void*) "test_getticks_end", 0); +#endif +} + +typedef struct +{ + unsigned int size; // Size of structure in bytes + unsigned int status; // 1 = success, 0 = failure + unsigned long long time; // Time in milliseconds + unsigned long long work; + unsigned long long span; + unsigned long long burdened_span; + unsigned long long spawns; + unsigned long long syncs; + unsigned long long strands; + unsigned long long atomic_ins; + unsigned long long frames; +} cilkview_data_t; + +typedef struct +{ + cilkview_data_t *start; // Values at start of interval + cilkview_data_t *end; // Values at end of interval + const char *label; // Name for this interval + unsigned int flags; // What to do - see flags below +} cilkview_report_t; + +// What __cilkview_report should do. The flags can be ORed together +enum +{ + CV_REPORT_WRITE_TO_LOG = 1, // Write parallelism report to the log (xml or text) + CV_REPORT_WRITE_TO_RESULTS = 2 // Write parallelism data to results file +}; + +#ifndef CILKVIEW_NO_REPORT +static void __cilkview_do_report(cilkview_data_t *start, + cilkview_data_t *end, + const char *label, + unsigned int flags); +#endif /* CILKVIEW_NO_REPORT */ + +/* + * Metacall data + * + * A metacall is a way to pass data to a function implemented by a tool. + * Metacalls are always instrumented when the tool is loaded. + */ + +// Tool code for Cilkview +#define METACALL_TOOL_CILKVIEW 2 + +// Metacall codes implemented by Cilkview +enum +{ + CV_METACALL_PUTS, + CV_METACALL_QUERY, + CV_METACALL_START, + CV_METACALL_STOP, + CV_METACALL_RESET, + CV_METACALL_USE_DEFAULT_GRAIN, + CV_METACALL_CONNECTED, + CV_METACALL_SUSPEND, + CV_METACALL_RESUME, + CV_METACALL_REPORT +}; + +#if ! defined(CILK_STUB) && defined(__INTEL_COMPILER) +# define __cilkview_metacall(code,data) \ + __cilkrts_metacall(METACALL_TOOL_CILKVIEW, code, data) +#else +# define __cilkview_metacall(annotation,expr) (annotation, (void) (expr)) +#endif + +// Write arbitrary string to the log +#define __cilkview_puts(arg) \ + __cilkview_metacall(CV_METACALL_PUTS, arg) + +// Retrieve the Cilkview performance counters. The parameter must be a +// cilkview_data_t +#define __cilkview_query(d) \ + do { \ + d.size = sizeof(d); \ + d.status = 0; \ + __cilkview_metacall(CV_METACALL_QUERY, &d); \ + if (0 == d.status) \ + d.time = __cilkview_getticks(); \ + } while (0) + +// Write report to log or results file. If end is NULL, Cilkview will +// use the current values. +#define __cilkview_report(start, end, label, flags) \ + __cilkview_do_report(start, end, label, flags) + +// Control the workspan performance counters for the final report +#define __cilkview_workspan_start() \ + __cilkview_metacall(CV_METACALL_START, 0) +#define __cilkview_workspan_stop() \ + __cilkview_metacall(CV_METACALL_STOP, 0) +#define __cilkview_workspan_reset() \ + __cilkview_metacall(CV_METACALL_RESET, 0) +#define __cilkview_workspan_suspend() \ + __cilkview_metacall(CV_METACALL_SUSPEND, 0) +#define __cilkview_workspan_resume() \ + __cilkview_metacall(CV_METACALL_RESUME, 0) + +#define __cilkview_use_default_grain_size() \ + __cilkview_metacall(CV_METACALL_USE_DEFAULT, 0) + +// Sets the int is_connected to 1 if Cilkview is active +#define __cilkview_connected(is_connected) \ + __cilkview_metacall(CV_METACALL_CONNECTED, &is_connected) + + +#ifndef CILKVIEW_NO_REPORT + +// Stop Microsoft include files from complaining about getenv and fopen +#define _CRT_SECURE_NO_WARNINGS + +#include <stdlib.h> +#include <stdio.h> + +#ifdef _WIN32 +#pragma warning(push) +#pragma warning(disable: 1786) // Suppress warnings that getenv, fopen are deprecated +#endif + +static void __cilkview_do_report(cilkview_data_t *start, + cilkview_data_t *end, + const char *label, + unsigned int flags) +{ + int under_cilkview = 0; + unsigned long long elapsed_ms; + int worker_count = 0; + char *nworkers; + char *outfile; + FILE *f; + + // Check whether we're running under Cilkview + __cilkview_connected(under_cilkview); + + // If we're running under Cilkview, let it do those things that need + // to be done + if (under_cilkview) + { + cilkview_report_t d = {start, end, label, flags}; + __cilkview_metacall(CV_METACALL_REPORT, &d); + return; + } + + // We're not running under Cilkview. + // + // If we weren't asked to write to the results file, we're done. + if (0 == (flags & CV_REPORT_WRITE_TO_RESULTS)) + return; + + // Calculate the elapse milliseconds + if (NULL == end) + elapsed_ms = __cilkview_getticks() - start->time; + else + elapsed_ms = end->time - start->time; + + // Determine how many workers we're using for this trial run + nworkers = getenv("CILK_NWORKERS"); + if (NULL != nworkers) + worker_count = atoi(nworkers); + if (0 == worker_count) + worker_count = 16; + + // Open the output file and write the trial data to it + outfile = getenv("CILKVIEW_OUTFILE"); + if (NULL == outfile) + outfile = (char *)"cilkview.out"; + + f = fopen(outfile, "a"); + if (NULL == f) + fprintf(stderr, "__cilkview_do_report: unable to append to file %s\n", outfile); + else + { + fprintf(f, "%s trial %d %f\n", label, + worker_count, + ((float)elapsed_ms) / 1000.0f); + fclose(f); + } +} +#ifdef _WIN32 +#pragma warning(pop) +#endif + +#endif // CILKVIEW_NO_REPORT + + +#endif /* ! defined(INCLUDED_CILKVIEW_H) */ diff --git a/libcilkrts/include/cilktools/fake_mutex.h b/libcilkrts/include/cilktools/fake_mutex.h new file mode 100644 index 00000000000..9ae0678112f --- /dev/null +++ b/libcilkrts/include/cilktools/fake_mutex.h @@ -0,0 +1,92 @@ +/* fake_mutex.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************** + * + * Cilkscreen fake mutexes are provided to indicate to the Cilkscreen race + * detector that a race should be ignored. + * + * NOTE: This class does not provide mutual exclusion. You should use the + * mutual exclusion constructs provided by TBB or your operating system to + * protect against real data races. + */ + +#ifndef FAKE_MUTEX_H_INCLUDED +#define FAKE_MUTEX_H_INCLUDED + +#include <cilktools/cilkscreen.h> + +namespace cilkscreen +{ + class fake_mutex + { + public: + fake_mutex() : locked(false) + { + } + + ~fake_mutex() + { + __CILKRTS_ASSERT(! locked); + } + + // Wait until mutex is available, then enter + void lock() + { + __cilkscreen_acquire_lock(&locked); + __CILKRTS_ASSERT(! locked); + locked = true; + } + + // A fake mutex is always available + bool try_lock() { lock(); return true; } + + // Releases the mutex + void unlock() + { + __CILKRTS_ASSERT(locked); + locked = false; + __cilkscreen_release_lock(&locked); + } + + private: + bool locked; + }; + +} // namespace cilk + +#endif // FAKE_MUTEX_H_INCLUDED diff --git a/libcilkrts/include/cilktools/lock_guard.h b/libcilkrts/include/cilktools/lock_guard.h new file mode 100644 index 00000000000..d513e2b9734 --- /dev/null +++ b/libcilkrts/include/cilktools/lock_guard.h @@ -0,0 +1,86 @@ +/* lock_guard.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2011-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************** + * + * Lock guard patterned after the std::lock_guard class template proposed in + * the C++ 0x draft standard. + * + * An object of type lock_guard controls the ownership of a mutex object + * within a scope. A lock_guard object maintains ownership of a mutex object + * throughout the lock_guard object's lifetime. The behavior of a program is + * undefined if the mutex referenced by pm does not exist for the entire + * lifetime of the lock_guard object. + */ + +#ifndef LOCK_GUARD_H_INCLUDED +#define LOCK_GUARD_H_INCLUDED + +#include <cilk/cilk.h> + +namespace cilkscreen +{ + template <class Mutex> + class lock_guard + { + public: + typedef Mutex mutex_type; + + explicit lock_guard(mutex_type &m) : pm(m) + { + pm.lock(); + locked = true; + } + + ~lock_guard() + { + locked = false; + pm.unlock(); + } + + private: + lock_guard(lock_guard const&); + lock_guard& operator=(lock_guard const&); + + private: + // exposition only: + mutex_type ± + bool locked; + }; +} + +#endif // LOCK_GUARD_H_INCLUDED diff --git a/libcilkrts/include/internal/abi.h b/libcilkrts/include/internal/abi.h new file mode 100644 index 00000000000..f45b5bcb178 --- /dev/null +++ b/libcilkrts/include/internal/abi.h @@ -0,0 +1,639 @@ +/* + * abi.h + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ******************************************************************************/ + +/** + * @file abi.h + * + * @brief Defines the application binary interface between the compiler and + * the Intel Cilk Plus runtime. + */ + +#ifndef CILK_INTERNAL_ABI_H +#define CILK_INTERNAL_ABI_H + + +#include <cilk/common.h> +#include <stddef.h> // Needed to define size_t + +/** + * Jump buffers are OS and architecture dependent + */ +#if ! defined(_MSC_VER) +/* Non-Windows - only need 5 registers for the jump buffer for both IA32 and Intel64 */ +typedef void *__CILK_JUMP_BUFFER[5]; + +/** OS-specific implementation of setjmp */ +# define CILK_SETJMP(X) __builtin_setjmp(X) +/** OS-specific implementation of longjmp */ +# define CILK_LONGJMP(X) __builtin_longjmp(X,1) +#else +/* Windows - things are a little more complicated */ +# if defined(_M_X64) +/* Intel64 - Use an OS-defined jump buffer */ +# include <setjmp.h> +typedef jmp_buf __CILK_JUMP_BUFFER; + +# define CILK_SETJMP(X) setjmp(X) +# define CILK_LONGJMP(X) longjmp(X, 1) +# elif defined(_M_IX86) +/** + * Windows x86 - Use a simplified version of the Windows jump buffer for x86 + * setjmp is provided by __cilkrts_setjmp which passes jump buffer in EAX and + * destination in EDX longjmp is provided by an internal routine which uses + * this structure + */ +typedef struct +{ + unsigned long Ebp; + unsigned long Ebx; + unsigned long Edi; + unsigned long Esi; + unsigned long Esp; + unsigned long Eip; + unsigned long Registration; + unsigned long TryLevel; +} __CILK_JUMP_BUFFER; + +# else +# error Unexpected architecture - Need to define __CILK_JUMP_BUFFER +# endif /* _M_X64 */ + +#endif /* defined(_MSC_VER) */ + +/* struct tags */ +typedef struct __cilkrts_stack_frame __cilkrts_stack_frame; ///< struct tag for stack frame + +// Forwarded declarations +typedef struct global_state_t global_state_t; ///< Forwarded declaration for global state +typedef struct local_state local_state; ///< Forwarded declaration for local state +typedef struct cilkred_map cilkred_map; ///< Forward declaration for reducer map + +/// Forwarded declaration for system-dependent worker state +typedef struct __cilkrts_worker_sysdep_state + __cilkrts_worker_sysdep_state; + +/** + * The worker struct contains per-worker information that needs to be + * visible to the compiler, or rooted here. + * + * For 32-bit Windows we need to be aligning the structures on 4-byte + * boundaries to match where ICL is allocating the birthrank and rank + * in the __cilkrts_stack_frame. It's 4-byte aligned instead of 8-byte + * aligned. This is OK because the compiler is dealing with the 64-bit + * quantities as two 32-bit values. So change the packing to be on + * 4-byte boundaries. + * + * The fields of the worker struct can be classified as either local + * or shared. + * + * Local: This field is only accessed by the thread bound to this + * worker struct. Local fields can be freely accessed without + * acquiring locks. + * + * Shared: This field may be accessed by multiple worker threads. + * Accesses to shared fields usually requires locks, except in + * special situations where one can prove that locks are + * unnecessary. + * + * The fields of the worker struct can also be classified as + * "read-only" if the field does not change after it is initialized. + * Otherwise, the field is "read/write". Read-only fields do not + * require locks to access (ignoring the synchronization that might be + * needed for initialization if this can occur in parallel). + * + * Finally, we explicitly classify some fields as "synchronization" + * fields if they are used as part of a synchronization protocol in + * the runtime. These variables are generally shared and read/write. + * Mostly, this category includes lock variables and other variables + * that are involved in synchronization protocols (i.e., the THE + * protocol). + */ +#if defined(_MSC_VER) && defined(_M_IX86) +#pragma pack(push, 4) +#endif + +struct __cilkrts_worker { + /** + * T, H, and E pointers in the THE protocol See "The implementation of + * the Cilk-5 multithreaded language", PLDI 1998: + * http://portal.acm.org/citation.cfm?doid=277652.277725 + * + * Synchronization fields. [shared read/write] + */ + __cilkrts_stack_frame *volatile *volatile tail; + __cilkrts_stack_frame *volatile *volatile head; /**< @copydoc tail */ + __cilkrts_stack_frame *volatile *volatile exc; /**< @copydoc tail */ + + /** + * Addition to the THE protocol to allow us to protect some set of + * entries in the tail queue from stealing. Normally, this is set + * beyond the end of the task queue, indicating that all entries are + * available for stealing. During exception handling, protected_tail + * may be set to the first entry in the task queue, indicating that + * stealing is not allowed. + * + * Synchronization field. + */ + __cilkrts_stack_frame *volatile *volatile protected_tail; + + /** + * Limit of the Lazy Task Queue, to detect queue overflow + * [local read-only] + */ + __cilkrts_stack_frame *volatile *ltq_limit; + + /** + * Worker id. + * [local read-only] + */ + int32_t self; + + /** + * Global state of the runtime system, opaque to the client. + * [local read-only] + */ + global_state_t *g; + + /** + * Additional per-worker state of the runtime system that we want + * to maintain hidden from the client. + * [shared read-only] + */ + local_state *l; + + /** + * Map from reducer names to reducer values. + * [local read/write] + */ + cilkred_map *reducer_map; + + /** + * A slot that points to the currently executing Cilk frame. + * [local read/write] + */ + __cilkrts_stack_frame *current_stack_frame; + + /** + * Reserved space for a pointer. + * Used to be __cilkrts_stack_frame *volatile *volatile saved_protected_tail; + */ + void* reserved; + + /** + * System-dependent part of the worker state + * [local read-only] + */ + __cilkrts_worker_sysdep_state *sysdep; + +#if __CILKRTS_ABI_VERSION >= 1 + /** + * Per-worker pedigree information used to support scheduling-independent + * pseudo-random numbers. + * [local read/write] + */ + __cilkrts_pedigree pedigree; +#endif /* __CILKRTS_ABI_VERSION >= 1 */ +}; + + +/** + * Every spawning function has a frame descriptor. A spawning function + * is a function that spawns or detaches. Only spawning functions + * are visible to the Cilk runtime. + */ +struct __cilkrts_stack_frame +{ + /** + * flags is an integer with values defined below. Client code + * initializes flags to CILK_FRAME_VERSION before the first Cilk + * operation. + * + * The low 24-bits of the 'flags' field are the flags, proper. The high + * 8-bits are the version number. + * + * IMPORTANT: bits in this word are set and read by the PARENT ONLY, + * not by a spawned child. In particular, the STOLEN and UNSYNCHED + * bits are set on a steal and are read before a sync. Since there + * is no synchronization (locking) on this word, any attempt to set + * or read these bits asynchronously in a child would result in a race. + */ + uint32_t flags; + + /** Not currently used. Not initialized by Intel compiler. */ + int32_t size; + + /** + * call_parent points to the __cilkrts_stack_frame of the closest + * ancestor spawning function, including spawn helpers, of this frame. + * It forms a linked list ending at the first stolen frame. + */ + __cilkrts_stack_frame *call_parent; + + /** + * The client copies the worker from TLS here when initializing + * the structure. The runtime ensures that the field always points + * to the __cilkrts_worker which currently "owns" the frame. + */ + __cilkrts_worker *worker; + + /** + * Unix: Pending exception after sync. The sync continuation + * must call __cilkrts_rethrow to handle the pending exception. + * + * Windows: the handler that _would_ have been registered if our + * handler were not there. We maintain this for unwinding purposes. + * Win32: the value of this field is only defined in spawn helper + * functions + * + * Win64: except_data must be filled in for all functions with a + * __cilkrts_stack_frame + */ + void *except_data; + + /** + * Before every spawn and nontrivial sync the client function + * saves its continuation here. + */ + __CILK_JUMP_BUFFER ctx; + +#if __CILKRTS_ABI_VERSION >= 1 + /** + * Architecture-specific floating point state. mxcsr and fpcsr should be + * set when CILK_SETJMP is called in client code. Note that the Win64 + * jmpbuf for the Intel64 architecture already contains this information + * so there is no need to use these fields on that OS/architecture. + */ + uint32_t mxcsr; + uint16_t fpcsr; /**< @copydoc mxcsr */ + + + /** + * reserved is not used at this time. Client code should initialize it + * to 0 before the first Cilk operation + */ + uint16_t reserved; + + /** + * Pedigree information to support scheduling-independent pseudo-random + * numbers. There are two views of this information. The copy in a + * spawning function is used to stack the rank and communicate to the + * runtime on a steal or continuation. The copy in a spawn helper is + * immutable once the function is detached and is a node in the pedigree. + * The union is used to make clear which view we're using. + * + * In the detach sequence Client code should: + * - copy the worker pedigree into the spawn helper's pedigree + * - copy the worker pedigree into the call parent's pedigree + * - set the worker's rank to 0 + * - set the worker's pedigree.next to the spawn helper's pedigree + */ + union + { + __cilkrts_pedigree spawn_helper_pedigree; /* Used in spawn helpers */ + __cilkrts_pedigree parent_pedigree; /* Used in spawning funcs */ + }; +#endif /* __CILKRTS_ABI_VERSION >= 1 */ +}; + +/* + * Restore previous structure packing for 32-bit Windows + */ +#if defined(_MSC_VER) && defined(_M_IX86) +#pragma pack(pop) +#endif + +/* Values of the flags bitfield */ +/** CILK_FRAME_STOLEN is set if the frame has ever been stolen. */ +#define CILK_FRAME_STOLEN 0x01 + +/** + * CILK_FRAME_UNSYNCHED is set if the frame has been stolen and + * is has not yet executed _Cilk_sync. It is technically a misnomer in that a + * frame can have this flag set even if all children have returned. + */ +#define CILK_FRAME_UNSYNCHED 0x02 + +/** + * Is this frame detached (spawned)? If so the runtime needs + * to undo-detach in the slow path epilogue. + */ +#define CILK_FRAME_DETACHED 0x04 + +/** + * CILK_FRAME_EXCEPTION_PROBED is set if the frame has been probed in the + * exception handler first pass + */ +#define CILK_FRAME_EXCEPTION_PROBED 0x08 + +/** Is this frame receiving an exception after sync? */ +#define CILK_FRAME_EXCEPTING 0x10 + +/** + * Is the pedigree unsynched? That is, has a synch occurred that is not + * yet represented in the pedigree? + */ +#define CILK_FRAME_SF_PEDIGREE_UNSYNCHED 0x20 + +/** Is this the last (oldest) Cilk frame? */ +#define CILK_FRAME_LAST 0x80 + +/** + * Is this frame in the epilogue, or more generally after the last + * sync when it can no longer do any Cilk operations? + */ +#define CILK_FRAME_EXITING 0x0100 + +/** Is this frame suspended? (used for debugging) */ +#define CILK_FRAME_SUSPENDED 0x8000 + +/** Used by Windows exception handling to indicate that __cilkrts_leave_frame should do nothing */ +#define CILK_FRAME_UNWINDING 0x10000 + +/* + * The low 24-bits of the 'flags' field are the flags, proper. The high 8-bits + * are the version number. + */ + +/** ABI version left shifted to the high byte */ +#define CILK_FRAME_VERSION (__CILKRTS_ABI_VERSION << 24) + +/** Mask for the flags field to isolate the version bits */ +#define CILK_FRAME_VERSION_MASK 0xFF000000 + +/** Mask for the flags field to isolate the flag bits */ +#define CILK_FRAME_FLAGS_MASK 0x00FFFFFF + +/** Convenience macro to provide access the version portion of the flags field */ +#define CILK_FRAME_VERSION_VALUE(_flags) (((_flags) & CILK_FRAME_VERSION_MASK) >> 24) + +/** Any undefined bits are reserved and must be zero ("MBZ" = "Must Be Zero") */ +#define CILK_FRAME_MBZ (~ (CILK_FRAME_STOLEN | \ + CILK_FRAME_UNSYNCHED | \ + CILK_FRAME_DETACHED | \ + CILK_FRAME_EXCEPTION_PROBED | \ + CILK_FRAME_EXCEPTING | \ + CILK_FRAME_SF_PEDIGREE_UNSYNCHED | \ + CILK_FRAME_LAST | \ + CILK_FRAME_EXITING | \ + CILK_FRAME_SUSPENDED | \ + CILK_FRAME_UNWINDING | \ + CILK_FRAME_VERSION_MASK)) + +__CILKRTS_BEGIN_EXTERN_C + +/** + * Call __cilkrts_enter_frame to initialize an ABI 0 frame descriptor. + * Initialize the frame descriptor before spawn or detach. A function that + * conditionally does Cilk operations need not initialize the frame descriptor + * in a code path that never uses it. + * + * @param sf The __cilkrts_stack_frame that is to be initialized. + */ +CILK_ABI(void) __cilkrts_enter_frame(__cilkrts_stack_frame* sf); + +/** + * Call __cilkrts_enter_frame to initialize an ABI 1 frame descriptor. + * Initialize the frame descriptor before spawn or detach. A function that + * conditionally does Cilk operations need not initialize the frame descriptor + * in a code path that never uses it. + * + * @param sf The __cilkrts_stack_frame that is to be initialized. + */ +CILK_ABI(void) __cilkrts_enter_frame_1(__cilkrts_stack_frame* sf); + +/** + * __cilkrts_enter_frame_fast is the same as __cilkrts_enter_frame, except it + * assumes that the thread has already been bound to a worker. + * + * @param sf The __cilkrts_stack_frame that is to be initialized. + */ +CILK_ABI(void) __cilkrts_enter_frame_fast(__cilkrts_stack_frame *sf); + +/** + * __cilkrts_enter_frame_fast_1 is the same as __cilkrts_enter_frame_1, + * except it assumes that the thread has already been bound to a worker. + * + * @param sf The __cilkrts_stack_frame that is to be initialized. + */ +CILK_ABI(void) __cilkrts_enter_frame_fast_1(__cilkrts_stack_frame *sf); + +/** + * Call leave_frame before leaving a frame, after sync. This function + * returns except in a spawn wrapper where the parent has been stolen. + * + * @param sf The __cilkrts_stack_frame that is to be left. + */ +CILK_ABI(void) __cilkrts_leave_frame(__cilkrts_stack_frame *sf); + +/** + * Wait for any spawned children of this function to complete before + * continuing. This function will only return when the join counter + * has gone to 0. Other workers will re-enter the scheduling loop to + * attempt to steal additional work. + * + * @param sf The __cilkrts_stack_frame that is to be synched. + */ +CILK_ABI(void) __cilkrts_sync(__cilkrts_stack_frame *sf); + +/** + * Called when an exception is escaping a spawn * wrapper. + * The stack frame's except_data field is the C++ runtime + * exception object. If NULL (temporary workaround) the + * currently caught exception should be rethrown. If this + * function returns normal exit functions must be called; + * undo-detach will have been done. + * + * @param sf The __cilkrts_stack_frame for the function that + * is raising an exception. + */ +CILK_ABI_THROWS(void) + __cilkrts_return_exception(__cilkrts_stack_frame *sf); + +/** + * Called to re-raise an exception. + * + * @param sf The __cilkrts_stack_frame for the function that + * is raising an exception. + */ +CILK_ABI_THROWS(void) __cilkrts_rethrow(__cilkrts_stack_frame *sf); + +/** + * Called at the beginning of a spawning function to get the worker + * that this function is running on. This worker will be used to + * initialize the __cilkrts_stack_frame. + * + * @return The __cilkrts_worker that the function is running on. + * @return NULL if this thread is not yet bound to a worker. + */ +CILK_ABI(__cilkrts_worker_ptr) __cilkrts_get_tls_worker(void); + +/** + * Similar to __cilkrts_get_tls_worker, but assumes that TLS has been + * initialized. + * + * @return The __cilkrts_worker that the function is running on. + * @return NULL if this thread is not yet bound to a worker. + */ +CILK_ABI(__cilkrts_worker_ptr) __cilkrts_get_tls_worker_fast(void); + +/** + * Binds a thread to the runtime by associating a __cilkrts_worker with + * it. Called if __cilkrts_get_tls_worker returns NULL. This function will + * initialize the runtime the first time it is called. + * + * This function is versioned by the ABI version number. The runtime + * will export all previous versions. This prevents using an application + * built with a newer compiler against an old runtime. + * + * @return The __cilkrts_worker bound to the thread the function is running + * on. + */ +CILK_ABI(__cilkrts_worker_ptr) __cilkrts_bind_thread_1(void); + +typedef uint32_t cilk32_t; /**< 32-bit unsigned type for cilk_for loop indicies */ + +typedef uint64_t cilk64_t; /**< 64-bit unsigned type for cilk_for loop indicies */ + +/** + * Signature for the lambda function generated for the body of a cilk_for loop + * which uses 32-bit indicies + */ +typedef void (*__cilk_abi_f32_t)(void *data, cilk32_t low, cilk32_t high); + +/** + * Signature for the lambda function generated for the body of a cilk_for lop + * which uses 64-bit indicies + */ +typedef void (*__cilk_abi_f64_t)(void *data, cilk64_t low, cilk64_t high); + +/** + * @brief cilk_for implementation for 32-bit indexes. + * + * @param body The lambda function for the body of the cilk_for. The lambda + * function will be called to execute each grain of work. + * @param data Data passed by the compiler into the lambda function. Provides + * access to data outside the cilk_for body. + * @param count Number of steps in the loop. + * @param grain This parameter allows the compiler to pass a value from a + * \#pragam(grainsize) statement to allow the user to control the grainsize. If + * there isn't a \#pragma(grainsize) immediately preceeding cilk_for loop, Pass + * 0 to specify that the runtime should calculate the grainsize using its own + * hueristicts. + */ +CILK_ABI_THROWS(void) __cilkrts_cilk_for_32(__cilk_abi_f32_t body, + void *data, + cilk32_t count, + int grain); + +/** + * @brief cilk_for implementation for 64-bit indexes. + * + * @copydetails __cilkrts_cilk_for_32 + */ +CILK_ABI_THROWS(void) __cilkrts_cilk_for_64(__cilk_abi_f64_t body, + void *data, + cilk64_t count, + int grain); + +/** + * @brief Allocate memory for variable length arrays. If the frame is + * sync'd, the memory will be allocated on the stack, otherwise it will + * be allocated from the heap. + * + * @param sf The __cilkrts_stack_frame for the function allocating the + * memory. + * @param size The number of bytes requested. + * @param distance_from_sp_to_alloca_area ?. + * @param align Alignment required. Always >= minimum stack alignment, + * >= ptr_size, and always a power of 2. + * @param needs_tag Non-zero if the pointer being returned needs to be + * tagged + * + * @return The address of the memory block allocated. + */ + +CILK_ABI(__cilkrts_void_ptr) +__cilkrts_stack_alloc(__cilkrts_stack_frame *sf, + size_t size, + size_t distance_from_sp_to_alloca_area, + uint32_t align, + uint32_t needs_tag); + +/** + * @brief Free memory allocated by _cilkrts_stack_alloc() for variable length + * arrays. + * + * @param sf The __cilkrts_stack_frame for the function allocating the + * memory. + * @param p Pointer to the memory block to be freed. + * @param size The number of bytes requested. + * @param distance_from_sp_to_alloca_area ?. + * @param align Alignment required. Always >= minimum stack alignment, + * >= ptr_size, and always a power of 2. + * @param know_from_stack Non-zero if the pointer is known to have been + * allocated on the stack and has no tag. + */ +CILK_ABI(void) +__cilkrts_stack_free(__cilkrts_stack_frame *sf, + void *p, + size_t size, + size_t distance_from_sp_to_alloca_area, + uint32_t align, + uint32_t known_from_stack); + +/** + * @brief System-dependent code to save floating point control information + * to an ABI 1 or higher @c __cilkrts_stack_frame. If possible (and necessary) + * the code to save the floating point control information should be inlined. + * + * Note that this function does *not* save the current floating point + * registers. It saves the floating point control words that control + * precision and rounding and stuff like that. + * + * This function will be a noop for architectures that don't have warts + * like the floating point control words, or where the information is + * already being saved by the setjmp. + * + * @param sf @c __cilkrts_stack_frame for the frame we're saving the + * floating point control information in. + */ +CILK_ABI(void) +__cilkrts_save_fp_ctrl_state(__cilkrts_stack_frame *sf); + +__CILKRTS_END_EXTERN_C +#endif /* include guard */ diff --git a/libcilkrts/include/internal/cilk_fake.h b/libcilkrts/include/internal/cilk_fake.h new file mode 100644 index 00000000000..2386dd6bffa --- /dev/null +++ b/libcilkrts/include/internal/cilk_fake.h @@ -0,0 +1,477 @@ +/* cilk_fake.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2011-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file cilk_fake.h + * + * @brief Macros to simulate a compiled Cilk program. + * + * Used carefully, these macros can be used to create a Cilk program with a + * non-Cilk compiler by manually inserting the code necessary for interacting + * with the Cilk runtime library. They are not intended to be pretty (you + * wouldn't want to write a whole program using these macros), but they are + * useful for experiments. They also work well as an illustration of what the + * compiler generates. + * + * Details of the mechanisms used in these macros are described in + * design-notes/CilkPlusABI.docx + * + * Example 1: fib in C++ + * --------------------- + * + * #include <internal/cilk_fake.h> + * + * int fib(int n) + * { + * CILK_FAKE_PROLOG(); + * + * if (n < 2) + * return n; + * + * int a, b; + * CILK_FAKE_SPAWN_R(a, fib(n - 1)); + * b = fib(n - 2); + * CILK_FAKE_SYNC(); + * + * return a + b; + * } + * + * + * Example 2: fib in C + * ------------------- + * + * #include <internal/cilk_fake.h> + * + * int fib(int n); + * + * void fib_spawn_helper(__cilkrts_stack_frame* parent_sf, int* a, int n) + * { + * CILK_FAKE_SPAWN_HELPER_PROLOG(*parent_sf); + * *a = fib(n - 1); + * CILK_FAKE_SPAWN_HELPER_EPILOG(); + * } + * + * int fib(int n) + * { + * CILK_FAKE_PROLOG(); + * + * if (n < 2) + * return n; + * + * int a, b; + * CILK_FAKE_CALL_SPAWN_HELPER(fib_spawn_helper(&__cilk_sf, &a, n)); + * b = fib(n - 2); + * CILK_FAKE_SYNC(); + * + * CILK_FAKE_EPILOG(); + * return a + b; + * } + */ + +#ifndef INCLUDED_CILK_FAKE_DOT_H +#define INCLUDED_CILK_FAKE_DOT_H + +// This header implements ABI version 1. If __CILKRTS_ABI_VERSION is already +// defined but is less than 1, then the data structures in <internal/abi.h> +// will not match the expectations of facilities in this header. Therefore, +// for successful compilation, __CILKRTS_ABI_VERSION must either be not +// defined, or defined to be 1 or greater. +#ifndef __CILKRTS_ABI_VERSION + // ABI version was not specified. Set it to 1. +# define __CILKRTS_ABI_VERSION 1 +#elif __CILKRTS_ABI_VERSION < 1 + // ABI version was specified but was too old. Fail compilation. +# error cilk_fake.h requirs an ABI version of 1 or greater +#endif + +#include <internal/abi.h> + +// alloca is defined in malloc.h on Windows, alloca.h on Linux +#ifndef _MSC_VER +#include <alloca.h> +#else +#include <malloc.h> +// Define offsetof +#include <stddef.h> +#endif + +// Allows use of a different version that the one defined in abi.h +#define CILK_FAKE_VERSION_FLAG (__CILKRTS_ABI_VERSION << 24) + +/* Initialize frame. To be called when worker is known */ +__CILKRTS_INLINE void __cilk_fake_enter_frame_fast(__cilkrts_stack_frame *sf, + __cilkrts_worker *w) +{ + sf->call_parent = w->current_stack_frame; + sf->worker = w; + sf->flags = CILK_FAKE_VERSION_FLAG; + w->current_stack_frame = sf; +} + +/* Initialize frame. To be called when worker is not known */ +__CILKRTS_INLINE void __cilk_fake_enter_frame(__cilkrts_stack_frame *sf) +{ + __cilkrts_worker* w = __cilkrts_get_tls_worker(); + uint32_t last_flag = 0; + if (! w) { + w = __cilkrts_bind_thread_1(); + last_flag = CILK_FRAME_LAST; + } + __cilk_fake_enter_frame_fast(sf, w); + sf->flags |= last_flag; +} + +/* Initialize frame. To be called within the spawn helper */ +__CILKRTS_INLINE void __cilk_fake_helper_enter_frame( + __cilkrts_stack_frame *sf, + __cilkrts_stack_frame *parent_sf) +{ + sf->worker = 0; + sf->call_parent = parent_sf; +} + +/* Called from the spawn helper to push the parent continuation on the task + * deque so that it can be stolen. + */ +__CILKRTS_INLINE void __cilk_fake_detach(__cilkrts_stack_frame *sf) +{ + /* Initialize spawn helper frame. + * call_parent was saved in __cilk_fake_helper_enter_frame */ + __cilkrts_stack_frame *parent = sf->call_parent; + __cilkrts_worker *w = parent->worker; + __cilk_fake_enter_frame_fast(sf, w); + + /* Append a node to the pedigree */ + sf->spawn_helper_pedigree = w->pedigree; + parent->parent_pedigree = w->pedigree; + w->pedigree.rank = 0; + w->pedigree.parent = &sf->spawn_helper_pedigree; + + /* Push parent onto the task deque */ + __cilkrts_stack_frame *volatile *tail = w->tail; + *tail++ = sf->call_parent; + /* The stores must be separated by a store fence (noop on x86) + * or the second store is a release (st8.rel on Itanium) */ + w->tail = tail; + sf->flags |= CILK_FRAME_DETACHED; +} + +/* This variable is used in CILK_FAKE_FORCE_FRAME_PTR(), below */ +static int __cilk_fake_dummy = 8; + +/* The following macro is used to force the compiler into generating a frame + * pointer. We never change the value of __cilk_fake_dummy, so the alloca() + * is never called, but we need the 'if' statement and the __cilk_fake_dummy + * variable so that the compiler does not attempt to optimize it away. + */ +#define CILK_FAKE_FORCE_FRAME_PTR(sf) do { \ + if (__builtin_expect(1 & __cilk_fake_dummy, 0)) \ + (sf).worker = (__cilkrts_worker*) alloca(__cilk_fake_dummy); \ +} while (0) + +#ifndef CILK_FAKE_NO_SHRINKWRAP + /* "shrink-wrap" optimization enabled. Do not initialize frame on entry, + * except to clear worker pointer. Instead, defer initialization until + * the first spawn. + */ +# define CILK_FAKE_INITIAL_ENTER_FRAME(sf) ((void) ((sf).worker = 0)) +# define CILK_FAKE_DEFERRED_ENTER_FRAME(sf) do { \ + if (! (sf).worker) __cilk_fake_enter_frame(&(sf)); \ + } while (0) +#else + /* "shrink-wrap" optimization disabled. Initialize frame immediately on + * entry. Do not initialize frame on spawn. + */ +# define CILK_FAKE_INITIAL_ENTER_FRAME(sf) \ + __cilk_fake_enter_frame(&(sf)) +# define CILK_FAKE_DEFERRED_ENTER_FRAME(sf) ((void) &(sf)) +#endif + +/* Prologue of a spawning function. Declares and initializes the stack + * frame. + */ +#define CILK_FAKE_PROLOG() \ + __cilk_fake_stack_frame __cilk_sf; \ + CILK_FAKE_FORCE_FRAME_PTR(__cilk_sf); \ + CILK_FAKE_INITIAL_ENTER_FRAME(__cilk_sf) + +/* Prologue of a spawning function where the current worker is already known. + * Declares and initializes the stack frame without looking up the worker from + * TLS. + */ +#define CILK_FAKE_PROLOG_FAST(w) \ + __cilk_fake_stack_frame __cilk_sf; \ + CILK_FAKE_FORCE_FRAME_PTR(__cilk_sf); \ + __cilk_fake_enter_frame_fast(&__cilk_sf, (w)) + +/* Simulate a cilk_sync */ +#define CILK_FAKE_SYNC() CILK_FAKE_SYNC_IMP(__cilk_sf) + +/* Epilog at the end of a spawning function. Does a sync and calls the + * runtime for leaving the frame. + */ +#ifdef __cplusplus + // Epilogue is run automatically by __cilk_fake_stack_frame destructor. +# define CILK_FAKE_EPILOG() ((void) __cilk_sf) +#else +# define CILK_FAKE_EPILOG() CILK_FAKE_CLEANUP_FRAME(__cilk_sf) +#endif // C + +/* Implementation of spawning function epilog. See CILK_FAKE_EPILOG macro and + * __cilk_fake_stack_frame destructor body. + */ +#define CILK_FAKE_CLEANUP_FRAME(sf) do { \ + if (! (sf).worker) break; \ + CILK_FAKE_SYNC_IMP(sf); \ + CILK_FAKE_POP_FRAME(sf); \ + if ((sf).flags != CILK_FAKE_VERSION_FLAG) \ + __cilkrts_leave_frame(&(sf)); \ +} while (0) + +/* Implementation of CILK_FAKE_SYNC with sf argument */ +#define CILK_FAKE_SYNC_IMP(sf) do { \ + if (__builtin_expect((sf).flags & CILK_FRAME_UNSYNCHED, 0)) { \ + (sf).parent_pedigree = (sf).worker->pedigree; \ + CILK_FAKE_SAVE_FP(sf); \ + if (! CILK_SETJMP((sf).ctx)) \ + __cilkrts_sync(&(sf)); \ + } \ + ++(sf).worker->pedigree.rank; \ +} while (0) + +/* Save the floating-point control registers. + * The definition of CILK_FAKE_SAVE_FP is compiler specific (and + * architecture specific on Windows) + */ +#ifdef _MSC_VER +# define MXCSR_OFFSET offsetof(struct __cilkrts_stack_frame, mxcsr) +# define FPCSR_OFFSET offsetof(struct __cilkrts_stack_frame, fpcsr) +# if defined(_M_IX86) +/* Windows x86 */ +# define CILK_FAKE_SAVE_FP(sf) do { \ + __asm \ + { \ + mov eax, sf \ + stmxcsr [eax+MXCSR_OFFSET] \ + fnstcw [eax+FPCSR_OFFSET] \ + } \ + } while (0) +# elif defined(_M_X64) +/* Windows Intel64 - Not needed - saved by setjmp call */ +# define CILK_FAKE_SAVE_FP(sf) ((void) sf) +# else +# error "Unknown architecture" +# endif /* Microsoft architecture specifics */ +#else +/* Non-Windows */ +# define CILK_FAKE_SAVE_FP(sf) do { \ + __asm__ ( "stmxcsr %0\n\t" \ + "fnstcw %1" : : "m" ((sf).mxcsr), "m" ((sf).fpcsr)); \ + } while (0) +#endif + +/* Call the spawn helper as part of a fake spawn */ +#define CILK_FAKE_CALL_SPAWN_HELPER(helper) do { \ + CILK_FAKE_DEFERRED_ENTER_FRAME(__cilk_sf); \ + CILK_FAKE_SAVE_FP(__cilk_sf); \ + if (__builtin_expect(! CILK_SETJMP(__cilk_sf.ctx), 1)) { \ + helper; \ + } \ +} while (0) + +/* Body of a spawn helper function. In addition to the worker and the + * expression to spawn, pass it any number of statements to be executed before + * detaching. + */ +#define CILK_FAKE_SPAWN_HELPER_BODY(parent_sf, expr, ...) \ + CILK_FAKE_SPAWN_HELPER_PROLOG(parent_sf); \ + __VA_ARGS__; \ + __cilk_fake_detach(&__cilk_sf); \ + expr; \ + CILK_FAKE_SPAWN_HELPER_EPILOG() + +/* Prolog for a spawn helper function */ +#define CILK_FAKE_SPAWN_HELPER_PROLOG(parent_sf) \ + __cilk_fake_spawn_helper_stack_frame __cilk_sf; \ + __cilk_fake_helper_enter_frame(&__cilk_sf, &(parent_sf)) + +/* Implementation of spawn helper epilog. See CILK_FAKE_SPAWN_HELPER_EPILOG + * and the __cilk_fake_spawn_helper_frame destructor. + */ +#define CILK_FAKE_SPAWN_HELPER_CLEANUP_FRAME(sf) do { \ + if (! (sf).worker) break; \ + CILK_FAKE_POP_FRAME(sf); \ + __cilkrts_leave_frame(&(sf)); \ +} while (0) + +/* Epilog to execute at the end of a spawn helper */ +#ifdef __cplusplus + // Epilog handled by __cilk_fake_spawn_helper_stack_frame destructor +# define CILK_FAKE_SPAWN_HELPER_EPILOG() ((void) __cilk_sf) +#else +# define CILK_FAKE_SPAWN_HELPER_EPILOG() \ + CILK_FAKE_SPAWN_HELPER_CLEANUP_FRAME(__cilk_sf) +#endif + +/* Pop the current frame off of the call chain */ +#define CILK_FAKE_POP_FRAME(sf) do { \ + (sf).worker->current_stack_frame = (sf).call_parent; \ + (sf).call_parent = 0; \ +} while (0) + +#ifdef _WIN32 +/* define macros for synching functions before allowing them to propagate. */ +# define CILK_FAKE_EXCEPT_BEGIN \ + if (0 == CILK_SETJMP(__cilk_sf.except_ctx)) { + +# define CILK_FAKE_EXCEPT_END \ + } else { \ + assert((__cilk_sf.flags & (CILK_FRAME_UNSYNCHED|CILK_FRAME_EXCEPTING))\ + == CILK_FRAME_EXCEPTING); \ + __cilkrts_rethrow(&__cilk_sf); \ + exit(0); \ + } +#else +# define CILK_EXCEPT_BEGIN { +# define CILK_EXCEPT_END } +#endif + +#ifdef __cplusplus +// The following definitions depend on C++ features. + +// Wrap a functor (probably a lambda), so that a call to it cannot be +// inlined. +template <typename F> +class __cilk_fake_noinline_wrapper +{ + F&& m_fn; +public: + __cilk_fake_noinline_wrapper(F&& fn) : m_fn(static_cast<F&&>(fn)) { } + +#ifdef _WIN32 + __declspec(noinline) void operator()(__cilkrts_stack_frame *sf); +#else + void operator()(__cilkrts_stack_frame *sf) __attribute__((noinline)); +#endif + +}; + +template <typename F> +void __cilk_fake_noinline_wrapper<F>::operator()(__cilkrts_stack_frame *sf) +{ + m_fn(sf); +} + +template <typename F> +inline +__cilk_fake_noinline_wrapper<F> __cilk_fake_make_noinline_wrapper(F&& fn) +{ + return __cilk_fake_noinline_wrapper<F>(static_cast<F&&>(fn)); +} + +// Simulate "_Cilk_spawn expr", where expr must be a function call. +// +// Note: this macro does not correctly construct function arguments. +// According to the ABI specification, function arguments should be evaluated +// before the detach and destroyed after the detach. This macro both +// evaluates and destroys them after the detach. This means that if any part +// of the function argument expression depends on a value that is modified in +// the continuation of the spawn, race will occur between the continuation and +// the argument evaluation. +// +// To work around this problem, this macro accepts an arbitrary list of +// declarations and statements (separated by semicolons) that are evaluated +// before the detach. Thus, to simulate: +// +// _Cilk_spawn f(expr); +// +// one would write: +// +// CILK_FAKE_SPAWN(f(arg), auto arg = expr); +// +// Despite appearing in the reverse order, the 'arg' variable is created and +// initialized before the detach and the call to f(arg) occurs after the +// detach. +#define CILK_FAKE_SPAWN(expr, ...) \ + CILK_FAKE_CALL_SPAWN_HELPER( \ + CILK_FAKE_SPAWN_HELPER(expr, __VA_ARGS__)(&__cilk_sf)) + +// Simulate "ret = cilk_spawn expr". See CILK_FAKE_SPAWN for constraints. +#define CILK_FAKE_SPAWN_R(ret, expr, ...) \ + CILK_FAKE_SPAWN(((ret) = (expr)), __VA_ARGS__) + +// Create a spawn helper as a C++11 lambda function. In addition to the +// expression to spawn, this macro takes a any number of statements to be +// executed before detaching. +#define CILK_FAKE_SPAWN_HELPER(expr, ...) \ + __cilk_fake_make_noinline_wrapper([&](__cilkrts_stack_frame *parent_sf) { \ + CILK_FAKE_SPAWN_HELPER_BODY(*parent_sf, expr, __VA_ARGS__); \ + }) + +// C++ version of a __cilkrts_stack_frame for a spawning function. +// This struct is identical to __cilkrts_stack_frame except that the +// destructor automatically does frame cleanup. +struct __cilk_fake_stack_frame : __cilkrts_stack_frame +{ + // Extension of __cilkrts_stack_frame with constructor and destructor + __cilk_fake_stack_frame() { } + __forceinline ~__cilk_fake_stack_frame() { + CILK_FAKE_CLEANUP_FRAME(*this); + } +}; + +// C++ version of a __cilkrts_stack_frame for a spawn helper. +// This struct is identical to __cilkrts_stack_frame except that the +// destructor automatically does frame cleanup. +struct __cilk_fake_spawn_helper_stack_frame : __cilkrts_stack_frame +{ + // Extension of __cilkrts_stack_frame with constructor and destructor + __cilk_fake_spawn_helper_stack_frame() { worker = 0; } + __forceinline ~__cilk_fake_spawn_helper_stack_frame() { + CILK_FAKE_SPAWN_HELPER_CLEANUP_FRAME(*this); + } +}; +#else +// For C, __cilk_fake_stack_frame and __cilk_fake_spawn_helper_stack_frame are +// identical to __cilkrts_stack_frame. Frame cleanup must be performed +// excplicitly (in CILK_FAKE_EPILOG and CILK_FAKE_SPAWN_HELPER_EPILOG) +typedef __cilkrts_stack_frame __cilk_fake_stack_frame; +typedef __cilkrts_stack_frame __cilk_fake_spawn_helper_stack_frame; +#endif + +#endif // ! defined(INCLUDED_CILK_FAKE_DOT_H) diff --git a/libcilkrts/include/internal/cilk_version.h b/libcilkrts/include/internal/cilk_version.h new file mode 100644 index 00000000000..f628338f7d2 --- /dev/null +++ b/libcilkrts/include/internal/cilk_version.h @@ -0,0 +1,47 @@ +// cilk_version.h +// +// @copyright +// Copyright (C) 2009-2013, Intel Corporation +// All rights reserved. +// +// @copyright +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Intel Corporation nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// @copyright +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +// WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// DO NOT EDIT THIS FILE! +// +// It was automatically generated by cilkrts/include/internal/Makefile + +#define VERSION_MAJOR 2 +#define VERSION_MINOR 0 +#define VERSION_BUILD 3902 +#define VERSION_REV 0 +#define VERSION_STRING "2,0,3902,0" +#define VERSION_HASH "b4e38f4f7e3e" +#define VERSION_BRANCH "v14.0" +#define TBB_REV_NUMBER "" +#define VERSION_YEAR "2013" diff --git a/libcilkrts/include/internal/metacall.h b/libcilkrts/include/internal/metacall.h new file mode 100644 index 00000000000..886f49f9f83 --- /dev/null +++ b/libcilkrts/include/internal/metacall.h @@ -0,0 +1,99 @@ +// -*- C++ -*- + +/* + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + * + * metacall.h + * + * This is an internal header file defining part of the metacall + * interface used by Cilkscreen. It is not a stable API and is + * subject to change without notice. + */ + +// Provides the enum of metacall kinds. This is used by Cilkscreen and the +// runtime, and will probably be used by any future ptools. + +#pragma once + +/////////////////////////////////////////////////////////////////////////////// + +enum +{ + // Notify Cilkscreen to stop/start instrumenting code + HYPER_DISABLE_INSTRUMENTATION = 0, + HYPER_ENABLE_INSTRUMENTATION = 1, + + // Write 0 in *(char *)arg if the p-tool is sequential. The Cilk runtime + // system invokes this metacall to know whether to spawn worker threads. + HYPER_ZERO_IF_SEQUENTIAL_PTOOL = 2, + + // Write 0 in *(char *)arg if the runtime must force reducers to + // call the reduce() method even if no actual stealing occurs. + HYPER_ZERO_IF_FORCE_REDUCE = 3, + + // Inform cilkscreen about the current stack pointer. + HYPER_ESTABLISH_C_STACK = 4, + + // Inform Cilkscreen about the current worker + HYPER_ESTABLISH_WORKER = 5, + + // Tell tools to ignore a block of memory. Parameter is a 2 element + // array: void *block[2] = {_begin, _end}; _end is 1 beyond the end + // of the block to be ignored. Essentially, if p is a pointer to an + // array, _begin = &p[0], _end = &p[max] + HYPER_IGNORE_MEMORY_BLOCK = 6 + + // If you add metacalls here, remember to update BOTH workspan.cpp AND + // cilkscreen-common.cpp! +}; + +typedef struct +{ + unsigned int tool; // Specifies tool metacall is for + // (eg. system=0, cilkscreen=1, cilkview=2). + // All tools should understand system codes. + // Tools should ignore all other codes, except + // their own. + + unsigned int code; // Tool-specific code specifies what to do and how to + // interpret data + + void *data; +} metacall_data_t; + +#define METACALL_TOOL_SYSTEM 0 + +/////////////////////////////////////////////////////////////////////////////// diff --git a/libcilkrts/include/internal/rev.mk b/libcilkrts/include/internal/rev.mk new file mode 100644 index 00000000000..f65ad6d57d0 --- /dev/null +++ b/libcilkrts/include/internal/rev.mk @@ -0,0 +1,41 @@ +######################################################################### +# +# @copyright +# Copyright (C) 2011-2013, Intel Corporation +# All rights reserved. +# +# @copyright +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# @copyright +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +########################################################################### + +# DO NOT EDIT THIS FILE! +# +# It was automatically generated by cilkrts/include/internal/Makefile + +CILK_REVISION = 3902 |