GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
blaswrap.c
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2012-2025 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24////////////////////////////////////////////////////////////////////////
25
26/*
27
28Wrapper for Apple libBLAS.dylib and libLAPACK.dylib
29
30At least on the versions of OSX 10.6 so far (up and including 10.6.6)
31these libraries are incompatible with 64 bit builds, as some functions
32in libBLAS.dylib are not conforming to F2C calling conventions, as
33they should. This breaks them in 64-bit builds on the x86_64
34architecture.
35
36Newer gfortran compilers no longer default to the F2C calling
37convention. These wrappers map the F2C conformant functions in
38libBLAS and libLAPACK to the native gfortran calling convention, so
39that the libraries can be used with software built for x86_64
40architecture.
41
42*/
43
44#if defined (HAVE_CONFIG_H)
45# include "config.h" /* USE_BLASWRAP ? */
46#endif
47
48#if defined (USE_BLASWRAP)
49
50/*
51 * vecLib is an Apple framework (collection of libraries) containing
52 * libBLAS and libLAPACK. The fortran stubs in these libraries are
53 * (mostly, but not completely) in the F2C calling convention.
54 * We access the libraries via the vecLib framework to make sure we
55 * get the Apple versions, rather than some other blas/lapack with the
56 * same name.
57 */
58#if ! defined (VECLIB_FILE)
59# define VECLIB_FILE "/System/Library/Frameworks/vecLib.framework/Versions/A/vecLib"
60#endif
61
62#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
63/*
64 * Since this is a wrapper for fortran functions,
65 * we do not have prototypes for them.
66 */
67# pragma GCC diagnostic ignored "-Wmissing-prototypes"
68#endif
69
70#include <dlfcn.h>
71#include <stdlib.h>
72
73/*
74 * Apple LAPACK follows F2C calling convention,
75 * Convert to normal gfortran calling convention
76 */
77
78static void (*f2c_blas_func[]) (void); /* forward declaration for wrapper */
79static void (*f2c_lapack_func[]) (void); /* forward declaration for wrapper */
80
81/*
82 * LAPACK Wrappers, only need to convert the return value from double to float
83 */
84
85typedef double (*F2C_CALL_0) (void);
86typedef double (*F2C_CALL_1) (void *a1);
87typedef double (*F2C_CALL_2) (void *a1, void *a2);
88typedef double (*F2C_CALL_3) (void *a1, void *a2, void *a3);
89typedef double (*F2C_CALL_4) (void *a1, void *a2, void *a3, void *a4);
90typedef double (*F2C_CALL_5) (void *a1, void *a2, void *a3, void *a4, void *a5);
91typedef double (*F2C_CALL_6) (void *a1, void *a2, void *a3, void *a4, void *a5,
92 void *a6);
93typedef double (*F2C_CALL_7) (void *a1, void *a2, void *a3, void *a4, void *a5,
94 void *a6, void *a7);
95typedef double (*F2C_CALL_8) (void *a1, void *a2, void *a3, void *a4, void *a5,
96 void *a6, void *a7, void *a8);
97
98#define F2C_LAPACK_CALL_8(name) \
99 float name (void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, void *a7, void *a8) \
100 { \
101 return ((F2C_CALL_8)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3, a4, a5, a6, a7, a8); \
102 }
103
104#define F2C_LAPACK_CALL_7(name) \
105 float name (void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, void *a7) \
106 { \
107 return ((F2C_CALL_7)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3, a4, a5, a6, a7); \
108 }
109
110#define F2C_LAPACK_CALL_6(name) \
111 float name (void *a1, void *a2, void *a3, void *a4, void *a5, void *a6) \
112 { \
113 return ((F2C_CALL_6)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3, a4, a5, a6); \
114 }
115
116#define F2C_LAPACK_CALL_5(name) \
117 float name (void *a1, void *a2, void *a3, void *a4, void *a5) \
118 { \
119 return ((F2C_CALL_5)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3, a4, a5); \
120 }
121
122#define F2C_LAPACK_CALL_4(name) \
123 float name (void *a1, void *a2, void *a3, void *a4) \
124 { \
125 return ((F2C_CALL_4)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3, a4); \
126 }
127
128#define F2C_LAPACK_CALL_3(name) \
129 float name (void *a1, void *a2, void *a3) \
130 { \
131 return ((F2C_CALL_3)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3); \
132 }
133
134#define F2C_LAPACK_CALL_2(name) \
135 float name (void *a1, void *a2) \
136 { \
137 return ((F2C_CALL_2)f2c_lapack_func[f2c_ ## name]) (a1, a2); \
138 }
139
140#define F2C_LAPACK_CALL_1(name) \
141 float name (void *a1) \
142 { \
143 return ((F2C_CALL_1)f2c_lapack_func[f2c_ ## name]) (a1); \
144 }
145
146#define F2C_LAPACK_CALL_0(name) \
147 float name (void) \
148 { \
149 return ((F2C_CALL_0)f2c_lapack_func[f2c_ ## name]) (); \
150 }
151
152#define F2C_LAPACK_CALL_NONE(name)
153
154#define F2C_LAPACK_CALL(name, args) F2C_LAPACK_CALL_ ## args (name)
155
156#define ENUM_ITEM(name, args) \
157 f2c_ ## name,
158
159#define NAME_TO_STRING_CASE(name, args) \
160 case f2c_ ## name: return #name;
161
162#define DEFINE_LAPACK_ENUM(name, list) \
163 typedef enum { \
164 list(ENUM_ITEM) \
165 } name; \
166 static const char* \
167 f2c_ ## name ## _name (name n) { \
168 switch (n) { \
169 list(NAME_TO_STRING_CASE) \
170 default: return ""; \
171 } \
172 } \
173 list(F2C_LAPACK_CALL)
174
175#define DEFINE_BLAS_ENUM(name, list) \
176 typedef enum { \
177 list(ENUM_ITEM) \
178 } name; \
179 static const char* \
180 f2c_ ## name ## _name(name n) { \
181 switch (n) { \
182 list(NAME_TO_STRING_CASE) \
183 default: return ""; \
184 } \
185 }
186
187/*
188 * Lapack functions (with argument count) that need the return value
189 * converted from double to float
190 */
191#define LAPACK_LIST(_) \
192 _(clangb_,7) \
193 _(clange_,6) \
194 _(clangt_,5) \
195 _(clanhb_,7) \
196 _(clanhe_,6) \
197 _(clanhp_,5) \
198 _(clanhs_,5) \
199 _(clanht_,4) \
200 _(clansb_,7) \
201 _(clansp_,5) \
202 _(clansy_,6) \
203 _(clantb_,8) \
204 _(clantp_,6) \
205 _(clantr_,8) \
206 _(scsum1_,3) \
207 _(second_,0) \
208 _(slamc3_,2) \
209 _(slamch_,1) \
210 _(slangb_,7) \
211 _(slange_,6) \
212 _(slangt_,5) \
213 _(slanhs_,5) \
214 _(slansb_,7) \
215 _(slansp_,5) \
216 _(slanst_,4) \
217 _(slansy_,6) \
218 _(slantb_,8) \
219 _(slantp_,6) \
220 _(slantr_,8) \
221 _(slapy2_,2) \
222 _(slapy3_,3) \
223 _(LAPACK_COUNT,NONE)
224
225/*
226 * These need a bit more complex wrappers
227 */
228#define BLAS_LIST(_) \
229 _(cdotu_,6) \
230 _(zdotu_,6) \
231 _(cdotc_,6) \
232 _(zdotc_,6) \
233 _(BLAS_COUNT,NONE)
234
235DEFINE_BLAS_ENUM(blas, BLAS_LIST)
236
237DEFINE_LAPACK_ENUM(lapack, LAPACK_LIST)
238
239/*
240 * BLAS wrappers, F2C convention passes returned complex as an extra first
241 * argument
242 */
243typedef struct { float r, i; } complex;
244typedef struct { double r, i; } doublecomplex;
245
246typedef void (*F2C_BLAS_CALL_6) (void *c, void *a1, void *a2, void *a3,
247 void *a4, void *a5);
248
249#define F2C_BLAS_CALL(type, name) \
250type name (void *a1, void *a2, void *a3, void *a4, void *a5) \
251{ \
252 type cplx; \
253 ((F2C_BLAS_CALL_6)f2c_blas_func[f2c_ ## name]) (&cplx, a1, a2, a3, a4, a5); \
254 return cplx; \
255}
256
257F2C_BLAS_CALL(complex, cdotu_)
258F2C_BLAS_CALL(doublecomplex, zdotu_)
259F2C_BLAS_CALL(complex, cdotc_)
260F2C_BLAS_CALL(doublecomplex, zdotc_)
261
262/*
263 * Function pointer arrays, indexed by the enums
264 */
265static void (*f2c_blas_func[f2c_BLAS_COUNT]) (void) = { 0 };
266static void (*f2c_lapack_func[f2c_LAPACK_COUNT]) (void) = { 0 };
267
268/*
269 * Initialization: This is called before main ().
270 * Get the function pointers to the wrapped functions in Apple vecLib
271 */
272
273static void * apple_vecLib = 0;
274
275__attribute__((constructor))
276static void initVecLibWrappers (void)
277{
278 apple_vecLib = dlopen (VECLIB_FILE, RTLD_LOCAL | RTLD_NOLOAD | RTLD_FIRST);
279 if (0 == apple_vecLib)
280 abort ();
281
282 int i;
283 for (i = 0; i < f2c_LAPACK_COUNT; i++)
284 if (0 == (f2c_lapack_func[i] = dlsym (apple_vecLib, f2c_lapack_name(i))))
285 abort ();
286 for (i = 0; i < f2c_BLAS_COUNT; i++)
287 if (0 == (f2c_blas_func[i] = dlsym (apple_vecLib, f2c_blas_name(i))))
288 abort ();
289}
290
291__attribute__((destructor))
292static void finiVecLibWrappers (void)
293{
294 if (apple_vecLib)
295 dlclose (apple_vecLib);
296 apple_vecLib = 0;
297}
298
299#endif /* USE_BLASWRAP */
const octave_base_value & a2