Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28899 Discussions

Incorrect minloc/maxloc results with ifx 2024.0

NCarlson
New Contributor I
4,094 Views

The minloc/maxloc intrinsics return the incorrect result for 0-sized arrays with ifx 2024.0.  Here's an example program.  Note that the classic ifort compiler doesn't suffer from this error.

real :: a(0), b(2,0), c(3)
logical :: mask(3)
integer :: nfail

nfail = 0

! min/maxloc should return 0 for 0-sized arrays
if (maxloc(a,dim=1) /= 0) nfail = nfail + 1
if (minloc(a,dim=1) /= 0) nfail = nfail + 1

if (any(minloc(b) /= [0,0])) nfail = nfail + 1
if (any(maxloc(b) /= [0,0])) nfail = nfail + 1

! min/maxloc should return 0 when all mask values are false
c = [1.0, 2.0, 3.0]
mask = .false.
if (maxloc(c,dim=1,mask=mask) /= 0) nfail = nfail + 1
if (minloc(c,dim=1,mask=mask) /= 0) nfail = nfail + 1

if (nfail > 0) then
  print *, 'failed', nfail, 'tests'
else
  print *, 'passed all tests'
end if

end
0 Kudos
1 Solution
hakostra1
New Contributor II
4,066 Views

I searched around and found this old thread on the topic:

https://community.intel.com/t5/Intel-Fortran-Compiler/Change-in-result-of-MINLOC-MAXLOC-functions-when-all-elements-of/m-p/1125542

I tried your example and it works with '-standard-semantics' flag enabled... I do find it strange that such a flag is needed, though. The default behavior should be to follow the standard, then those that need another behavior should set the appropriate flags... Even just '-stand f18' did not help..

View solution in original post

22 Replies
hakostra1
New Contributor II
4,067 Views

I searched around and found this old thread on the topic:

https://community.intel.com/t5/Intel-Fortran-Compiler/Change-in-result-of-MINLOC-MAXLOC-functions-when-all-elements-of/m-p/1125542

I tried your example and it works with '-standard-semantics' flag enabled... I do find it strange that such a flag is needed, though. The default behavior should be to follow the standard, then those that need another behavior should set the appropriate flags... Even just '-stand f18' did not help..

NCarlson
New Contributor I
3,632 Views

Aha! Thanks for pointing that out. We're working on porting our code from ifort to ifx and we've buried the addition of the`-standard-semantic` flag down in our CMake setup for the Intel compiler but CMake identifies ifx with a different name, so it wasn't being added.  Easy fix.

It drives us nuts that the Intel compiler's default behavior is non-standard.

0 Kudos
NCarlson
New Contributor I
3,569 Views

I think it important to call attention to one of the problems of using  `-standard-semantics`. It implies `-assume std_mod_proc_name` that changes how module procedure names are mangled. This is viral in the sense that other Fortran code must also use the option or linking (involving module procedures) will fail.

 

Since we want standard-conforming behavior in our libraries we forcibly add `-standard-semantics`, but to solve this viral problem also add `-assume nostd_mod_proc_name` unless otherwise directed. The effect is that users who use the default Intel behavior can use the libraries without any problem.  Here's the snippet of CMake code we've used:

add_compile_options(
  "$<$<COMPILE_LANG_AND_ID:Fortran,Intel,IntelLLVM>:-standard-semantics>"
  "$<$<AND:$<NOT:$<BOOL:${ENABLE_STD_MOD_PROC_NAME}>>,$<COMPILE_LANG_AND_ID:Fortran,Intel,IntelLLVM>>:SHELL:-assume nostd_mod_proc_name>"
)

Someone may find this useful.  We're not aware of any other option implied by `-standard-semantics` that is viral like that.  Are there?

0 Kudos
Steve_Lionel
Honored Contributor III
3,641 Views

-stand doesn't change semantics, it controls diagnostics only. The issue is that earlier standards didn't specify what happens with zero-sized arrays, and adding checks for that slows code down. Intel has traditionally been reluctant to make changes that reduce performance, though it has happened (one no longer needs /assume:realloc_lhs, for example).  Changing the default here would slow down everyone's MAXLOC/MINLOC, so there will be some resistance.

0 Kudos
Steve_Lionel
Honored Contributor III
3,618 Views

It would certainly be my preference that the compiler did what the standard says to do by default. It would greatly reduce user complaints and is something I lobbied for when I was at Intel. I know, though, that if the compiler team made those changes, they'd get beat up by other groups who run performance tests and file bug reports when performance slips. A bit of "courage" would combat this. There has been slow but steady progress to that end over the years.

