blaswrap.c

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2012 Jarno Rajahalme
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 /*
00024 
00025 Wrapper for Apple libBLAS.dylib and libLAPACK.dylib
00026 
00027 At least on the versions of OSX 10.6 so far (up and including 10.6.6)
00028 these libraries are incompatible with 64 bit builds, as some functions
00029 in libBLAS.dylib are not conforming to F2C calling conventions, as
00030 they should.  This breaks them in 64-bit builds on the x86_64
00031 architecture.
00032 
00033 Newer gfortran compoilers no longer default to the F2C calling
00034 convention.  These wrappers map the F2C conformant functions in
00035 libBLAS and libLAPACK to the native gfortran calling convention, so
00036 that the libraries can be used with software built for x86_64
00037 architecture.
00038  
00039  */
00040 
00041 #ifdef HAVE_CONFIG_H
00042 #include <config.h> /* USE_BLASWRAP ? */
00043 #endif
00044 
00045 #ifdef USE_BLASWRAP
00046 
00047 /*
00048  * vecLib is an Apple framework (collection of libraries) containing
00049  * libBLAS and libLAPACK.  The fortran stubs in these libraries are
00050  * (mostly, but not completely) in the F2C calling convention.
00051  * We access the libraries via the vecLib framework to make sure we 
00052  * get the Apple versions, rather than some other blas/lapack with the
00053  * same name.
00054  */
00055 #ifndef VECLIB_FILE
00056 #define VECLIB_FILE "/System/Library/Frameworks/vecLib.framework/Versions/A/vecLib"
00057 #endif
00058 
00059 /*
00060  * Since this is a wrapper for fortran functions, we do not have prototypes for them.
00061  */
00062 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
00063 
00064 #include <dlfcn.h>
00065 #include <stdlib.h>
00066 
00067 /*
00068  * Apple LAPACK follows F2C calling convention,
00069  * Convert to normal gfortran calling convention
00070  */
00071 
00072 static void (*f2c_blas_func[])(void); /* forward declaration for the wrapper */
00073 static void (*f2c_lapack_func[])(void); /* forward declaration for the wrapper */
00074 
00075 /*
00076  * LAPACK Wrappers, only need to convert the return value from double to float
00077  */
00078 
00079 typedef double (*F2C_CALL_0)(void);
00080 typedef double (*F2C_CALL_1)(void *a1);
00081 typedef double (*F2C_CALL_2)(void *a1, void *a2);
00082 typedef double (*F2C_CALL_3)(void *a1, void *a2, void *a3);
00083 typedef double (*F2C_CALL_4)(void *a1, void *a2, void *a3, void *a4);
00084 typedef double (*F2C_CALL_5)(void *a1, void *a2, void *a3, void *a4, void *a5);
00085 typedef double (*F2C_CALL_6)(void *a1, void *a2, void *a3, void *a4, void *a5, void *a6);
00086 typedef double (*F2C_CALL_7)(void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, void *a7);
00087 typedef double (*F2C_CALL_8)(void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, void *a7, void *a8);
00088 
00089 #define F2C_LAPACK_CALL_8(name) \
00090   float name (void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, void *a7, void *a8) \
00091   {                                                                     \
00092     return ((F2C_CALL_8)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3, a4, a5, a6, a7, a8); \
00093   }
00094 
00095 #define F2C_LAPACK_CALL_7(name) \
00096   float name (void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, void *a7) \
00097   {                                                                     \
00098     return ((F2C_CALL_7)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3, a4, a5, a6, a7); \
00099   }
00100 
00101 #define F2C_LAPACK_CALL_6(name) \
00102   float name (void *a1, void *a2, void *a3, void *a4, void *a5, void *a6) \
00103   {                                                                     \
00104     return ((F2C_CALL_6)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3, a4, a5, a6); \
00105   }
00106 
00107 #define F2C_LAPACK_CALL_5(name) \
00108   float name (void *a1, void *a2, void *a3, void *a4, void *a5)         \
00109   {                                                                     \
00110     return ((F2C_CALL_5)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3, a4, a5); \
00111   }
00112 
00113 #define F2C_LAPACK_CALL_4(name) \
00114   float name (void *a1, void *a2, void *a3, void *a4)                   \
00115   {                                                                     \
00116     return ((F2C_CALL_4)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3, a4); \
00117   }
00118 
00119 #define F2C_LAPACK_CALL_3(name) \
00120   float name (void *a1, void *a2, void *a3)                          \
00121   {                                                                  \
00122     return ((F2C_CALL_3)f2c_lapack_func[f2c_ ## name]) (a1, a2, a3); \
00123   }
00124 
00125 #define F2C_LAPACK_CALL_2(name) \
00126   float name (void *a1, void *a2)                                \
00127   {                                                              \
00128     return ((F2C_CALL_2)f2c_lapack_func[f2c_ ## name]) (a1, a2); \
00129   }
00130 
00131 #define F2C_LAPACK_CALL_1(name) \
00132   float name (void *a1)                                      \
00133   {                                                          \
00134     return ((F2C_CALL_1)f2c_lapack_func[f2c_ ## name]) (a1); \
00135   }
00136 
00137 #define F2C_LAPACK_CALL_0(name) \
00138   float name (void)                                        \
00139   {                                                        \
00140     return ((F2C_CALL_0)f2c_lapack_func[f2c_ ## name]) (); \
00141   }
00142 
00143 #define F2C_LAPACK_CALL_NONE(name)
00144 
00145 #define F2C_LAPACK_CALL(name, args) F2C_LAPACK_CALL_ ## args (name)
00146 
00147 #define ENUM_ITEM(name, args)                   \
00148   f2c_ ## name, 
00149 
00150 #define NAME_TO_STRING_CASE(name, args)         \
00151   case f2c_ ## name: return #name;
00152 
00153 #define DEFINE_LAPACK_ENUM(name, list)  \
00154   typedef enum {                        \
00155     list(ENUM_ITEM)                     \
00156   } name;                               \
00157   static const char*                    \
00158   f2c_ ## name ## _name (name n) {      \
00159     switch (n) {                        \
00160       list(NAME_TO_STRING_CASE)         \
00161     default: return "";                 \
00162     }                                   \
00163   }                                     \
00164   list(F2C_LAPACK_CALL)
00165 
00166 #define DEFINE_BLAS_ENUM(name, list)    \
00167   typedef enum {                        \
00168     list(ENUM_ITEM)                     \
00169   } name;                               \
00170   static const char*                    \
00171   f2c_ ## name ## _name(name n) {       \
00172     switch (n) {                        \
00173       list(NAME_TO_STRING_CASE)         \
00174     default: return "";                 \
00175     }                                   \
00176   }
00177 
00178 /*
00179  * Lapack functions (with argument count) that need the return value
00180  * converted from double to float
00181  */
00182 #define LAPACK_LIST(_)  \
00183   _(clangb_,7)          \
00184   _(clange_,6)          \
00185   _(clangt_,5)          \
00186   _(clanhb_,7)          \
00187   _(clanhe_,6)          \
00188   _(clanhp_,5)          \
00189   _(clanhs_,5)          \
00190   _(clanht_,4)          \
00191   _(clansb_,7)          \
00192   _(clansp_,5)          \
00193   _(clansy_,6)          \
00194   _(clantb_,8)          \
00195   _(clantp_,6)          \
00196   _(clantr_,8)          \
00197   _(scsum1_,3)          \
00198   _(second_,0)          \
00199   _(slamc3_,2)          \
00200   _(slamch_,1)          \
00201   _(slangb_,7)          \
00202   _(slange_,6)          \
00203   _(slangt_,5)          \
00204   _(slanhs_,5)          \
00205   _(slansb_,7)          \
00206   _(slansp_,5)          \
00207   _(slanst_,4)          \
00208   _(slansy_,6)          \
00209   _(slantb_,8)          \
00210   _(slantp_,6)          \
00211   _(slantr_,8)          \
00212   _(slapy2_,2)          \
00213   _(slapy3_,3)          \
00214   _(LAPACK_COUNT,NONE)
00215 
00216 /*
00217  * These need a bit more complex wrappers
00218  */
00219 #define BLAS_LIST(_)    \
00220   _(cdotu_,6)           \
00221   _(zdotu_,6)           \
00222   _(cdotc_,6)           \
00223   _(zdotc_,6)           \
00224   _(BLAS_COUNT,NONE)
00225 
00226 DEFINE_BLAS_ENUM(blas, BLAS_LIST)
00227 
00228 DEFINE_LAPACK_ENUM(lapack, LAPACK_LIST)
00229 
00230 /*
00231  * BLAS wrappers, F2C convention passes retuned complex as an extra first
00232  * argument
00233  */
00234 typedef struct { float r, i; } complex;
00235 typedef struct { double r, i; } doublecomplex;
00236 
00237 typedef void (*F2C_BLAS_CALL_6)(void *c, void *a1, void *a2, void *a3, void *a4, void *a5);
00238 
00239 #define F2C_BLAS_CALL(type, name) \
00240 type name (void *a1, void *a2, void *a3, void *a4, void *a5) \
00241 { \
00242   type cplx; \
00243   ((F2C_BLAS_CALL_6)f2c_blas_func[f2c_ ## name]) (&cplx, a1, a2, a3, a4, a5); \
00244   return cplx; \
00245 }
00246 
00247 F2C_BLAS_CALL(complex, cdotu_)
00248 F2C_BLAS_CALL(doublecomplex, zdotu_)
00249 F2C_BLAS_CALL(complex, cdotc_)
00250 F2C_BLAS_CALL(doublecomplex, zdotc_)
00251 
00252 
00253 /*
00254  * Function pointer arrays, indexed by the enums
00255  */
00256 static void (*f2c_blas_func[f2c_BLAS_COUNT])(void) = { 0 };
00257 static void (*f2c_lapack_func[f2c_LAPACK_COUNT])(void) = { 0 };
00258 
00259 /*
00260  * Initialization: This is called before main ().
00261  * Get the function pointers to the wrapped functions in Apple vecLib
00262  */
00263 
00264 static void * apple_vecLib = 0;
00265 
00266 __attribute__((constructor))
00267 static void initVecLibWrappers (void)
00268 {
00269   apple_vecLib = dlopen (VECLIB_FILE, RTLD_LOCAL | RTLD_NOLOAD | RTLD_FIRST);
00270   if (0 == apple_vecLib)
00271     abort ();
00272 
00273   int i;
00274   for (i = 0; i < f2c_LAPACK_COUNT; i++)
00275     if (0 == (f2c_lapack_func[i] = dlsym(apple_vecLib, f2c_lapack_name(i))))
00276       abort ();  
00277   for (i = 0; i < f2c_BLAS_COUNT; i++)
00278     if (0 == (f2c_blas_func[i] = dlsym(apple_vecLib, f2c_blas_name(i))))
00279       abort ();  
00280 }
00281 
00282 __attribute__((destructor))
00283 static void finiVecLibWrappers (void)
00284 {
00285   if (apple_vecLib)
00286     dlclose (apple_vecLib);
00287   apple_vecLib = 0;
00288 }
00289 
00290 #endif /* USE_BLASWRAP */
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines