Ieee_arithmetic in NVFORTRAN error

Dear Folks,

I am writing a Fortran code with openACC directives and compiling it with nvfortran.
I need to check if a value is NaN, and therefore I used ieee_is_nan function from ieee_arithmetic module.
When I compile, though, I get the following error:

NVFORTRAN-S-0155-Could not resolve generic procedure ieee_is_nan

The result of nvfortran --version is

nvfortran 22.11-0 64-bit target on x86-64 Linux -tp haswell

ieee_aritthmetic.mod is currently on my computer (Ubuntu 22.04), and I set its folder to export PATH in .bashrc file.

Can someone please help me?
Thanks

Hi riky_cv,

Can someone please help me?

Sure, though can you post a minimal reproducing example so we can see what you’re doing?

The error seems to indicate that you’re trying to pass ieee_is_nan a wrong data type, like an integer. It only accepts real. For example:

% cat test.f90
program foo
  use ieee_arithmetic
  integer i
  print *, ieee_is_nan(i)
end program foo
% nvfortran test.f90
NVFORTRAN-S-0155-Could not resolve generic procedure ieee_is_nan (test.f90: 4)
  0 inform,   0 warnings,   1 severes, 0 fatal for foo

ieee_aritthmetic.mod is currently on my computer (Ubuntu 22.04), and I set its folder to export PATH in .bashrc file.

Not sure what you mean by this. This module file is included with the compilers. Are you using something different than what we provide?

-Mat

Thank you Mat,

Well, the issue is part of a big code, i paste the parts that regard it:

USE ieee_arithmetic
REAL(RP),DEVICE, DIMENSION(3,nnodesx,nnodesy)      :: dspTRIDIS

chk = ZERO
            !$acc parallel loop collapse(2) reduction(+:chk)
            DO k = 1,nnodesy
                DO i = 1,nnodesx
                    IF (((dspTRIDIS(1,i,k)-1 == dspTRIDIS(1,i,k))).or.((dspTRIDIS(2,i,k)-1 == dspTRIDIS(2,i,k))).or.((dspTRIDIS(3,i,k)-1 == dspTRIDIS(3,i,k))).OR. &
                    & (ieee_is_nan(dspTRIDIS(1,i,k))).or.ieee_is_nan(dspTRIDIS(2,i,k)).or.ieee_is_nan(dspTRIDIS(3,i,k))) THEN
                        posTRIDIS(1,i,k) = posTRIDIS(1,i,k) + 1
                        posTRIDIS(2,i,k) = posTRIDIS(2,i,k) + 1
                        posTRIDIS(3,i,k) = posTRIDIS(3,i,k) + 1
                        chk = chk + 1
                    ENDIF
                ENDDO
            ENDDO
            !$acc end parallel loop

(RP is for real precision)

The fact is that the same code works in a colleague’s workstation, who has nvfortran compiler version 22.3, so I fear I am missing something…

-Riky

Hi Riky,

It looks like it’s due to the “DEVICE” attribute. If you remove this and instead use OpenACC data directives then it should work ok. I’ll need to ask engineering if this is an oversight or intentional.

Are you mixing CUDA Fortran and OpenACC or just using “DEVICE” for other reasons?

-Mat

Investigating a bit more, I see that this is a regression in 22.5. Same code works with 22.3. Not sure what happened, but I added a issue report, TPR #33168.

As a work around, you can call the specific runtime function directly to avoid the generic interface. Something like:

#ifdef __NVCOMPILER
    if (__pgi_ieee_is_nan_dev_r8(A(i))) then
#else

For single precision, change “r8” to “r4”.

Thank you Mat,

I tried with your work around, but I get the following error:
NVFORTRAN-S-0155-Illegal call from host code to device subprogram __pgi_ieee_is_nan_dev_r8
I wrote a simple piece of code to test that, you can see it here:

program main

    use ieee_arithmetic

    implicit none

    real(8),device :: a

    a = 0
#ifdef __NVCOMPILER
    if (__pgi_ieee_is_nan_dev_r8(a)) write(*,*) "1. a is NaN"
#endif

    a = a/0
#ifdef
    if (__pgi_ieee_is_nan_dev_r8(a)) write(*,*) "2. a is NaN"
#endif
    
end program main 

Did I miss something? Like some modules or compilation flags?

Thank you,

  • Riky

This is a device only call, so can only be used within an OpenACC compute regions or CUDA Fortran device routine. Here you’re trying to call it from the host.

The intent was for you to put this into the OpenACC “parallel loop” region as shown in your original example.

There was a regression here that has been fixed in our latest release, 23.5. This now works (again).

use ieee_arithmetic
real(8), device, allocatable, dimension(:) :: A
integer, allocatable, dimension(:) :: iA
integer :: i

allocate(A(1024))
allocate(iA(1024))

A = -99.0d0

!$ACC parallel loop
do i=1,1024
if (ieee_is_nan(A(i))) then
iA(i) = 1
else
iA(i) = 0
endif
enddo