GNU Octave  6.2.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-2021 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 compoilers 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 /*
63  * Since this is a wrapper for fortran functions,
64  * we do not have prototypes for them.
65  */
66 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
67 
68 #include <dlfcn.h>
69 #include <stdlib.h>
70 
71 /*
72  * Apple LAPACK follows F2C calling convention,
73  * Convert to normal gfortran calling convention
74  */
75 
76 static void (*f2c_blas_func[]) (void); /* forward declaration for wrapper */
77 static void (*f2c_lapack_func[]) (void); /* forward declaration for wrapper */
78 
79 /*
80  * LAPACK Wrappers, only need to convert the return value from double to float
81  */
82 
83 typedef double (*F2C_CALL_0) (void);
84 typedef double (*F2C_CALL_1) (void *a1);
85 typedef double (*F2C_CALL_2) (void *a1, void *a2);
86 typedef double (*F2C_CALL_3) (void *a1, void *a2, void *a3);
87 typedef double (*F2C_CALL_4) (void *a1, void *a2, void *a3, void *a4);
88 typedef double (*F2C_CALL_5) (void *a1, void *a2, void *a3, void *a4, void *a5);
89 typedef double (*F2C_CALL_6) (void *a1, void *a2, void *a3, void *a4, void *a5,
90  void *a6);
91 typedef double (*F2C_CALL_7) (void *a1, void *a2, void *a3, void *a4, void *a5,
92  void *a6, void *a7);
93 typedef double (*F2C_CALL_8) (void *a1, void *a2, void *a3, void *a4, void *a5,
94  void *a6, void *a7, void *a8);
95 
96 #define F2C_LAPACK_CALL_8(name) \
97  float name (void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, void *a7, void *a8) \
98  { \
99  return ((F2C_CALL_8)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3, a4, a5, a6, a7, a8); \
100  }
101 
102 #define F2C_LAPACK_CALL_7(name) \
103  float name (void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, void *a7) \
104  { \
105  return ((F2C_CALL_7)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3, a4, a5, a6, a7); \
106  }
107 
108 #define F2C_LAPACK_CALL_6(name) \
109  float name (void *a1, void *a2, void *a3, void *a4, void *a5, void *a6) \
110  { \
111  return ((F2C_CALL_6)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3, a4, a5, a6); \
112  }
113 
114 #define F2C_LAPACK_CALL_5(name) \
115  float name (void *a1, void *a2, void *a3, void *a4, void *a5) \
116  { \
117  return ((F2C_CALL_5)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3, a4, a5); \
118  }
119 
120 #define F2C_LAPACK_CALL_4(name) \
121  float name (void *a1, void *a2, void *a3, void *a4) \
122  { \
123  return ((F2C_CALL_4)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3, a4); \
124  }
125 
126 #define F2C_LAPACK_CALL_3(name) \
127  float name (void *a1, void *a2, void *a3) \
128  { \
129  return ((F2C_CALL_3)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3); \
130  }
131 
132 #define F2C_LAPACK_CALL_2(name) \
133  float name (void *a1, void *a2) \
134  { \
135  return ((F2C_CALL_2)f2c_lapack_func[f2c_ ## name]) (a1, a2); \
136  }
137 
138 #define F2C_LAPACK_CALL_1(name) \
139  float name (void *a1) \
140  { \
141  return ((F2C_CALL_1)f2c_lapack_func[f2c_ ## name]) (a1); \
142  }
143 
144 #define F2C_LAPACK_CALL_0(name) \
145  float name (void) \
146  { \
147  return ((F2C_CALL_0)f2c_lapack_func[f2c_ ## name]) (); \
148  }
149 
150 #define F2C_LAPACK_CALL_NONE(name)
151 
152 #define F2C_LAPACK_CALL(name, args) F2C_LAPACK_CALL_ ## args (name)
153 
154 #define ENUM_ITEM(name, args) \
155  f2c_ ## name,
156 
157 #define NAME_TO_STRING_CASE(name, args) \
158  case f2c_ ## name: return #name;
159 
160 #define DEFINE_LAPACK_ENUM(name, list) \
161  typedef enum { \
162  list(ENUM_ITEM) \
163  } name; \
164  static const char* \
165  f2c_ ## name ## _name (name n) { \
166  switch (n) { \
167  list(NAME_TO_STRING_CASE) \
168  default: return ""; \
169  } \
170  } \
171  list(F2C_LAPACK_CALL)
172 
173 #define DEFINE_BLAS_ENUM(name, list) \
174  typedef enum { \
175  list(ENUM_ITEM) \
176  } name; \
177  static const char* \
178  f2c_ ## name ## _name(name n) { \
179  switch (n) { \
180  list(NAME_TO_STRING_CASE) \
181  default: return ""; \
182  } \
183  }
184 
185 /*
186  * Lapack functions (with argument count) that need the return value
187  * converted from double to float
188  */
189 #define LAPACK_LIST(_) \
190  _(clangb_,7) \
191  _(clange_,6) \
192  _(clangt_,5) \
193  _(clanhb_,7) \
194  _(clanhe_,6) \
195  _(clanhp_,5) \
196  _(clanhs_,5) \
197  _(clanht_,4) \
198  _(clansb_,7) \
199  _(clansp_,5) \
200  _(clansy_,6) \
201  _(clantb_,8) \
202  _(clantp_,6) \
203  _(clantr_,8) \
204  _(scsum1_,3) \
205  _(second_,0) \
206  _(slamc3_,2) \
207  _(slamch_,1) \
208  _(slangb_,7) \
209  _(slange_,6) \
210  _(slangt_,5) \
211  _(slanhs_,5) \
212  _(slansb_,7) \
213  _(slansp_,5) \
214  _(slanst_,4) \
215  _(slansy_,6) \
216  _(slantb_,8) \
217  _(slantp_,6) \
218  _(slantr_,8) \
219  _(slapy2_,2) \
220  _(slapy3_,3) \
221  _(LAPACK_COUNT,NONE)
222 
223 /*
224  * These need a bit more complex wrappers
225  */
226 #define BLAS_LIST(_) \
227  _(cdotu_,6) \
228  _(zdotu_,6) \
229  _(cdotc_,6) \
230  _(zdotc_,6) \
231  _(BLAS_COUNT,NONE)
232 
233 DEFINE_BLAS_ENUM(blas, BLAS_LIST)
234 
235 DEFINE_LAPACK_ENUM(lapack, LAPACK_LIST)
236 
237 /*
238  * BLAS wrappers, F2C convention passes returned complex as an extra first
239  * argument
240  */
241 typedef struct { float r, i; } complex;
242 typedef struct { double r, i; } doublecomplex;
243 
244 typedef void (*F2C_BLAS_CALL_6) (void *c, void *a1, void *a2, void *a3,
245  void *a4, void *a5);
246 
247 #define F2C_BLAS_CALL(type, name) \
248 type name (void *a1, void *a2, void *a3, void *a4, void *a5) \
249 { \
250  type cplx; \
251  ((F2C_BLAS_CALL_6)f2c_blas_func[f2c_ ## name]) (&cplx, a1, a2, a3, a4, a5); \
252  return cplx; \
253 }
254 
255 F2C_BLAS_CALL(complex, cdotu_)
256 F2C_BLAS_CALL(doublecomplex, zdotu_)
257 F2C_BLAS_CALL(complex, cdotc_)
258 F2C_BLAS_CALL(doublecomplex, zdotc_)
259 
260 /*
261  * Function pointer arrays, indexed by the enums
262  */
263 static void (*f2c_blas_func[f2c_BLAS_COUNT]) (void) = { 0 };
264 static void (*f2c_lapack_func[f2c_LAPACK_COUNT]) (void) = { 0 };
265 
266 /*
267  * Initialization: This is called before main ().
268  * Get the function pointers to the wrapped functions in Apple vecLib
269  */
270 
271 static void * apple_vecLib = 0;
272 
273 __attribute__((constructor))
274 static void initVecLibWrappers (void)
275 {
276  apple_vecLib = dlopen (VECLIB_FILE, RTLD_LOCAL | RTLD_NOLOAD | RTLD_FIRST);
277  if (0 == apple_vecLib)
278  abort ();
279 
280  int i;
281  for (i = 0; i < f2c_LAPACK_COUNT; i++)
282  if (0 == (f2c_lapack_func[i] = dlsym (apple_vecLib, f2c_lapack_name(i))))
283  abort ();
284  for (i = 0; i < f2c_BLAS_COUNT; i++)
285  if (0 == (f2c_blas_func[i] = dlsym (apple_vecLib, f2c_blas_name(i))))
286  abort ();
287 }
288 
289 __attribute__((destructor))
290 static void finiVecLibWrappers (void)
291 {
292  if (apple_vecLib)
293  dlclose (apple_vecLib);
294  apple_vecLib = 0;
295 }
296 
297 #endif /* USE_BLASWRAP */
T * r
Definition: mx-inlines.cc:773
const octave_base_value & a2