GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
blaswrap.c
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2012-2024 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 
28 Wrapper for Apple libBLAS.dylib and libLAPACK.dylib
29 
30 At least on the versions of OSX 10.6 so far (up and including 10.6.6)
31 these libraries are incompatible with 64 bit builds, as some functions
32 in libBLAS.dylib are not conforming to F2C calling conventions, as
33 they should. This breaks them in 64-bit builds on the x86_64
34 architecture.
35 
36 Newer gfortran compilers no longer default to the F2C calling
37 convention. These wrappers map the F2C conformant functions in
38 libBLAS and libLAPACK to the native gfortran calling convention, so
39 that the libraries can be used with software built for x86_64
40 architecture.
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 
78 static void (*f2c_blas_func[]) (void); /* forward declaration for wrapper */
79 static 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 
85 typedef double (*F2C_CALL_0) (void);
86 typedef double (*F2C_CALL_1) (void *a1);
87 typedef double (*F2C_CALL_2) (void *a1, void *a2);
88 typedef double (*F2C_CALL_3) (void *a1, void *a2, void *a3);
89 typedef double (*F2C_CALL_4) (void *a1, void *a2, void *a3, void *a4);
90 typedef double (*F2C_CALL_5) (void *a1, void *a2, void *a3, void *a4, void *a5);
91 typedef double (*F2C_CALL_6) (void *a1, void *a2, void *a3, void *a4, void *a5,
92  void *a6);
93 typedef double (*F2C_CALL_7) (void *a1, void *a2, void *a3, void *a4, void *a5,
94  void *a6, void *a7);
95 typedef 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 
235 DEFINE_BLAS_ENUM(blas, BLAS_LIST)
236 
237 DEFINE_LAPACK_ENUM(lapack, LAPACK_LIST)
238 
239 /*
240  * BLAS wrappers, F2C convention passes returned complex as an extra first
241  * argument
242  */
243 typedef struct { float r, i; } complex;
244 typedef struct { double r, i; } doublecomplex;
245 
246 typedef 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) \
250 type 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 
257 F2C_BLAS_CALL(complex, cdotu_)
258 F2C_BLAS_CALL(doublecomplex, zdotu_)
259 F2C_BLAS_CALL(complex, cdotc_)
260 F2C_BLAS_CALL(doublecomplex, zdotc_)
261 
262 /*
263  * Function pointer arrays, indexed by the enums
264  */
265 static void (*f2c_blas_func[f2c_BLAS_COUNT]) (void) = { 0 };
266 static 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 
273 static void * apple_vecLib = 0;
274 
275 __attribute__((constructor))
276 static 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))
292 static void finiVecLibWrappers (void)
293 {
294  if (apple_vecLib)
295  dlclose (apple_vecLib);
296  apple_vecLib = 0;
297 }
298 
299 #endif /* USE_BLASWRAP */
T * r
Definition: mx-inlines.cc:781
const octave_base_value & a2