1144 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1144 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2003, 2007-14 Matteo Frigo
 | |
|  * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or modify
 | |
|  * it under the terms of the GNU General Public License as published by
 | |
|  * the Free Software Foundation; either version 2 of the License, or
 | |
|  * (at your option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program; if not, write to the Free Software
 | |
|  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 | |
|  *
 | |
|  */
 | |
| 
 | |
| 
 | |
| /* FFTW internal header file */
 | |
| #ifndef __IFFTW_H__
 | |
| #define __IFFTW_H__
 | |
| 
 | |
| #include "config.h"
 | |
| 
 | |
| #include <stdlib.h>		/* size_t */
 | |
| #include <stdarg.h>		/* va_list */
 | |
| #include <stddef.h>             /* ptrdiff_t */
 | |
| #include <limits.h>             /* INT_MAX */
 | |
| 
 | |
| #if HAVE_SYS_TYPES_H
 | |
| # include <sys/types.h>
 | |
| #endif
 | |
| 
 | |
| #if HAVE_STDINT_H
 | |
| # include <stdint.h>             /* uintptr_t, maybe */
 | |
| #endif
 | |
| 
 | |
| #if HAVE_INTTYPES_H
 | |
| # include <inttypes.h>           /* uintptr_t, maybe */
 | |
| #endif
 | |
| 
 | |
| #ifdef __cplusplus
 | |
| extern "C"
 | |
| {
 | |
| #endif /* __cplusplus */
 | |
| 
 | |
| /* Windows annoyances -- since tests/hook.c uses some internal
 | |
|    FFTW functions, we need to given them the dllexport attribute
 | |
|    under Windows when compiling as a DLL (see api/fftw3.h). */
 | |
| #if defined(FFTW_EXTERN)
 | |
| #  define IFFTW_EXTERN FFTW_EXTERN
 | |
| #elif (defined(FFTW_DLL) || defined(DLL_EXPORT)) \
 | |
|  && (defined(_WIN32) || defined(__WIN32__))
 | |
| #  define IFFTW_EXTERN extern __declspec(dllexport)
 | |
| #else
 | |
| #  define IFFTW_EXTERN extern
 | |
| #endif
 | |
| 
 | |
| /* determine precision and name-mangling scheme */
 | |
| #define CONCAT(prefix, name) prefix ## name
 | |
| #if defined(FFTW_SINGLE)
 | |
|   typedef float R;
 | |
| # define X(name) CONCAT(fftwf_, name)
 | |
| #elif defined(FFTW_LDOUBLE)
 | |
|   typedef long double R;
 | |
| # define X(name) CONCAT(fftwl_, name)
 | |
| # define TRIGREAL_IS_LONG_DOUBLE
 | |
| #elif defined(FFTW_QUAD)
 | |
|   typedef __float128 R;
 | |
| # define X(name) CONCAT(fftwq_, name)
 | |
| # define TRIGREAL_IS_QUAD
 | |
| #else
 | |
|   typedef double R;
 | |
| # define X(name) CONCAT(fftw_, name)
 | |
| #endif
 | |
| 
 | |
| /*
 | |
|   integral type large enough to contain a stride (what ``int'' should
 | |
|   have been in the first place.
 | |
| */
 | |
| typedef ptrdiff_t INT;
 | |
| 
 | |
| /* dummy use of unused parameters to silence compiler warnings */
 | |
| #define UNUSED(x) (void)x
 | |
| 
 | |
| #define NELEM(array) ((sizeof(array) / sizeof((array)[0])))
 | |
| 
 | |
| #define FFT_SIGN (-1)  /* sign convention for forward transforms */
 | |
| extern void X(extract_reim)(int sign, R *c, R **r, R **i);
 | |
| 
 | |
| #define REGISTER_SOLVER(p, s) X(solver_register)(p, s)
 | |
| 
 | |
| #define STRINGIZEx(x) #x
 | |
| #define STRINGIZE(x) STRINGIZEx(x)
 | |
| #define CIMPLIES(ante, post) (!(ante) || (post))
 | |
| 
 | |
| /* define HAVE_SIMD if any simd extensions are supported */
 | |
| #if defined(HAVE_SSE) || defined(HAVE_SSE2) || \
 | |
|       defined(HAVE_AVX) || defined(HAVE_AVX_128_FMA) || \
 | |
|       defined(HAVE_AVX2) || defined(HAVE_AVX512) || \
 | |
|       defined(HAVE_KCVI) || \
 | |
|       defined(HAVE_ALTIVEC) || defined(HAVE_VSX) || \
 | |
|       defined(HAVE_MIPS_PS) || \
 | |
|       defined(HAVE_GENERIC_SIMD128) || defined(HAVE_GENERIC_SIMD256)
 | |
| #define HAVE_SIMD 1
 | |
| #else
 | |
| #define HAVE_SIMD 0
 | |
| #endif
 | |
| 
 | |
| extern int X(have_simd_sse2)(void);
 | |
| extern int X(have_simd_avx)(void);
 | |
| extern int X(have_simd_avx_128_fma)(void);
 | |
| extern int X(have_simd_avx2)(void);
 | |
| extern int X(have_simd_avx2_128)(void);
 | |
| extern int X(have_simd_avx512)(void);
 | |
| extern int X(have_simd_altivec)(void);
 | |
| extern int X(have_simd_vsx)(void);
 | |
| extern int X(have_simd_neon)(void);
 | |
| 
 | |
| /* forward declarations */
 | |
| typedef struct problem_s problem;
 | |
| typedef struct plan_s plan;
 | |
| typedef struct solver_s solver;
 | |
| typedef struct planner_s planner;
 | |
| typedef struct printer_s printer;
 | |
| typedef struct scanner_s scanner;
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* alloca: */
 | |
| #if HAVE_SIMD
 | |
| #  if defined(HAVE_KCVI) || defined(HAVE_AVX512)
 | |
| #    define MIN_ALIGNMENT 64
 | |
| #  elif defined(HAVE_AVX) || defined(HAVE_AVX2) || defined(HAVE_GENERIC_SIMD256)
 | |
| #    define MIN_ALIGNMENT 32  /* best alignment for AVX, conservative for
 | |
| 			       * everything else */
 | |
| #  else
 | |
|      /* Note that we cannot use 32-byte alignment for all SIMD.  For
 | |
| 	example, MacOS X malloc is 16-byte aligned, but there was no
 | |
| 	posix_memalign in MacOS X until version 10.6. */
 | |
| #    define MIN_ALIGNMENT 16
 | |
| #  endif
 | |
| #endif
 | |
| 
 | |
| #if defined(HAVE_ALLOCA) && defined(FFTW_ENABLE_ALLOCA)
 | |
|    /* use alloca if available */
 | |
| 
 | |
| #ifndef alloca
 | |
| #ifdef __GNUC__
 | |
| # define alloca __builtin_alloca
 | |
| #else
 | |
| # ifdef _MSC_VER
 | |
| #  include <malloc.h>
 | |
| #  define alloca _alloca
 | |
| # else
 | |
| #  if HAVE_ALLOCA_H
 | |
| #   include <alloca.h>
 | |
| #  else
 | |
| #   ifdef _AIX
 | |
|  #pragma alloca
 | |
| #   else
 | |
| #    ifndef alloca /* predefined by HP cc +Olibcalls */
 | |
| void *alloca(size_t);
 | |
| #    endif
 | |
| #   endif
 | |
| #  endif
 | |
| # endif
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| #  ifdef MIN_ALIGNMENT
 | |
| #    define STACK_MALLOC(T, p, n)				\
 | |
|      {								\
 | |
|          p = (T)alloca((n) + MIN_ALIGNMENT);			\
 | |
|          p = (T)(((uintptr_t)p + (MIN_ALIGNMENT - 1)) &	\
 | |
|                (~(uintptr_t)(MIN_ALIGNMENT - 1)));		\
 | |
|      }
 | |
| #    define STACK_FREE(n) 
 | |
| #  else /* HAVE_ALLOCA && !defined(MIN_ALIGNMENT) */
 | |
| #    define STACK_MALLOC(T, p, n) p = (T)alloca(n) 
 | |
| #    define STACK_FREE(n) 
 | |
| #  endif
 | |
| 
 | |
| #else /* ! HAVE_ALLOCA */
 | |
|    /* use malloc instead of alloca */
 | |
| #  define STACK_MALLOC(T, p, n) p = (T)MALLOC(n, OTHER)
 | |
| #  define STACK_FREE(n) X(ifree)(n)
 | |
| #endif /* ! HAVE_ALLOCA */
 | |
| 
 | |
| /* allocation of buffers.  If these grow too large use malloc(), else
 | |
|    use STACK_MALLOC (hopefully reducing to alloca()). */
 | |
| 
 | |
| /* 64KiB ought to be enough for anybody */
 | |
| #define MAX_STACK_ALLOC ((size_t)64 * 1024)
 | |
| 
 | |
| #define BUF_ALLOC(T, p, n)			\
 | |
| {						\
 | |
|      if (n < MAX_STACK_ALLOC) {			\
 | |
| 	  STACK_MALLOC(T, p, n);		\
 | |
|      } else {					\
 | |
| 	  p = (T)MALLOC(n, BUFFERS);		\
 | |
|      }						\
 | |
| }
 | |
| 
 | |
| #define BUF_FREE(p, n)				\
 | |
| {						\
 | |
|      if (n < MAX_STACK_ALLOC) {			\
 | |
| 	  STACK_FREE(p);			\
 | |
|      } else {					\
 | |
| 	  X(ifree)(p);				\
 | |
|      }						\
 | |
| }
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* define uintptr_t if it is not already defined */
 | |
| 
 | |
| #ifndef HAVE_UINTPTR_T
 | |
| #  if SIZEOF_VOID_P == 0
 | |
| #    error sizeof void* is unknown!
 | |
| #  elif SIZEOF_UNSIGNED_INT == SIZEOF_VOID_P
 | |
|      typedef unsigned int uintptr_t;
 | |
| #  elif SIZEOF_UNSIGNED_LONG == SIZEOF_VOID_P
 | |
|      typedef unsigned long uintptr_t;
 | |
| #  elif SIZEOF_UNSIGNED_LONG_LONG == SIZEOF_VOID_P
 | |
|      typedef unsigned long long uintptr_t;
 | |
| #  else
 | |
| #    error no unsigned integer type matches void* sizeof!
 | |
| #  endif
 | |
| #endif
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* We can do an optimization for copying pairs of (aligned) floats
 | |
|    when in single precision if 2*float = double. */
 | |
| 
 | |
| #define FFTW_2R_IS_DOUBLE (defined(FFTW_SINGLE) \
 | |
|                            && SIZEOF_FLOAT != 0 \
 | |
|                            && SIZEOF_DOUBLE == 2*SIZEOF_FLOAT)
 | |
| 
 | |
| #define DOUBLE_ALIGNED(p) ((((uintptr_t)(p)) % sizeof(double)) == 0)
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* assert.c: */
 | |
| IFFTW_EXTERN void X(assertion_failed)(const char *s, 
 | |
| 				      int line, const char *file);
 | |
| 
 | |
| /* always check */
 | |
| #define CK(ex)						 \
 | |
|       (void)((ex) || (X(assertion_failed)(#ex, __LINE__, __FILE__), 0))
 | |
| 
 | |
| #ifdef FFTW_DEBUG
 | |
| /* check only if debug enabled */
 | |
| #define A(ex)						 \
 | |
|       (void)((ex) || (X(assertion_failed)(#ex, __LINE__, __FILE__), 0))
 | |
| #else
 | |
| #define A(ex) /* nothing */
 | |
| #endif
 | |
| 
 | |
| extern void X(debug)(const char *format, ...);
 | |
| #define D X(debug)
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* kalloc.c: */
 | |
| extern void *X(kernel_malloc)(size_t n);
 | |
| extern void X(kernel_free)(void *p);
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* alloc.c: */
 | |
| 
 | |
| /* objects allocated by malloc, for statistical purposes */
 | |
| enum malloc_tag {
 | |
|      EVERYTHING,
 | |
|      PLANS,
 | |
|      SOLVERS,
 | |
|      PROBLEMS,
 | |
|      BUFFERS,
 | |
|      HASHT,
 | |
|      TENSORS,
 | |
|      PLANNERS,
 | |
|      SLVDESCS,
 | |
|      TWIDDLES,
 | |
|      STRIDES,
 | |
|      OTHER,
 | |
|      MALLOC_WHAT_LAST		/* must be last */
 | |
| };
 | |
| 
 | |
| IFFTW_EXTERN void X(ifree)(void *ptr);
 | |
| extern void X(ifree0)(void *ptr);
 | |
| 
 | |
| IFFTW_EXTERN void *X(malloc_plain)(size_t sz);
 | |
| #define MALLOC(n, what)  X(malloc_plain)(n)
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* low-resolution clock */
 | |
| 
 | |
| #ifdef FAKE_CRUDE_TIME
 | |
|  typedef int crude_time;
 | |
| #else
 | |
| # if TIME_WITH_SYS_TIME
 | |
| #  include <sys/time.h>
 | |
| #  include <time.h>
 | |
| # else
 | |
| #  if HAVE_SYS_TIME_H
 | |
| #   include <sys/time.h>
 | |
| #  else
 | |
| #   include <time.h>
 | |
| #  endif
 | |
| # endif
 | |
| 
 | |
| # ifdef HAVE_BSDGETTIMEOFDAY
 | |
| # ifndef HAVE_GETTIMEOFDAY
 | |
| # define gettimeofday BSDgettimeofday
 | |
| # define HAVE_GETTIMEOFDAY 1
 | |
| # endif
 | |
| # endif
 | |
| 
 | |
| # if defined(HAVE_GETTIMEOFDAY)
 | |
|    typedef struct timeval crude_time;
 | |
| # else
 | |
|    typedef clock_t crude_time;
 | |
| # endif
 | |
| #endif /* else FAKE_CRUDE_TIME */
 | |
| 
 | |
| crude_time X(get_crude_time)(void);
 | |
| double X(elapsed_since)(const planner *plnr, const problem *p,
 | |
| 			crude_time t0); /* time in seconds since t0 */
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* ops.c: */
 | |
| /*
 | |
|  * ops counter.  The total number of additions is add + fma
 | |
|  * and the total number of multiplications is mul + fma.
 | |
|  * Total flops = add + mul + 2 * fma
 | |
|  */
 | |
| typedef struct {
 | |
|      double add;
 | |
|      double mul;
 | |
|      double fma;
 | |
|      double other;
 | |
| } opcnt;
 | |
| 
 | |
| void X(ops_zero)(opcnt *dst);
 | |
| void X(ops_other)(INT o, opcnt *dst);
 | |
| void X(ops_cpy)(const opcnt *src, opcnt *dst);
 | |
| 
 | |
| void X(ops_add)(const opcnt *a, const opcnt *b, opcnt *dst);
 | |
| void X(ops_add2)(const opcnt *a, opcnt *dst);
 | |
| 
 | |
| /* dst = m * a + b */
 | |
| void X(ops_madd)(INT m, const opcnt *a, const opcnt *b, opcnt *dst);
 | |
| 
 | |
| /* dst += m * a */
 | |
| void X(ops_madd2)(INT m, const opcnt *a, opcnt *dst);
 | |
| 
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* minmax.c: */
 | |
| INT X(imax)(INT a, INT b);
 | |
| INT X(imin)(INT a, INT b);
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* iabs.c: */
 | |
| INT X(iabs)(INT a);
 | |
| 
 | |
| /* inline version */
 | |
| #define IABS(x) (((x) < 0) ? (0 - (x)) : (x))
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* md5.c */
 | |
| 
 | |
| #if SIZEOF_UNSIGNED_INT >= 4
 | |
| typedef unsigned int md5uint;
 | |
| #else
 | |
| typedef unsigned long md5uint; /* at least 32 bits as per C standard */
 | |
| #endif
 | |
| 
 | |
| typedef md5uint md5sig[4];
 | |
| 
 | |
| typedef struct {
 | |
|      md5sig s; /* state and signature */
 | |
| 
 | |
|      /* fields not meant to be used outside md5.c: */
 | |
|      unsigned char c[64]; /* stuff not yet processed */
 | |
|      unsigned l;  /* total length.  Should be 64 bits long, but this is
 | |
| 		     good enough for us */
 | |
| } md5;
 | |
| 
 | |
| void X(md5begin)(md5 *p);
 | |
| void X(md5putb)(md5 *p, const void *d_, size_t len);
 | |
| void X(md5puts)(md5 *p, const char *s);
 | |
| void X(md5putc)(md5 *p, unsigned char c);
 | |
| void X(md5int)(md5 *p, int i);
 | |
| void X(md5INT)(md5 *p, INT i);
 | |
| void X(md5unsigned)(md5 *p, unsigned i);
 | |
| void X(md5end)(md5 *p);
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* tensor.c: */
 | |
| #define STRUCT_HACK_KR
 | |
| #undef STRUCT_HACK_C99
 | |
| 
 | |
| typedef struct {
 | |
|      INT n;
 | |
|      INT is;			/* input stride */
 | |
|      INT os;			/* output stride */
 | |
| } iodim;
 | |
| 
 | |
| typedef struct {
 | |
|      int rnk;
 | |
| #if defined(STRUCT_HACK_KR)
 | |
|      iodim dims[1];
 | |
| #elif defined(STRUCT_HACK_C99)
 | |
|      iodim dims[];
 | |
| #else
 | |
|      iodim *dims;
 | |
| #endif
 | |
| } tensor;
 | |
| 
 | |
| /*
 | |
|   Definition of rank -infinity.
 | |
|   This definition has the property that if you want rank 0 or 1,
 | |
|   you can simply test for rank <= 1.  This is a common case.
 | |
|  
 | |
|   A tensor of rank -infinity has size 0.
 | |
| */
 | |
| #define RNK_MINFTY  INT_MAX
 | |
| #define FINITE_RNK(rnk) ((rnk) != RNK_MINFTY)
 | |
| 
 | |
| typedef enum { INPLACE_IS, INPLACE_OS } inplace_kind;
 | |
| 
 | |
| tensor *X(mktensor)(int rnk);
 | |
| tensor *X(mktensor_0d)(void);
 | |
| tensor *X(mktensor_1d)(INT n, INT is, INT os);
 | |
| tensor *X(mktensor_2d)(INT n0, INT is0, INT os0,
 | |
| 		       INT n1, INT is1, INT os1);
 | |
| tensor *X(mktensor_3d)(INT n0, INT is0, INT os0,
 | |
| 		       INT n1, INT is1, INT os1,
 | |
| 		       INT n2, INT is2, INT os2);
 | |
| tensor *X(mktensor_4d)(INT n0, INT is0, INT os0,
 | |
| 		       INT n1, INT is1, INT os1,
 | |
| 		       INT n2, INT is2, INT os2,
 | |
| 		       INT n3, INT is3, INT os3);
 | |
| tensor *X(mktensor_5d)(INT n0, INT is0, INT os0,
 | |
| 		       INT n1, INT is1, INT os1,
 | |
| 		       INT n2, INT is2, INT os2,
 | |
| 		       INT n3, INT is3, INT os3,
 | |
| 		       INT n4, INT is4, INT os4);
 | |
| INT X(tensor_sz)(const tensor *sz);
 | |
| void X(tensor_md5)(md5 *p, const tensor *t);
 | |
| INT X(tensor_max_index)(const tensor *sz);
 | |
| INT X(tensor_min_istride)(const tensor *sz);
 | |
| INT X(tensor_min_ostride)(const tensor *sz);
 | |
| INT X(tensor_min_stride)(const tensor *sz);
 | |
| int X(tensor_inplace_strides)(const tensor *sz);
 | |
| int X(tensor_inplace_strides2)(const tensor *a, const tensor *b);
 | |
| int X(tensor_strides_decrease)(const tensor *sz, const tensor *vecsz,
 | |
|                                inplace_kind k);
 | |
| tensor *X(tensor_copy)(const tensor *sz);
 | |
| int X(tensor_kosherp)(const tensor *x);
 | |
| 
 | |
| tensor *X(tensor_copy_inplace)(const tensor *sz, inplace_kind k);
 | |
| tensor *X(tensor_copy_except)(const tensor *sz, int except_dim);
 | |
| tensor *X(tensor_copy_sub)(const tensor *sz, int start_dim, int rnk);
 | |
| tensor *X(tensor_compress)(const tensor *sz);
 | |
| tensor *X(tensor_compress_contiguous)(const tensor *sz);
 | |
| tensor *X(tensor_append)(const tensor *a, const tensor *b);
 | |
| void X(tensor_split)(const tensor *sz, tensor **a, int a_rnk, tensor **b);
 | |
| int X(tensor_tornk1)(const tensor *t, INT *n, INT *is, INT *os);
 | |
| void X(tensor_destroy)(tensor *sz);
 | |
| void X(tensor_destroy2)(tensor *a, tensor *b);
 | |
| void X(tensor_destroy4)(tensor *a, tensor *b, tensor *c, tensor *d);
 | |
| void X(tensor_print)(const tensor *sz, printer *p);
 | |
| int X(dimcmp)(const iodim *a, const iodim *b);
 | |
| int X(tensor_equal)(const tensor *a, const tensor *b);
 | |
| int X(tensor_inplace_locations)(const tensor *sz, const tensor *vecsz);
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* problem.c: */
 | |
| enum { 
 | |
|      /* a problem that cannot be solved */
 | |
|      PROBLEM_UNSOLVABLE,
 | |
| 
 | |
|      PROBLEM_DFT, 
 | |
|      PROBLEM_RDFT,
 | |
|      PROBLEM_RDFT2,
 | |
| 
 | |
|      /* for mpi/ subdirectory */
 | |
|      PROBLEM_MPI_DFT,
 | |
|      PROBLEM_MPI_RDFT,
 | |
|      PROBLEM_MPI_RDFT2,
 | |
|      PROBLEM_MPI_TRANSPOSE,
 | |
| 
 | |
|      PROBLEM_LAST 
 | |
| };
 | |
| 
 | |
| typedef struct {
 | |
|      int problem_kind;
 | |
|      void (*hash) (const problem *ego, md5 *p);
 | |
|      void (*zero) (const problem *ego);
 | |
|      void (*print) (const problem *ego, printer *p);
 | |
|      void (*destroy) (problem *ego);
 | |
| } problem_adt;
 | |
| 
 | |
| struct problem_s {
 | |
|      const problem_adt *adt;
 | |
| };
 | |
| 
 | |
| problem *X(mkproblem)(size_t sz, const problem_adt *adt);
 | |
| void X(problem_destroy)(problem *ego);
 | |
| problem *X(mkproblem_unsolvable)(void);
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* print.c */
 | |
| struct printer_s {
 | |
|      void (*print)(printer *p, const char *format, ...);
 | |
|      void (*vprint)(printer *p, const char *format, va_list ap);
 | |
|      void (*putchr)(printer *p, char c);
 | |
|      void (*cleanup)(printer *p);
 | |
|      int indent;
 | |
|      int indent_incr;
 | |
| };
 | |
| 
 | |
| printer *X(mkprinter)(size_t size, 
 | |
| 		      void (*putchr)(printer *p, char c),
 | |
| 		      void (*cleanup)(printer *p));
 | |
| IFFTW_EXTERN void X(printer_destroy)(printer *p);
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* scan.c */
 | |
| struct scanner_s {
 | |
|      int (*scan)(scanner *sc, const char *format, ...);
 | |
|      int (*vscan)(scanner *sc, const char *format, va_list ap);
 | |
|      int (*getchr)(scanner *sc);
 | |
|      int ungotc;
 | |
| };
 | |
| 
 | |
| scanner *X(mkscanner)(size_t size, int (*getchr)(scanner *sc));
 | |
| void X(scanner_destroy)(scanner *sc);
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* plan.c: */
 | |
| 
 | |
| enum wakefulness {
 | |
|      SLEEPY,
 | |
|      AWAKE_ZERO,
 | |
|      AWAKE_SQRTN_TABLE,
 | |
|      AWAKE_SINCOS
 | |
| };
 | |
| 
 | |
| typedef struct {
 | |
|      void (*solve)(const plan *ego, const problem *p);
 | |
|      void (*awake)(plan *ego, enum wakefulness wakefulness);
 | |
|      void (*print)(const plan *ego, printer *p);
 | |
|      void (*destroy)(plan *ego);
 | |
| } plan_adt;
 | |
| 
 | |
| struct plan_s {
 | |
|      const plan_adt *adt;
 | |
|      opcnt ops;
 | |
|      double pcost;
 | |
|      enum wakefulness wakefulness; /* used for debugging only */
 | |
|      int could_prune_now_p;
 | |
| };
 | |
| 
 | |
| plan *X(mkplan)(size_t size, const plan_adt *adt);
 | |
| void X(plan_destroy_internal)(plan *ego);
 | |
| IFFTW_EXTERN void X(plan_awake)(plan *ego, enum wakefulness wakefulness);
 | |
| void X(plan_null_destroy)(plan *ego);
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* solver.c: */
 | |
| typedef struct {
 | |
|      int problem_kind;
 | |
|      plan *(*mkplan)(const solver *ego, const problem *p, planner *plnr);
 | |
|      void (*destroy)(solver *ego);
 | |
| } solver_adt;
 | |
| 
 | |
| struct solver_s {
 | |
|      const solver_adt *adt;
 | |
|      int refcnt;
 | |
| };
 | |
| 
 | |
| solver *X(mksolver)(size_t size, const solver_adt *adt);
 | |
| void X(solver_use)(solver *ego);
 | |
| void X(solver_destroy)(solver *ego);
 | |
| void X(solver_register)(planner *plnr, solver *s);
 | |
| 
 | |
| /* shorthand */
 | |
| #define MKSOLVER(type, adt) (type *)X(mksolver)(sizeof(type), adt)
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* planner.c */
 | |
| 
 | |
| typedef struct slvdesc_s {
 | |
|      solver *slv;
 | |
|      const char *reg_nam;
 | |
|      unsigned nam_hash;
 | |
|      int reg_id;
 | |
|      int next_for_same_problem_kind;
 | |
| } slvdesc;
 | |
| 
 | |
| typedef struct solution_s solution; /* opaque */
 | |
| 
 | |
| /* interpretation of L and U: 
 | |
| 
 | |
|    - if it returns a plan, the planner guarantees that all applicable
 | |
|      plans at least as impatient as U have been tried, and that each
 | |
|      plan in the solution is at least as impatient as L.
 | |
|    
 | |
|    - if it returns 0, the planner guarantees to have tried all solvers
 | |
|      at least as impatient as L, and that none of them was applicable.
 | |
| 
 | |
|    The structure is packed to fit into 64 bits.
 | |
| */
 | |
| 
 | |
| typedef struct {
 | |
|      unsigned l:20;
 | |
|      unsigned hash_info:3;
 | |
| #    define BITS_FOR_TIMELIMIT 9
 | |
|      unsigned timelimit_impatience:BITS_FOR_TIMELIMIT;
 | |
|      unsigned u:20;
 | |
|      
 | |
|      /* abstraction break: we store the solver here to pad the
 | |
| 	structure to 64 bits.  Otherwise, the struct is padded to 64
 | |
| 	bits anyway, and another word is allocated for slvndx. */
 | |
| #    define BITS_FOR_SLVNDX 12
 | |
|      unsigned slvndx:BITS_FOR_SLVNDX;
 | |
| } flags_t;
 | |
| 
 | |
| /* impatience flags  */
 | |
| enum {
 | |
|      BELIEVE_PCOST = 0x0001,
 | |
|      ESTIMATE = 0x0002,
 | |
|      NO_DFT_R2HC = 0x0004,
 | |
|      NO_SLOW = 0x0008,
 | |
|      NO_VRECURSE = 0x0010,
 | |
|      NO_INDIRECT_OP = 0x0020,
 | |
|      NO_LARGE_GENERIC = 0x0040,
 | |
|      NO_RANK_SPLITS = 0x0080,
 | |
|      NO_VRANK_SPLITS = 0x0100,
 | |
|      NO_NONTHREADED = 0x0200,
 | |
|      NO_BUFFERING = 0x0400,
 | |
|      NO_FIXED_RADIX_LARGE_N = 0x0800,
 | |
|      NO_DESTROY_INPUT = 0x1000,
 | |
|      NO_SIMD = 0x2000,
 | |
|      CONSERVE_MEMORY = 0x4000,
 | |
|      NO_DHT_R2HC = 0x8000,
 | |
|      NO_UGLY = 0x10000,
 | |
|      ALLOW_PRUNING = 0x20000
 | |
| };
 | |
| 
 | |
| /* hashtable information */
 | |
| enum {
 | |
|      BLESSING = 0x1u,   /* save this entry */
 | |
|      H_VALID = 0x2u,    /* valid hastable entry */
 | |
|      H_LIVE = 0x4u      /* entry is nonempty, implies H_VALID */
 | |
| };
 | |
| 
 | |
| #define PLNR_L(plnr) ((plnr)->flags.l)
 | |
| #define PLNR_U(plnr) ((plnr)->flags.u)
 | |
| #define PLNR_TIMELIMIT_IMPATIENCE(plnr) ((plnr)->flags.timelimit_impatience)
 | |
| 
 | |
| #define ESTIMATEP(plnr) (PLNR_U(plnr) & ESTIMATE)
 | |
| #define BELIEVE_PCOSTP(plnr) (PLNR_U(plnr) & BELIEVE_PCOST)
 | |
| #define ALLOW_PRUNINGP(plnr) (PLNR_U(plnr) & ALLOW_PRUNING)
 | |
| 
 | |
| #define NO_INDIRECT_OP_P(plnr) (PLNR_L(plnr) & NO_INDIRECT_OP)
 | |
| #define NO_LARGE_GENERICP(plnr) (PLNR_L(plnr) & NO_LARGE_GENERIC)
 | |
| #define NO_RANK_SPLITSP(plnr) (PLNR_L(plnr) & NO_RANK_SPLITS)
 | |
| #define NO_VRANK_SPLITSP(plnr) (PLNR_L(plnr) & NO_VRANK_SPLITS)
 | |
| #define NO_VRECURSEP(plnr) (PLNR_L(plnr) & NO_VRECURSE)
 | |
| #define NO_DFT_R2HCP(plnr) (PLNR_L(plnr) & NO_DFT_R2HC)
 | |
| #define NO_SLOWP(plnr) (PLNR_L(plnr) & NO_SLOW)
 | |
| #define NO_UGLYP(plnr) (PLNR_L(plnr) & NO_UGLY)
 | |
| #define NO_FIXED_RADIX_LARGE_NP(plnr) \
 | |
|   (PLNR_L(plnr) & NO_FIXED_RADIX_LARGE_N)
 | |
| #define NO_NONTHREADEDP(plnr) \
 | |
|   ((PLNR_L(plnr) & NO_NONTHREADED) && (plnr)->nthr > 1)
 | |
| 
 | |
| #define NO_DESTROY_INPUTP(plnr) (PLNR_L(plnr) & NO_DESTROY_INPUT)
 | |
| #define NO_SIMDP(plnr) (PLNR_L(plnr) & NO_SIMD)
 | |
| #define CONSERVE_MEMORYP(plnr) (PLNR_L(plnr) & CONSERVE_MEMORY)
 | |
| #define NO_DHT_R2HCP(plnr) (PLNR_L(plnr) & NO_DHT_R2HC)
 | |
| #define NO_BUFFERINGP(plnr) (PLNR_L(plnr) & NO_BUFFERING)
 | |
| 
 | |
| typedef enum { FORGET_ACCURSED, FORGET_EVERYTHING } amnesia;
 | |
| 
 | |
| typedef enum { 
 | |
|      /* WISDOM_NORMAL: planner may or may not use wisdom */
 | |
|      WISDOM_NORMAL, 
 | |
| 
 | |
|      /* WISDOM_ONLY: planner must use wisdom and must avoid searching */
 | |
|      WISDOM_ONLY, 
 | |
| 
 | |
|      /* WISDOM_IS_BOGUS: planner must return 0 as quickly as possible */
 | |
|      WISDOM_IS_BOGUS,
 | |
| 
 | |
|      /* WISDOM_IGNORE_INFEASIBLE: planner ignores infeasible wisdom */
 | |
|      WISDOM_IGNORE_INFEASIBLE,
 | |
| 
 | |
|      /* WISDOM_IGNORE_ALL: planner ignores all */
 | |
|      WISDOM_IGNORE_ALL
 | |
| } wisdom_state_t;
 | |
| 
 | |
| typedef struct {
 | |
|      void (*register_solver)(planner *ego, solver *s);
 | |
|      plan *(*mkplan)(planner *ego, const problem *p);
 | |
|      void (*forget)(planner *ego, amnesia a);
 | |
|      void (*exprt)(planner *ego, printer *p); /* ``export'' is a reserved
 | |
| 						 word in C++. */
 | |
|      int (*imprt)(planner *ego, scanner *sc);
 | |
| } planner_adt;
 | |
| 
 | |
| /* hash table of solutions */
 | |
| typedef struct {
 | |
|      solution *solutions;
 | |
|      unsigned hashsiz, nelem;
 | |
| 
 | |
|      /* statistics */
 | |
|      int lookup, succ_lookup, lookup_iter;
 | |
|      int insert, insert_iter, insert_unknown;
 | |
|      int nrehash;
 | |
| } hashtab;
 | |
| 
 | |
| typedef enum { COST_SUM, COST_MAX } cost_kind;
 | |
| 
 | |
| struct planner_s {
 | |
|      const planner_adt *adt;
 | |
|      void (*hook)(struct planner_s *plnr, plan *pln, 
 | |
| 		  const problem *p, int optimalp);
 | |
|      double (*cost_hook)(const problem *p, double t, cost_kind k);
 | |
|      int (*wisdom_ok_hook)(const problem *p, flags_t flags);
 | |
|      void (*nowisdom_hook)(const problem *p);
 | |
|      wisdom_state_t (*bogosity_hook)(wisdom_state_t state, const problem *p);
 | |
| 
 | |
|      /* solver descriptors */
 | |
|      slvdesc *slvdescs;
 | |
|      unsigned nslvdesc, slvdescsiz;
 | |
|      const char *cur_reg_nam;
 | |
|      int cur_reg_id;
 | |
|      int slvdescs_for_problem_kind[PROBLEM_LAST];
 | |
| 
 | |
|      wisdom_state_t wisdom_state;
 | |
| 
 | |
|      hashtab htab_blessed;
 | |
|      hashtab htab_unblessed;
 | |
| 
 | |
|      int nthr;
 | |
|      flags_t flags;
 | |
| 
 | |
|      crude_time start_time;
 | |
|      double timelimit; /* elapsed_since(start_time) at which to bail out */
 | |
|      int timed_out; /* whether most recent search timed out */
 | |
|      int need_timeout_check;
 | |
| 
 | |
|      /* various statistics */
 | |
|      int nplan;    /* number of plans evaluated */
 | |
|      double pcost, epcost; /* total pcost of measured/estimated plans */
 | |
|      int nprob;    /* number of problems evaluated */
 | |
| };
 | |
| 
 | |
| planner *X(mkplanner)(void);
 | |
| void X(planner_destroy)(planner *ego);
 | |
| 
 | |
| /*
 | |
|   Iterate over all solvers.   Read:
 | |
|  
 | |
|   @article{ baker93iterators,
 | |
|   author = "Henry G. Baker, Jr.",
 | |
|   title = "Iterators: Signs of Weakness in Object-Oriented Languages",
 | |
|   journal = "{ACM} {OOPS} Messenger",
 | |
|   volume = "4",
 | |
|   number = "3",
 | |
|   pages = "18--25"
 | |
|   }
 | |
| */
 | |
| #define FORALL_SOLVERS(ego, s, p, what)			\
 | |
| {							\
 | |
|      unsigned _cnt;					\
 | |
|      for (_cnt = 0; _cnt < ego->nslvdesc; ++_cnt) {	\
 | |
| 	  slvdesc *p = ego->slvdescs + _cnt;		\
 | |
| 	  solver *s = p->slv;				\
 | |
| 	  what;						\
 | |
|      }							\
 | |
| }
 | |
| 
 | |
| #define FORALL_SOLVERS_OF_KIND(kind, ego, s, p, what)		\
 | |
| {								\
 | |
|      int _cnt = ego->slvdescs_for_problem_kind[kind]; 		\
 | |
|      while (_cnt >= 0) {					\
 | |
| 	  slvdesc *p = ego->slvdescs + _cnt;			\
 | |
| 	  solver *s = p->slv;					\
 | |
| 	  what;							\
 | |
| 	  _cnt = p->next_for_same_problem_kind;			\
 | |
|      }								\
 | |
| }
 | |
| 
 | |
| 
 | |
| /* make plan, destroy problem */
 | |
| plan *X(mkplan_d)(planner *ego, problem *p);
 | |
| plan *X(mkplan_f_d)(planner *ego, problem *p, 
 | |
| 		    unsigned l_set, unsigned u_set, unsigned u_reset);
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* stride.c: */
 | |
| 
 | |
| /* If PRECOMPUTE_ARRAY_INDICES is defined, precompute all strides. */
 | |
| #if (defined(__i386__) || defined(__x86_64__) || _M_IX86 >= 500) && !defined(FFTW_LDOUBLE)
 | |
| #define PRECOMPUTE_ARRAY_INDICES
 | |
| #endif
 | |
| 
 | |
| extern const INT X(an_INT_guaranteed_to_be_zero);
 | |
| 
 | |
| #ifdef PRECOMPUTE_ARRAY_INDICES
 | |
| typedef INT *stride;
 | |
| #define WS(stride, i)  (stride[i])
 | |
| extern stride X(mkstride)(INT n, INT s);
 | |
| void X(stride_destroy)(stride p);
 | |
| /* hackery to prevent the compiler from copying the strides array
 | |
|    onto the stack */
 | |
| #define MAKE_VOLATILE_STRIDE(nptr, x) (x) = (x) + X(an_INT_guaranteed_to_be_zero)
 | |
| #else
 | |
| 
 | |
| typedef INT stride;
 | |
| #define WS(stride, i)  (stride * i)
 | |
| #define fftwf_mkstride(n, stride) stride
 | |
| #define fftw_mkstride(n, stride) stride
 | |
| #define fftwl_mkstride(n, stride) stride
 | |
| #define fftwf_stride_destroy(p) ((void) p)
 | |
| #define fftw_stride_destroy(p) ((void) p)
 | |
| #define fftwl_stride_destroy(p) ((void) p)
 | |
| 
 | |
| /* hackery to prevent the compiler from ``optimizing'' induction
 | |
|    variables in codelet loops.  The problem is that for each K and for
 | |
|    each expression of the form P[I + STRIDE * K] in a loop, most
 | |
|    compilers will try to lift an induction variable PK := &P[I + STRIDE * K].
 | |
|    For large values of K this behavior overflows the
 | |
|    register set, which is likely worse than doing the index computation
 | |
|    in the first place.
 | |
| 
 | |
|    If we guess that there are more than
 | |
|    ESTIMATED_AVAILABLE_INDEX_REGISTERS such pointers, we deliberately confuse
 | |
|    the compiler by setting STRIDE ^= ZERO, where ZERO is a value guaranteed to
 | |
|    be 0, but the compiler does not know this. 
 | |
| 
 | |
|    16 registers ought to be enough for anybody, or so the amd64 and ARM ISA's
 | |
|    seem to imply.
 | |
| */
 | |
| #define ESTIMATED_AVAILABLE_INDEX_REGISTERS 16
 | |
| #define MAKE_VOLATILE_STRIDE(nptr, x)                   \
 | |
|      (nptr <= ESTIMATED_AVAILABLE_INDEX_REGISTERS ?     \
 | |
|         0 :                                             \
 | |
|       ((x) = (x) ^ X(an_INT_guaranteed_to_be_zero)))
 | |
| #endif /* PRECOMPUTE_ARRAY_INDICES */
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* solvtab.c */
 | |
| 
 | |
| struct solvtab_s { void (*reg)(planner *); const char *reg_nam; };
 | |
| typedef struct solvtab_s solvtab[];
 | |
| void X(solvtab_exec)(const solvtab tbl, planner *p);
 | |
| #define SOLVTAB(s) { s, STRINGIZE(s) }
 | |
| #define SOLVTAB_END { 0, 0 }
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* pickdim.c */
 | |
| int X(pickdim)(int which_dim, const int *buddies, size_t nbuddies,
 | |
| 	       const tensor *sz, int oop, int *dp);
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* twiddle.c */
 | |
| /* little language to express twiddle factors computation */
 | |
| enum { TW_COS = 0, TW_SIN = 1, TW_CEXP = 2, TW_NEXT = 3, 
 | |
|        TW_FULL = 4, TW_HALF = 5 };
 | |
| 
 | |
| typedef struct {
 | |
|      unsigned char op;
 | |
|      signed char v;
 | |
|      short i;
 | |
| } tw_instr;
 | |
| 
 | |
| typedef struct twid_s {
 | |
|      R *W;                     /* array of twiddle factors */
 | |
|      INT n, r, m;                /* transform order, radix, # twiddle rows */
 | |
|      int refcnt;
 | |
|      const tw_instr *instr;
 | |
|      struct twid_s *cdr;
 | |
|      enum wakefulness wakefulness;
 | |
| } twid;
 | |
| 
 | |
| INT X(twiddle_length)(INT r, const tw_instr *p);
 | |
| void X(twiddle_awake)(enum wakefulness wakefulness,
 | |
| 		      twid **pp, const tw_instr *instr, INT n, INT r, INT m);
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* trig.c */
 | |
| #if defined(TRIGREAL_IS_LONG_DOUBLE)
 | |
|    typedef long double trigreal;
 | |
| #elif defined(TRIGREAL_IS_QUAD)
 | |
|    typedef __float128 trigreal;
 | |
| #else
 | |
|    typedef double trigreal;
 | |
| #endif
 | |
| 
 | |
| typedef struct triggen_s triggen;
 | |
| 
 | |
| struct triggen_s {
 | |
|      void (*cexp)(triggen *t, INT m, R *result);
 | |
|      void (*cexpl)(triggen *t, INT m, trigreal *result);
 | |
|      void (*rotate)(triggen *p, INT m, R xr, R xi, R *res);
 | |
| 
 | |
|      INT twshft;
 | |
|      INT twradix;
 | |
|      INT twmsk;
 | |
|      trigreal *W0, *W1;
 | |
|      INT n;
 | |
| };
 | |
| 
 | |
| triggen *X(mktriggen)(enum wakefulness wakefulness, INT n);
 | |
| void X(triggen_destroy)(triggen *p);
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* primes.c: */
 | |
| 
 | |
| #define MULMOD(x, y, p) \
 | |
|    (((x) <= 92681 - (y)) ? ((x) * (y)) % (p) : X(safe_mulmod)(x, y, p))
 | |
| 
 | |
| INT X(safe_mulmod)(INT x, INT y, INT p);
 | |
| INT X(power_mod)(INT n, INT m, INT p);
 | |
| INT X(find_generator)(INT p);
 | |
| INT X(first_divisor)(INT n);
 | |
| int X(is_prime)(INT n);
 | |
| INT X(next_prime)(INT n);
 | |
| int X(factors_into)(INT n, const INT *primes);
 | |
| int X(factors_into_small_primes)(INT n);
 | |
| INT X(choose_radix)(INT r, INT n);
 | |
| INT X(isqrt)(INT n);
 | |
| INT X(modulo)(INT a, INT n);
 | |
| 
 | |
| #define GENERIC_MIN_BAD 173 /* min prime for which generic becomes bad */
 | |
| 
 | |
| /* thresholds below which certain solvers are considered SLOW.  These are guesses
 | |
|    believed to be conservative */
 | |
| #define GENERIC_MAX_SLOW     16
 | |
| #define RADER_MAX_SLOW       32
 | |
| #define BLUESTEIN_MAX_SLOW   24
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* rader.c: */
 | |
| typedef struct rader_tls rader_tl;
 | |
| 
 | |
| void X(rader_tl_insert)(INT k1, INT k2, INT k3, R *W, rader_tl **tl);
 | |
| R *X(rader_tl_find)(INT k1, INT k2, INT k3, rader_tl *t);
 | |
| void X(rader_tl_delete)(R *W, rader_tl **tl);
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* copy/transposition routines */
 | |
| 
 | |
| /* lower bound to the cache size, for tiled routines */
 | |
| #define CACHESIZE 8192
 | |
| 
 | |
| INT X(compute_tilesz)(INT vl, int how_many_tiles_in_cache);
 | |
| 
 | |
| void X(tile2d)(INT n0l, INT n0u, INT n1l, INT n1u, INT tilesz,
 | |
| 	       void (*f)(INT n0l, INT n0u, INT n1l, INT n1u, void *args),
 | |
| 	       void *args);
 | |
| void X(cpy1d)(R *I, R *O, INT n0, INT is0, INT os0, INT vl);
 | |
| void X(zero1d_pair)(R *O0, R *O1, INT n0, INT os0);
 | |
| void X(cpy2d)(R *I, R *O,
 | |
| 	      INT n0, INT is0, INT os0,
 | |
| 	      INT n1, INT is1, INT os1,
 | |
| 	      INT vl);
 | |
| void X(cpy2d_ci)(R *I, R *O,
 | |
| 		 INT n0, INT is0, INT os0,
 | |
| 		 INT n1, INT is1, INT os1,
 | |
| 		 INT vl);
 | |
| void X(cpy2d_co)(R *I, R *O,
 | |
| 		 INT n0, INT is0, INT os0,
 | |
| 		 INT n1, INT is1, INT os1,
 | |
| 		 INT vl);
 | |
| void X(cpy2d_tiled)(R *I, R *O,
 | |
| 		    INT n0, INT is0, INT os0,
 | |
| 		    INT n1, INT is1, INT os1, 
 | |
| 		    INT vl);
 | |
| void X(cpy2d_tiledbuf)(R *I, R *O,
 | |
| 		       INT n0, INT is0, INT os0,
 | |
| 		       INT n1, INT is1, INT os1, 
 | |
| 		       INT vl);
 | |
| void X(cpy2d_pair)(R *I0, R *I1, R *O0, R *O1,
 | |
| 		   INT n0, INT is0, INT os0,
 | |
| 		   INT n1, INT is1, INT os1);
 | |
| void X(cpy2d_pair_ci)(R *I0, R *I1, R *O0, R *O1,
 | |
| 		      INT n0, INT is0, INT os0,
 | |
| 		      INT n1, INT is1, INT os1);
 | |
| void X(cpy2d_pair_co)(R *I0, R *I1, R *O0, R *O1,
 | |
| 		      INT n0, INT is0, INT os0,
 | |
| 		      INT n1, INT is1, INT os1);
 | |
| 
 | |
| void X(transpose)(R *I, INT n, INT s0, INT s1, INT vl);
 | |
| void X(transpose_tiled)(R *I, INT n, INT s0, INT s1, INT vl);
 | |
| void X(transpose_tiledbuf)(R *I, INT n, INT s0, INT s1, INT vl);
 | |
| 
 | |
| typedef void (*transpose_func)(R *I, INT n, INT s0, INT s1, INT vl);
 | |
| typedef void (*cpy2d_func)(R *I, R *O,
 | |
| 			   INT n0, INT is0, INT os0,
 | |
| 			   INT n1, INT is1, INT os1,
 | |
| 			   INT vl);
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* misc stuff */
 | |
| void X(null_awake)(plan *ego, enum wakefulness wakefulness);
 | |
| double X(iestimate_cost)(const planner *, const plan *, const problem *);
 | |
| 
 | |
| #ifdef FFTW_RANDOM_ESTIMATOR
 | |
| extern unsigned X(random_estimate_seed);
 | |
| #endif
 | |
| 
 | |
| double X(measure_execution_time)(const planner *plnr, 
 | |
| 				 plan *pln, const problem *p);
 | |
| IFFTW_EXTERN int X(ialignment_of)(R *p);
 | |
| unsigned X(hash)(const char *s);
 | |
| INT X(nbuf)(INT n, INT vl, INT maxnbuf);
 | |
| int X(nbuf_redundant)(INT n, INT vl, size_t which, 
 | |
| 		      const INT *maxnbuf, size_t nmaxnbuf);
 | |
| INT X(bufdist)(INT n, INT vl);
 | |
| int X(toobig)(INT n);
 | |
| int X(ct_uglyp)(INT min_n, INT v, INT n, INT r);
 | |
| 
 | |
| #if HAVE_SIMD
 | |
| R *X(taint)(R *p, INT s);
 | |
| R *X(join_taint)(R *p1, R *p2);
 | |
| #define TAINT(p, s) X(taint)(p, s)
 | |
| #define UNTAINT(p) ((R *) (((uintptr_t) (p)) & ~(uintptr_t)3))
 | |
| #define TAINTOF(p) (((uintptr_t)(p)) & 3)
 | |
| #define JOIN_TAINT(p1, p2) X(join_taint)(p1, p2)
 | |
| #else
 | |
| #define TAINT(p, s) (p)
 | |
| #define UNTAINT(p) (p)
 | |
| #define TAINTOF(p) 0
 | |
| #define JOIN_TAINT(p1, p2) p1
 | |
| #endif
 | |
| 
 | |
| #define ASSERT_ALIGNED_DOUBLE  /*unused, legacy*/
 | |
| 
 | |
| /*-----------------------------------------------------------------------*/
 | |
| /* macros used in codelets to reduce source code size */
 | |
| 
 | |
| typedef R E;  /* internal precision of codelets. */
 | |
| 
 | |
| #if defined(FFTW_LDOUBLE)
 | |
| #  define K(x) ((E) x##L)
 | |
| #elif defined(FFTW_QUAD)
 | |
| #  define K(x) ((E) x##Q)
 | |
| #else
 | |
| #  define K(x) ((E) x)
 | |
| #endif
 | |
| #define DK(name, value) const E name = K(value)
 | |
| 
 | |
| /* FMA macros */
 | |
| 
 | |
| #if defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__) || defined(_POWER))
 | |
| /* The obvious expression a * b + c does not work.  If both x = a * b
 | |
|    + c and y = a * b - c appear in the source, gcc computes t = a * b,
 | |
|    x = t + c, y = t - c, thus destroying the fma.
 | |
| 
 | |
|    This peculiar coding seems to do the right thing on all of
 | |
|    gcc-2.95, gcc-3.1, gcc-3.2, and gcc-3.3.  It does the right thing
 | |
|    on gcc-3.4 -fno-web (because the ``web'' pass splits the variable
 | |
|    `x' for the single-assignment form).
 | |
| 
 | |
|    However, gcc-4.0 is a formidable adversary which succeeds in
 | |
|    pessimizing two fma's into one multiplication and two additions.
 | |
|    It does it very early in the game---before the optimization passes
 | |
|    even start.  The only real workaround seems to use fake inline asm
 | |
|    such as
 | |
| 
 | |
|      asm ("# confuse gcc %0" : "=f"(a) : "0"(a));
 | |
|      return a * b + c;
 | |
|      
 | |
|    in each of the FMA, FMS, FNMA, and FNMS functions.  However, this
 | |
|    does not solve the problem either, because two equal asm statements
 | |
|    count as a common subexpression!  One must use *different* fake asm
 | |
|    statements:
 | |
| 
 | |
|    in FMA:
 | |
|      asm ("# confuse gcc for fma %0" : "=f"(a) : "0"(a));
 | |
| 
 | |
|    in FMS:
 | |
|      asm ("# confuse gcc for fms %0" : "=f"(a) : "0"(a));
 | |
| 
 | |
|    etc.
 | |
| 
 | |
|    After these changes, gcc recalcitrantly generates the fma that was
 | |
|    in the source to begin with.  However, the extra asm() cruft
 | |
|    confuses other passes of gcc, notably the instruction scheduler.
 | |
|    (Of course, one could also generate the fma directly via inline
 | |
|    asm, but this confuses the scheduler even more.)
 | |
| 
 | |
|    Steven and I have submitted more than one bug report to the gcc
 | |
|    mailing list over the past few years, to no effect.  Thus, I give
 | |
|    up.  gcc-4.0 can go to hell.  I'll wait at least until gcc-4.3 is
 | |
|    out before touching this crap again.
 | |
| */
 | |
| static __inline__ E FMA(E a, E b, E c)
 | |
| {
 | |
|      E x = a * b;
 | |
|      x = x + c;
 | |
|      return x;
 | |
| }
 | |
| 
 | |
| static __inline__ E FMS(E a, E b, E c)
 | |
| {
 | |
|      E x = a * b;
 | |
|      x = x - c;
 | |
|      return x;
 | |
| }
 | |
| 
 | |
| static __inline__ E FNMA(E a, E b, E c)
 | |
| {
 | |
|      E x = a * b;
 | |
|      x = - (x + c);
 | |
|      return x;
 | |
| }
 | |
| 
 | |
| static __inline__ E FNMS(E a, E b, E c)
 | |
| {
 | |
|      E x = a * b;
 | |
|      x = - (x - c);
 | |
|      return x;
 | |
| }
 | |
| #else
 | |
| #define FMA(a, b, c) (((a) * (b)) + (c))
 | |
| #define FMS(a, b, c) (((a) * (b)) - (c))
 | |
| #define FNMA(a, b, c) (- (((a) * (b)) + (c)))
 | |
| #define FNMS(a, b, c) ((c) - ((a) * (b)))
 | |
| #endif
 | |
| 
 | |
| #ifdef __cplusplus
 | |
| }  /* extern "C" */
 | |
| #endif /* __cplusplus */
 | |
| 
 | |
| #endif /* __IFFTW_H__ */
 | 
