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__ */
 |