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