If you have paid support, it would be worthwhile to file a ticket complaining about the non-standard defaults.

0 Kudos
Steve_Lionel
Honored Contributor III
3,557 Views

There can be subtle effects, such as -assume byterecl and -fpscomp logicals. Users of your code should be getting the .mod from the same build as the object file, and that would resolve the name mangling issue.

0 Kudos
NCarlson
New Contributor I
3,544 Views

@Steve_Lionel wrote:

There can be subtle effects, such as -assume byterecl and -fpscomp logicals. Users of your code should be getting the .mod from the same build as the object file, and that would resolve the name mangling issue.


You'd think that would/could be the case, but it turns out not to be so:

$ cat foo.f90
module foo
  private
  type, public :: bar
  contains
    procedure :: init
  end type
contains
  subroutine init(this)
    class(bar), intent(inout) :: this
  end subroutine
end module

$ cat main.f90
use foo
type(bar) :: x
call x%init
end

$ ifort -c -assume std_mod_proc_name foo.f90
$ ifort main.f90 foo.o
ld: /tmp/ifortt1ely5.o: in function `MAIN__':
main.f90:(.text+0x82): undefined reference to `foo_mp_init_'
ld: /tmp/ifortt1ely5.o:(.rodata+0x18): undefined reference to `foo_mp_init_'

 Running nm on foo.o shows the symbol "foo_MP_init_", a different mangling of the module procedure than the compiled main.f90 is expecting.  Same results for ifx 2024.0 too.

 

0 Kudos
Steve_Lionel
Honored Contributor III
3,539 Views

I'd call that a bug.

0 Kudos
jimdempseyatthecove
Honored Contributor III
3,482 Views

The linker provides for multiply named (alias) entry points for a function (procedure). Why didn't the developers provide both naming formats? That would have seemed to have been the proper thing to do.

 

Jim Dempsey

0 Kudos
Steve_Lionel
Honored Contributor III
3,460 Views

The problem is that on Linux (and Mac, I think), the mangled name could conflict with a user name. For example, if I had a module FOO with a subroutine BAR, the mangled name would be foo_mp_bar. I could also write a routine named FOO_MP_BAR that would have the same external name.

The switch changes the mangling to include _MP_ instead of _mp_. Since on Linux names are downcased by default, that won't conflict.

The .mod is supposed to carry the external name of any symbols it defines. If that didn't happen, you'd have issues when using BIND(C,NAME=) or !DIR$ ALIAS.

0 Kudos
NCarlson
New Contributor I
3,468 Views

@Steve_Lionel wrote:

I'd call that a bug.


In that case you might want to take a look, @Barbara_P_Intel 

0 Kudos
FortranFan
Honored Contributor III
3,433 Views

@Barbara_P_Intel  / Intel Team:

Can you please also elaborate how `std_mod_proc_name` is expected to work on Windows?  Is it at all relevant on Windows i.e., is the option only for Linux (and Mac until Intel continues to do anything with it)?  With the example upthread, there appears no difference on Windows which is kinda what I expected (more on this in a follow-up post).

C:\temp>ifort /c /assume:std_mod_proc_name foo.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.10.0 Build 20230609_000000
Copyright (C) 1985-2023 Intel Corporation.  All rights reserved.


C:\temp>ifort main.f90 foo.obj
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.10.0 Build 20230609_000000
Copyright (C) 1985-2023 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.36.32537.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:main.exe
-subsystem:console
main.obj
foo.obj

C:\temp>del foo.obj main.obj main.exe

C:\temp>ifort /c /assume:nostd_mod_proc_name foo.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.10.0 Build 20230609_000000
Copyright (C) 1985-2023 Intel Corporation.  All rights reserved.


C:\temp>ifort main.f90 foo.obj
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.10.0 Build 20230609_000000
Copyright (C) 1985-2023 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.36.32537.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:main.exe
-subsystem:console
main.obj
foo.obj

C:\temp>

 

0 Kudos
FortranFan
Honored Contributor III
3,426 Views

@Barbara_P_Intel / Intel team:

Please also consider the following case: per Intel Fortran team's understanding, what is the expected behavior with IFORT and IFX?

module m
   interface
      subroutine foo() bind(C, name="M_mp_SUB")
      end subroutine 
   end interface
contains
   subroutine sub()
   end subroutine 
end module 

On Windows, no difference is observed.  Is this to be expected?

C:\temp>ifort /c /free /assume:std_mod_proc_name m.f
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.10.0 Build 20230609_000000
Copyright (C) 1985-2023 Intel Corporation.  All rights reserved.


C:\temp>objdump -t m.obj

m.obj:     file format pe-x86-64

SYMBOL TABLE:
[  0](sec  1)(fl 0x00)(ty    0)(scl   3) (nx 1) 0x0000000000000000 .text
AUX scnlen 0x20 nreloc 0 nlnno 0
[  2](sec  1)(fl 0x00)(ty   20)(scl   2) (nx 0) 0x0000000000000000 M.
[  3](sec  1)(fl 0x00)(ty   20)(scl   2) (nx 0) 0x0000000000000010 M_mp_SUB
[  4](sec  0)(fl 0x00)(ty   20)(scl   2) (nx 0) 0x0000000000000000 __ImageBase
[  5](sec  2)(fl 0x00)(ty    0)(scl   3) (nx 1) 0x0000000000000000 .drectve
AUX scnlen 0xb9 nreloc 0 nlnno 0



C:\temp>ifort /c /free /assume:nostd_mod_proc_name m.f
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.10.0 Build 20230609_000000
Copyright (C) 1985-2023 Intel Corporation.  All rights reserved.


C:\temp>objdump -t m.obj

m.obj:     file format pe-x86-64

SYMBOL TABLE:
[  0](sec  1)(fl 0x00)(ty    0)(scl   3) (nx 1) 0x0000000000000000 .text
AUX scnlen 0x20 nreloc 0 nlnno 0
[  2](sec  1)(fl 0x00)(ty   20)(scl   2) (nx 0) 0x0000000000000000 M.
[  3](sec  1)(fl 0x00)(ty   20)(scl   2) (nx 0) 0x0000000000000010 M_mp_SUB
[  4](sec  0)(fl 0x00)(ty   20)(scl   2) (nx 0) 0x0000000000000000 __ImageBase
[  5](sec  2)(fl 0x00)(ty    0)(scl   3) (nx 1) 0x0000000000000000 .drectve
AUX scnlen 0xb9 nreloc 0 nlnno 0
0 Kudos
Steve_Lionel
Honored Contributor III
3,396 Views

It has no effect on Windows and is not needed there. This is why I called out Linux and Mac in my earlier explanation - I probably should have mentioned the Windows aspect for completeness. As @FortranFan shows, the default on Windows is to upcase names but use a lowercase _mp_ in the module symbol name. Yes, you can go out of your way to create a conflicting name, but the idea is that if you just have straightforward, standard Fortran code there should be no conflict.

0 Kudos
Barbara_P_Intel
Employee
3,066 Views

@NCarlson, I can reproduce the undefined reference. Bug filed: CMPLRLLVM-54182.

Curiously, this compiles ok: ifx -assume std_mod_proc_name foo.f90 main.f90

 

 

0 Kudos
Barbara_P_Intel
Employee
3,066 Views

And, ya, this thread sure took a turn! Glad the minloc/maxloc discussion came to a conclusion.



0 Kudos
Barbara_P_Intel
Employee
3,022 Views

I learned something new today. The compiler team looked at the bug report and told me that -assume std_mod_proc_name is also required for the link. I suppose that makes sense. That's not obvious in the DGR (Developer Guide and Reference).

 

0 Kudos
NCarlson
New Contributor I
3,006 Views

That's not entirely accurate and is misleading.  It's not generally that -assume std_mod_proc_name is required on the link line, but that when linking, every source file is compiled with that option or none are -- that's the viral nature of the option.  In my example, if you swap which compilation includes the option you get the same sort of link error.

$ ifort -c foo.f90
$ ifort -assume std_mod_proc_name main.f90 foo.o
ld: /tmp/ifortChjgwU.o: in function `MAIN__':
main.f90:(.text+0x82): undefined reference to `foo_MP_init_'
ld: /tmp/ifortChjgwU.o:(.rodata+0x18): undefined reference to `foo_MP_init_'

I had assumed all along that this was the expected behavior, but others have indicated that it really should not, and need not, be this way. It's not a matter of language conformance, but a "quality of implementation" issue.

0 Kudos
Barbara_P_Intel
Employee
3,009 Views

One more tidbit... -assume std_mod_proc_name is not required to link, but is required for compiling all relevant .o files. In the original reproduction instructions, foo.f90 was compiled with that option, but main.f90 wasn't.

 

0 Kudos
NCarlson
New Contributor I
2,999 Views

Yes, I've known that for years and in my earlier comment I discussed how we've dealt with it, as it poses difficulties for library writers. In response to that @Steve_Lionel said it shouldn't be that way -- the .mod files should convey the correct link symbols.  My example was simply to demonstrate that it doesn't work that way.  Hope this clarifies things a bit.

0 Kudos
Reply