Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make real128 optional #93

Closed
wants to merge 2 commits into from
Closed

Conversation

scivision
Copy link
Member

@scivision scivision commented Jan 6, 2020

fixes #88
using Fortran submodule. The Makefiles would need to accommodate these changes

This is a cleaner, more modular approach than #83, which this supercedes.

To use real128, one would do

cmake -B build -DREAL128=true

then this method can be extended for real16 or other "exotic" kinds.


alternatives:

  • generated source code
  • just enclosing large bits of code inside #ifdef

@certik
Copy link
Member

certik commented Jan 6, 2020

Thanks @scivision!

I personally find that the macros make things less readable and more complex to compile. But at the same time, we do want to have the functionality of compiling with Flang, and it is my understanding that unless the quadruple precision is not compiled, Flang will segfault. That is the main motivation of this PR, correct?

I was hoping to avoid using macros much, but there might not be another way.

@scivision
Copy link
Member Author

Flang would still be broken with this (with the 2019 release, not sure about current dev version). Although Flang 2019 release is also missing real128.
This would be for Ifort or others not having real128

@certik
Copy link
Member

certik commented Jan 6, 2020

So unlike Flang, where I think I am fine to simply wait until they fix things, Intel Fortran is essential to support. However, our current master compiles and passes tests (including quadruple precision) just fine with ifort 19.0.4.243:

$ cmake .
-- The Fortran compiler identification is Intel 19.0.4.20190416
...
$ make
...
$ ctest
Test project /users/certik/repos/stdlib
      Start  1: always_skip
 1/10 Test  #1: always_skip ......................***Skipped   0.00 sec
      Start  2: always_fail
 2/10 Test  #2: always_fail ......................   Passed    0.00 sec
      Start  3: ascii
 3/10 Test  #3: ascii ............................   Passed    0.00 sec
      Start  4: loadtxt
 4/10 Test  #4: loadtxt ..........................   Passed    0.01 sec
      Start  5: savetxt
 5/10 Test  #5: savetxt ..........................   Passed    0.02 sec
      Start  6: loadtxt_qp
 6/10 Test  #6: loadtxt_qp .......................   Passed    0.00 sec
      Start  7: savetxt_qp
 7/10 Test  #7: savetxt_qp .......................   Passed    0.01 sec
      Start  8: open
 8/10 Test  #8: open .............................   Passed    0.01 sec
      Start  9: parse_mode
 9/10 Test  #9: parse_mode .......................   Passed    0.00 sec
      Start 10: optval
10/10 Test #10: optval ...........................   Passed    0.00 sec

100% tests passed, 0 tests failed out of 10

Label Time Summary:
quadruple_precision    =   0.02 sec*proc (2 tests)

Total Test time (real) =   0.11 sec

The following tests did not run:
	  1 - always_skip (Skipped)

Which version of Intel Fortran do you have?

@certik
Copy link
Member

certik commented Jan 6, 2020

P.S. I also tried 18.0.5.20180823, 17.0.4.20170411, 16.0.3.20160415 and they all compile our current master and pass all tests.

The version 15.0.4.20150805 fails to compile with the error:

[  3%] Building Fortran object src/CMakeFiles/fortran_stdlib.dir/stdlib_experimental_error.f90.o
/users/certik/repos/stdlib/src/stdlib_experimental_error.f90(7): error #5082: Syntax error, found IDENTIFIER 'ERROR_STOP' when expecting one of: <END-OF-STATEMENT> ;
module subroutine error_stop(msg, code)
------------------^
/users/certik/repos/stdlib/src/stdlib_experimental_error.f90(7): error #5082: Syntax error, found END-OF-STATEMENT when expecting one of: ( % [ . = =>
module subroutine error_stop(msg, code)
---------------------------------------^
...

@scivision
Copy link
Member Author

OK I didn't actually check ifort, I assumed they were using a current version

@scivision
Copy link
Member Author

scivision commented Jan 6, 2020

Intel's list of supported versions: https://software.intel.com/en-us/articles/intel-parallel-studio-xe-supported-and-unsupported-product-versions

Currently version 2019 (19.0.x) and 2020 (19.1.x) are supported.

@scivision
Copy link
Member Author

well in any case, if there were a precision that needed/wanted to be optional, this is a non-generated source way to do it.

@certik
Copy link
Member

