| cannam@127 | 1 /* | 
| cannam@127 | 2  * Copyright (c) 2003, 2007-14 Matteo Frigo | 
| cannam@127 | 3  * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology | 
| cannam@127 | 4  * | 
| cannam@127 | 5  * This program is free software; you can redistribute it and/or modify | 
| cannam@127 | 6  * it under the terms of the GNU General Public License as published by | 
| cannam@127 | 7  * the Free Software Foundation; either version 2 of the License, or | 
| cannam@127 | 8  * (at your option) any later version. | 
| cannam@127 | 9  * | 
| cannam@127 | 10  * This program is distributed in the hope that it will be useful, | 
| cannam@127 | 11  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| cannam@127 | 12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| cannam@127 | 13  * GNU General Public License for more details. | 
| cannam@127 | 14  * | 
| cannam@127 | 15  * You should have received a copy of the GNU General Public License | 
| cannam@127 | 16  * along with this program; if not, write to the Free Software | 
| cannam@127 | 17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA | 
| cannam@127 | 18  * | 
| cannam@127 | 19  */ | 
| cannam@127 | 20 | 
| cannam@127 | 21 | 
| cannam@127 | 22 #include "ifftw.h" | 
| cannam@127 | 23 | 
| cannam@127 | 24 #if defined(HAVE_MALLOC_H) | 
| cannam@127 | 25 #  include <malloc.h> | 
| cannam@127 | 26 #endif | 
| cannam@127 | 27 | 
| cannam@127 | 28 /* ``kernel'' malloc(), with proper memory alignment */ | 
| cannam@127 | 29 | 
| cannam@127 | 30 #if defined(HAVE_DECL_MEMALIGN) && !HAVE_DECL_MEMALIGN | 
| cannam@127 | 31 extern void *memalign(size_t, size_t); | 
| cannam@127 | 32 #endif | 
| cannam@127 | 33 | 
| cannam@127 | 34 #if defined(HAVE_DECL_POSIX_MEMALIGN) && !HAVE_DECL_POSIX_MEMALIGN | 
| cannam@127 | 35 extern int posix_memalign(void **, size_t, size_t); | 
| cannam@127 | 36 #endif | 
| cannam@127 | 37 | 
| cannam@127 | 38 #if defined(macintosh) /* MacOS 9 */ | 
| cannam@127 | 39 #  include <Multiprocessing.h> | 
| cannam@127 | 40 #endif | 
| cannam@127 | 41 | 
| cannam@127 | 42 #define real_free free /* memalign and malloc use ordinary free */ | 
| cannam@127 | 43 | 
| cannam@127 | 44 #define IS_POWER_OF_TWO(n) (((n) > 0) && (((n) & ((n) - 1)) == 0)) | 
| cannam@127 | 45 #if defined(WITH_OUR_MALLOC) && (MIN_ALIGNMENT >= 8) && IS_POWER_OF_TWO(MIN_ALIGNMENT) | 
| cannam@127 | 46 /* Our own MIN_ALIGNMENT-aligned malloc/free.  Assumes sizeof(void*) is a | 
| cannam@127 | 47    power of two <= 8 and that malloc is at least sizeof(void*)-aligned. | 
| cannam@127 | 48 | 
| cannam@127 | 49    The main reason for this routine is that, as of this writing, | 
| cannam@127 | 50    Windows does not include any aligned allocation routines in its | 
| cannam@127 | 51    system libraries, and instead provides an implementation with a | 
| cannam@127 | 52    Visual C++ "Processor Pack" that you have to statically link into | 
| cannam@127 | 53    your program.  We do not want to require users to have VC++ | 
| cannam@127 | 54    (e.g. gcc/MinGW should be fine).  Our code should be at least as good | 
| cannam@127 | 55    as the MS _aligned_malloc, in any case, according to second-hand | 
| cannam@127 | 56    reports of the algorithm it employs (also based on plain malloc). */ | 
| cannam@127 | 57 static void *our_malloc(size_t n) | 
| cannam@127 | 58 { | 
| cannam@127 | 59      void *p0, *p; | 
| cannam@127 | 60      if (!(p0 = malloc(n + MIN_ALIGNMENT))) return (void *) 0; | 
| cannam@127 | 61      p = (void *) (((uintptr_t) p0 + MIN_ALIGNMENT) & (~((uintptr_t) (MIN_ALIGNMENT - 1)))); | 
| cannam@127 | 62      *((void **) p - 1) = p0; | 
| cannam@127 | 63      return p; | 
| cannam@127 | 64 } | 
| cannam@127 | 65 static void our_free(void *p) | 
| cannam@127 | 66 { | 
| cannam@127 | 67      if (p) free(*((void **) p - 1)); | 
| cannam@127 | 68 } | 
| cannam@127 | 69 #endif | 
| cannam@127 | 70 | 
| cannam@127 | 71 void *X(kernel_malloc)(size_t n) | 
| cannam@127 | 72 { | 
| cannam@127 | 73      void *p; | 
| cannam@127 | 74 | 
| cannam@127 | 75 #if defined(MIN_ALIGNMENT) | 
| cannam@127 | 76 | 
| cannam@127 | 77 #  if defined(WITH_OUR_MALLOC) | 
| cannam@127 | 78      p = our_malloc(n); | 
| cannam@127 | 79 #    undef real_free | 
| cannam@127 | 80 #    define real_free our_free | 
| cannam@127 | 81 | 
| cannam@127 | 82 #  elif defined(__FreeBSD__) && (MIN_ALIGNMENT <= 16) | 
| cannam@127 | 83      /* FreeBSD does not have memalign, but its malloc is 16-byte aligned. */ | 
| cannam@127 | 84      p = malloc(n); | 
| cannam@127 | 85 | 
| cannam@127 | 86 #  elif (defined(__MACOSX__) || defined(__APPLE__)) && (MIN_ALIGNMENT <= 16) | 
| cannam@127 | 87      /* MacOS X malloc is already 16-byte aligned */ | 
| cannam@127 | 88      p = malloc(n); | 
| cannam@127 | 89 | 
| cannam@127 | 90 #  elif defined(HAVE_MEMALIGN) | 
| cannam@127 | 91      p = memalign(MIN_ALIGNMENT, n); | 
| cannam@127 | 92 | 
| cannam@127 | 93 #  elif defined(HAVE_POSIX_MEMALIGN) | 
| cannam@127 | 94      /* note: posix_memalign is broken in glibc 2.2.5: it constrains | 
| cannam@127 | 95 	the size, not the alignment, to be (power of two) * sizeof(void*). | 
| cannam@127 | 96         The bug seems to have been fixed as of glibc 2.3.1. */ | 
| cannam@127 | 97      if (posix_memalign(&p, MIN_ALIGNMENT, n)) | 
| cannam@127 | 98 	  p = (void*) 0; | 
| cannam@127 | 99 | 
| cannam@127 | 100 #  elif defined(__ICC) || defined(__INTEL_COMPILER) || defined(HAVE__MM_MALLOC) | 
| cannam@127 | 101      /* Intel's C compiler defines _mm_malloc and _mm_free intrinsics */ | 
| cannam@127 | 102      p = (void *) _mm_malloc(n, MIN_ALIGNMENT); | 
| cannam@127 | 103 #    undef real_free | 
| cannam@127 | 104 #    define real_free _mm_free | 
| cannam@127 | 105 | 
| cannam@127 | 106 #  elif defined(_MSC_VER) | 
| cannam@127 | 107      /* MS Visual C++ 6.0 with a "Processor Pack" supports SIMD | 
| cannam@127 | 108 	and _aligned_malloc/free (uses malloc.h) */ | 
| cannam@127 | 109      p = (void *) _aligned_malloc(n, MIN_ALIGNMENT); | 
| cannam@127 | 110 #    undef real_free | 
| cannam@127 | 111 #    define real_free _aligned_free | 
| cannam@127 | 112 | 
| cannam@127 | 113 #  elif defined(macintosh) /* MacOS 9 */ | 
| cannam@127 | 114      p = (void *) MPAllocateAligned(n, | 
| cannam@127 | 115 #    if MIN_ALIGNMENT == 8 | 
| cannam@127 | 116 				    kMPAllocate8ByteAligned, | 
| cannam@127 | 117 #    elif MIN_ALIGNMENT == 16 | 
| cannam@127 | 118 				    kMPAllocate16ByteAligned, | 
| cannam@127 | 119 #    elif MIN_ALIGNMENT == 32 | 
| cannam@127 | 120 				    kMPAllocate32ByteAligned, | 
| cannam@127 | 121 #    else | 
| cannam@127 | 122 #      error "Unknown alignment for MPAllocateAligned" | 
| cannam@127 | 123 #    endif | 
| cannam@127 | 124 				    0); | 
| cannam@127 | 125 #    undef real_free | 
| cannam@127 | 126 #    define real_free MPFree | 
| cannam@127 | 127 | 
| cannam@127 | 128 #  else | 
| cannam@127 | 129      /* Add your machine here and send a patch to fftw@fftw.org | 
| cannam@127 | 130         or (e.g. for Windows) configure --with-our-malloc */ | 
| cannam@127 | 131 #    error "Don't know how to malloc() aligned memory ... try configuring --with-our-malloc" | 
| cannam@127 | 132 #  endif | 
| cannam@127 | 133 | 
| cannam@127 | 134 #else /* !defined(MIN_ALIGNMENT) */ | 
| cannam@127 | 135      p = malloc(n); | 
| cannam@127 | 136 #endif | 
| cannam@127 | 137 | 
| cannam@127 | 138      return p; | 
| cannam@127 | 139 } | 
| cannam@127 | 140 | 
| cannam@127 | 141 void X(kernel_free)(void *p) | 
| cannam@127 | 142 { | 
| cannam@127 | 143      real_free(p); | 
| cannam@127 | 144 } |