xref: /petsc/config/PETSc/options/scalarTypes.py (revision 226f8a8a5081bc6ad7227cd631662400f0d6e2a0)
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