1from __future__ import generators 2import config.base 3 4class Configure(config.base.Configure): 5 def __init__(self, framework): 6 config.base.Configure.__init__(self, framework) 7 self.headerPrefix = '' 8 self.substPrefix = '' 9 self.have__fp16 = 0 10 self.have__float128 = 0 11 return 12 13 def __str1__(self): 14 output = ' Scalar type: ' + self.scalartype + '\n' 15 output += ' Precision: ' + self.precision + '\n' 16 support = [] 17 if self.have__fp16 and not self.precision == '__fp16': support.append('__fp16') 18 if self.have__float128 and not self.precision == '__float128': support.append('__float128') 19 if not len(support) == 0: output += ' Support for ' + ' and '.join(support) + '\n' 20 return output 21 22 def setupHelp(self, help): 23 import nargs 24 # Dec 2016, the __fp16 type is only available with GNU compilers on ARM systems 25 help.addArgument('PETSc', '-with-precision=<__fp16,single,double,__float128>', nargs.Arg(None, 'double', 'Specify numerical precision')) 26 help.addArgument('PETSc', '-with-scalar-type=<real or complex>', nargs.Arg(None, 'real', 'Specify real or complex numbers')) 27 return 28 29 def setupDependencies(self, framework): 30 config.base.Configure.setupDependencies(self, framework) 31 self.types = framework.require('config.types', self) 32 self.languages = framework.require('PETSc.options.languages', self) 33 self.compilers = framework.require('config.compilers', self) 34 self.libraries = framework.require('config.libraries',self) 35 self.setCompilers = framework.require('config.setCompilers', self) 36 self.compilerFlags = framework.require('config.compilerFlags', self) 37 self.types = framework.require('config.types', self) 38 self.headers = framework.require('config.headers', self) 39 self.libraries = framework.require('config.libraries', self) 40 return 41 42 def configureScalarType(self): 43 '''Choose between real and complex numbers''' 44 self.scalartype = self.framework.argDB['with-scalar-type'].lower() 45 if self.scalartype == 'complex': 46 self.addDefine('USE_COMPLEX', '1') 47 if self.languages.clanguage == 'C' and not self.types.c99_complex: 48 raise RuntimeError('C Compiler provided does not support C99 complex') 49 if self.languages.clanguage == 'Cxx' and not self.types.cxx_complex: 50 raise RuntimeError('Cxx compiler provided does not support std::complex') 51 if self.languages.clanguage == 'Cxx': 52 self.addDefine('USE_CXXCOMPLEX',1) 53 elif not self.scalartype == 'real': 54 raise RuntimeError('--with-scalar-type must be real or complex') 55 self.logPrint('Scalar type is '+str(self.scalartype)) 56 # On apple isinf() and isnan() do not work when <complex> is included 57 self.pushLanguage(self.languages.clanguage) 58 if self.scalartype == 'complex' and self.languages.clanguage == 'Cxx': 59 if self.checkLink('#include <math.h>\n#include <complex>\n','double b = 2.0;int a = isnormal(b);(void)a'): 60 self.addDefine('HAVE_ISNORMAL',1) 61 if self.checkLink('#include <math.h>\n#include <complex>\n','double b = 2.0;int a = isnan(b);(void)a'): 62 self.addDefine('HAVE_ISNAN',1) 63 elif self.checkLink('#include <float.h>\n#include <complex>\n','double b = 2.0;int a = _isnan(b);(void)a'): 64 self.addDefine('HAVE__ISNAN',1) 65 if self.checkLink('#include <math.h>\n#include <complex>\n','double b = 2.0;int a = isinf(b);(void)a'): 66 self.addDefine('HAVE_ISINF',1) 67 elif self.checkLink('#include <float.h>\n#include <complex>\n','double b = 2.0;int a = _finite(b);(void)a'): 68 self.addDefine('HAVE__FINITE',1) 69 else: 70 if self.checkLink('#include <math.h>\n','double b = 2.0; int a = isnormal(b);(void)a'): 71 self.addDefine('HAVE_ISNORMAL',1) 72 if self.checkLink('#include <math.h>\n','double b = 2.0; int a = isnan(b);(void)a'): 73 self.addDefine('HAVE_ISNAN',1) 74 elif self.checkLink('#include <float.h>\n','double b = 2.0;int a = _isnan(b);(void)a'): 75 self.addDefine('HAVE__ISNAN',1) 76 if self.checkLink('#include <math.h>\n','double b = 2.0; int a = isinf(b);(void)a'): 77 self.addDefine('HAVE_ISINF',1) 78 elif self.checkLink('#include <float.h>\n','double b = 2.0;int a = _finite(b);(void)a'): 79 self.addDefine('HAVE__FINITE',1) 80 self.popLanguage() 81 return 82 83 def checkNoFiniteMathOnly(self): 84 '''Check if attribute for ignoring finite-math-only optimization is valid, for isnan() and isinf()''' 85 if self.checkCompile('','__attribute__((optimize ("no-finite-math-only"))) int foo(void);'): 86 self.addDefine('HAVE_NO_FINITE_MATH_ONLY',1) 87 88 def configurePrecision(self): 89 '''Set the default real number precision for PETSc objects''' 90 self.log.write('Checking C compiler works with __float128\n') 91 self.have__float128 = 0 92 if self.libraries.check('quadmath','logq',prototype='#include <quadmath.h>',call='__float128 f = 0.0; logq(f)'): 93 self.log.write('C compiler works with quadmath library\n') 94 self.have__float128 = 1 95 if hasattr(self.compilers, 'FC'): 96 self.libraries.pushLanguage('FC') 97 self.log.write('Checking Fortran compiler works with quadmath library\n') 98 if self.libraries.check('quadmath',' ',call = ' real*16 s,w; w = 2.0; s = cos(w)'): 99 self.log.write('Fortran compiler works with quadmath library\n') 100 else: 101 self.have__float128 = 0 102 self.log.write('Fortran compiler fails with quadmath library\n') 103 self.libraries.popLanguage() 104 if hasattr(self.compilers, 'CXX'): 105 self.libraries.pushLanguage('Cxx') 106 isGNU = self.setCompilers.isGNU(self.getCompiler(lang='Cxx'), self.log) 107 # need to bypass g++ error: non-standard suffix on floating constant [-Werror=pedantic] 108 # this warning can't be disabled but is actually never triggered by PETSc 109 if isGNU: 110 self.setCompilers.pushLanguage('Cxx') 111 preprocessorFlagsArg = self.setCompilers.getPreprocessorFlagsArg() 112 oldPreprocessorFlags = getattr(self.setCompilers, preprocessorFlagsArg) 113 setattr(self.setCompilers, preprocessorFlagsArg, oldPreprocessorFlags+' -Wno-error') 114 self.log.write('Checking C++ compiler works with quadmath library\n') 115 if self.libraries.check('quadmath','logq',prototype='#include <quadmath.h>',call='__float128 f = FLT128_EPSILON; logq(f)'): 116 self.log.write('C++ compiler works with quadmath library\n') 117 else: 118 self.have__float128 = 0 119 self.log.write('C++ compiler fails with quadmath library\n') 120 if isGNU: 121 setattr(self.setCompilers, preprocessorFlagsArg, oldPreprocessorFlags) 122 self.setCompilers.popLanguage() 123 self.libraries.popLanguage() 124 if self.have__float128: 125 self.libraries.add('quadmath','logq',prototype='#include <quadmath.h>',call='__float128 f = 0.0; logq(f)') 126 self.addDefine('HAVE_REAL___FLOAT128', '1') 127 128 self.log.write('Checking C compiler works with __fp16\n') 129 self.have__fp16 = 0 130 if self.libraries.check('','',call='__fp16 f = 1.0, g; g = ret___fp16(f); (void)g',prototype='static __fp16 ret___fp16(__fp16 f) { return f; }'): 131 self.have__fp16 = 1 132 self.addDefine('HAVE_REAL___FP16', '1') 133 134 self.precision = self.framework.argDB['with-precision'].lower() 135 if self.precision == '__fp16': # supported by gcc trunk 136 if self.scalartype == 'complex': 137 raise RuntimeError('__fp16 can only be used with real numbers, not complex') 138 if hasattr(self.compilers, 'FC'): 139 raise RuntimeError('__fp16 can only be used with C compiler, not Fortran') 140 if self.have__fp16: 141 self.addDefine('USE_REAL___FP16', '1') 142 self.addMakeMacro('PETSC_SCALAR_SIZE', '16') 143 else: 144 raise RuntimeError('__fp16 support not found, cannot proceed --with-precision=__fp16') 145 elif self.precision == 'single': 146 self.addDefine('USE_REAL_SINGLE', '1') 147 self.addMakeMacro('PETSC_SCALAR_SIZE', '32') 148 elif self.precision == 'double': 149 self.addDefine('USE_REAL_DOUBLE', '1') 150 self.addMakeMacro('PETSC_SCALAR_SIZE', '64') 151 elif self.precision == '__float128': # supported by gcc 4.6/gfortran and later 152 if self.have__float128: 153 self.addDefine('USE_REAL___FLOAT128', '1') 154 self.addMakeMacro('PETSC_SCALAR_SIZE', '128') 155 else: 156 raise RuntimeError('__float128 support not found. --with-precision=__float128 works with gcc-4.6 and newer compilers.') 157 else: 158 raise RuntimeError('--with-precision must be __fp16, single, double, or __float128') 159 self.logPrint('Precision is '+str(self.precision)) 160 return 161 162 def configure(self): 163 self.executeTest(self.configureScalarType) 164 self.executeTest(self.configurePrecision) 165 self.executeTest(self.checkNoFiniteMathOnly) 166 return 167 168 def precisionToBytes(self): 169 d = {'__fp16' : 2, 'single' : 4, 'double' : 8, '__float128' : 16} 170 return d[self.precision] 171