certik commented Jan 6, 2020

well in any case, if there were a precision that needed/wanted to be optional, this is a non-generated source way to do it.

Yes, let's discuss how to best do that. I don't see how to significantly simplify the approach in this PR.

If we use jin2for, then the approach we discussed so far was to pre-generate all kinds ahead of time (for all compilers) and create a release tarball. Which wouldn't quite work either, since not all compilers support all kinds. So even with jin2for, we would need some macros to allow to turn kinds on and off.

@zbeekman any ideas how to best handle this?

@zbeekman
Copy link
Member

zbeekman commented Jan 6, 2020

If we use jin2for, then the approach we discussed so far was to pre-generate all kinds ahead of time (for all compilers) and create a release tarball. Which wouldn't quite work either, since not all compilers support all kinds. So even with jin2for, we would need some macros to allow to turn kinds on and off.

This isn't quite true:

Which wouldn't quite work either, since not all compilers support all kinds.

The question becomes: how do we want to use jin2for? Jin2For will use the compiler to enumerate all available kinds from ISO_FORTRAN_ENV's array kinds compile time constants. These all automatically get an alias, a declaration and a kind. The problem (or solution depending on how you look at it) is that Jin2For doesn't assign any meaning to the kinds it finds. For example, if I use Jin2For with GFortran and do something like this:

example.t90

{% for t in real_types %}
{{t.decl}} :: a_{{t.alias}}
real(kind={{t.kind}}) :: b_{{t.alias}}
{% endfor %}

Generate with:

jin2for -g gfortran-8 -e .F90 example.t90

You get:

real(4) :: a_r4
real(kind=4) :: b_r4

real(8) :: a_r8
real(kind=8) :: b_r8

real(10) :: a_r10
real(kind=10) :: b_r10

real(16) :: a_r16
real(kind=16) :: b_r16

As you can see I get a single, double, x86 80-bit and quad precision kind with GFortran. But if you use ifort (and pass -g ifort to jin2for) the emitted code will have only the kinds supported by ifort.

But, you don't have to query the compiler, or use the pre-defined types. The other two options are something like:

integer, parameter :: r32 = selected_real_kind(...
integer, parameter :: r64 = selected_real_kind(...
! ...
{% for t in ["r32", "r64", "r128"] %}
real({{t}}) :: a_{{t}}
real(kind={{t}}) :: b_{{t}}
{% end for %}

Here you don't use any of Jin2For's compiler introspection/kind & type enumeration and you must find a means of coding the introspection yourself or relying on a priori knowledge that all compilers we wish to support have the requested types. But the advantage is that you aren't (hopefuly) generating compiler specific code. It shouldin theory.... run on any compiler. You would have to provide logic through some other means for whether or not you want r128 to be present, probably via CMake.

Alternatively, we could create and maintain the json files that Jin2For generates describing the kinds available from the compiler. These can then be passed to jin2for with the -f flag. This lets you generate code for all the compilers you have json files for. Testing that code, however, is another matter. You need access to the compiler to do this, so, in a way, this is like a bad solution to just querying the compiler for the available kinds. The advantage is that you can ship code to users even if you don't have access to that particular compiler, and the users do not need to run Jin2For. You just need someone to generate the json file.

@zbeekman
Copy link
Member

zbeekman commented Jan 6, 2020

Also, one advantage of approach 1 & 3 (using Jin2For on the client system w/ the client compiler to generate sources, approach 1 or pre-generating sources from all supported compilers via the introspection data) is that you can implement interfaces for all available kinds. As long as there are bugs with the more exotic kinds (a big ask I know) then you don't have to care about single, double, 80-bit, quat precision etc. you just emit code for all possible kinds a given compiler claims to support.

@certik
Copy link
Member

certik commented Jan 6, 2020

I understand that using jin2for at the end user machine would work, as it would simply generate the kinds that are available for the particular compiler.

What I do not understand is how to pre-generate a tarball with already generated sources, so that when the user compiles it, the jin2for tool is not needed. That is what I had in mind doing, but if we have to generate different sources for different compilers, then I don't know how to approach it. Can you give an example how this would work?

@certik
Copy link
Member

certik commented Feb 3, 2020

I think this PR can be closed, as we now have an equivalent feature in master I think.

@certik certik closed this Feb 3, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

test_savetxt_qp fails with ifort
3 participants