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

Another glitch in SELECT CASE

e745200
Beginner
799 Views

Please consider the following simple example

      program tselect
      implicit none
      character(10) :: buf 

      buf=" "
      buf(1:1) = char(0)   ; call getit
      buf(1:1) = ' '       ; call getit
      buf(1:1) = char(255) ; call getit
      stop   

      contains

      subroutine getit
      character(1), parameter :: hex00 = char(  0)
      character(1), parameter :: hexff = char(255)

      integer, parameter :: first_is00      = 0    
      integer, parameter :: first_isff      = 255  
      integer, parameter :: first_isunknown = -1
      integer            :: first_is

      select case ( buf(1:1) )
      case ( hexff ); first_is = first_isff
      case ( hex00 ); first_is = first_is00
      case default  ; first_is = first_isunknown
      end select
      print *, "using select case, I get ", first_is

      if      (buf(1:1)==hexff) then ; first_is = first_isff
      else if (buf(1:1)==hex00) then ; first_is = first_is00
      else                           ; first_is = first_isunknown
      end if 
      print *, "using if ladder  , I get ", first_is
      end subroutine getit

      end program tselect

 

Compiling it with Intel Fortran compiler 19.0.3, it does not work correctly :
 

Intel(R) Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 19.0.3.199 Build 20190206
Copyright (C) 1985-2019 Intel Corporation.  All rights reserved.

 using select case, I get            0
 using if ladder  , I get            0

 using select case, I get           -1
 using if ladder  , I get           -1

 using select case, I get           -1   <<<
 using if ladder  , I get          255

 

I tested some older version I still have at hand, and I found that the Version 18.0.1.163 Build 20171018  also gives wrong results, while the version 17 used to work fine:

Intel(R) Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 17.0.1.132 Build 20161005
Copyright (C) 1985-2016 Intel Corporation.  All rights reserved.

 Intel(R) Fortran 17.0-1632
GNU ld version 2.20.51.0.2-5.48.el6 20100205
+ ./a.out
 using select case, I get            0
 using if ladder  , I get            0

 using select case, I get           -1
 using if ladder  , I get           -1

 using select case, I get          255   <<<<
 using if ladder  , I get          255

I do not know if, and why, for some reason, the SELECT CASE construct is not implemented exactly in the same way of the semantically equivalent IF-THEN-ELSE ladder, but I would expect the same results anyway.
I hope the previous (exact, I guess) behavior will be reinstated soon.
For the sake of readability, I made plenty of changes from IF/THEN construct to SELECT CASE construct in the legacy code I'm working on, expecially to avoid compound logical expression. And I'm afraid that using new (apparently wrong) versions of the compiler will break it.

I don't get any message even using the options

-stand f03 -warn all -check all

Please let me know if there is something wrong or not standard-compliant in my code.

Tanks a lot for your attention.

GM

0 Kudos
9 Replies
Juergen_R_R
Valued Contributor I
799 Views

This looks very much like a regression in ifort, could you please report this to the Intel Support Center.

0 Kudos
FortranFan
Honored Contributor II
799 Views

e745200 wrote:

.. let me know if there is something .. not standard-compliant in my code ..

As suggested upthread, your request for support with Intel can get you best feedback in terms of Intel compiler.

However, my take is your code is in a grey area when it comes to the Fortran standard which says for CHAR intrinsic the input argument I "shall be of type integer with a value in the range 0 ≤ I ≤ n−1, where n is the number of characters in the collating sequence associated with the specified kind type parameter".  Should a processor use base ASCII for its supported collating sequence, then the standard says "The collating sequence for the ASCII character kind is as specified in ISO/IEC 646:1991 (International Reference Version)".  Now ISO/IEC 646:1991 "specifies a set of 128 control and graphic characters such as letters, digits and symbols with their coded representation."  So with such a sequence, the actual argument to CHAR can be an integer i such that 0 <= i <= 127.  You appear to be getting into the EXTENDED ASCII character set with your value of 255 in the offending situation.  So Intel Fortran support staff can best inform you whether that would be part of its supported collating sequence for its character set.

 

0 Kudos
Juergen_R_R
Valued Contributor I
798 Views

That is actually a good point. The Intel documentation for Parallel Studio 19 mentions: "The ASCII character set contains characters with decimal values 0 through 127". That is for Linux and MAC OS X. On Windows that might be different. Unfortunately, the ifort 17 documentation is no longer online to cross-check.

0 Kudos
e745200
Beginner
799 Views

Thanks for your remarks.
However, in the example I've used char() just for simplicity, because the original lines in my program were:
 

      character(1) :: char0  = transfer(z'00', "a")
      character(1) :: charFF = transfer(z'FF', "a")

(older versions featured an EQUIVALENCEing between character an integers, which are no longer standard-compliant, so I removed them).

And there are two counterfacts; a weaker one: it used to work up to version 17, and it works using other compilers;  and a much stronger one: if the problem is in the value used, how is that the direct comparison in the IF statement works, while the CASE() statement doesn't ?

Also: in case of a domain problem in the function CHAR, I would also expect at least a remark at compile time, given that the arguments are constants, or an error/warning at runtime ( having used -warn all -check all ).

However, you might be right, in some extent. According to the documentation, the hex value "FF" does not represent anything belonging to the domain of the "characters" in Intel Fortran Compiler for Linux, so, strictly speaking, any operation on such an entity might be regarded as undetermined and unreliable. In this case, should I expect that even the logical comparison will stop working in the future, as the CASE() did ?

Even reading the contents of a binary file into a character buffer? Sould be this the case (my example is a small part of a much more complex bynary file processing) I think the best think would be rewriting this part of the program in C. But this would be a huge and unworthy effort!


Thanks again.



 

0 Kudos
jimdempseyatthecove
Honored Contributor III
799 Views

Why not use INTEGER(1), or the C-Interopt equivalent:

use, intrinsic :: iso_c_binding
integer(C_INT8_T) :: char0 = 0
integer(C_INT8_T) :: charFF = z'FF'

Jim Dempsey

 

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
799 Views

BTW this also requires you to re-type the characters in your READ and elsewhere. This is likely a lot easier to do than to port some code to C.

Jim Dempsey

0 Kudos
e745200
Beginner
799 Views

jimdempseyatthecove wrote:

BTW this also requires you to re-type the characters in your READ and elsewhere. This is likely a lot easier to do than to port some code to C.

Jim Dempsey

Thanks, Jim. I will ponder your suggestions (which look very reasonable) starting from an estimation of the impact this change would have on the whole related part of the program.
I knew that removing the non-standard EQUIVALENCEing in that spot was just touching the surface of the problem, and that being fully standard-compliant would have needed a more profound rewriting of the code. I'll try to find the most practical solution.
Thanks again.
GM

 

0 Kudos
FortranFan
Honored Contributor II
799 Views

.. in the example I've used char() just for simplicity, because the original lines in my program were:

..
character(1) :: charFF = transfer(z'FF', "a")

..  In this case, should I expect that even the logical comparison will stop working in the future, as the CASE() did ?

Even reading the contents of a binary file into a character buffer? Sould be this the case (my example is a small part of a much more complex bynary file processing) ..

Keep in mind constraint C7109 (R764) per Fortran 2018 standard states, "A boz-literal-constant shall appear only as a data-stmt-constant in a DATA statement, or where explicitly allowed in 16.9 as an actual argument of an intrinsic procedure." 

Note SOURCE dummy argument (first parameter) in the intrinsic procedure TRANSFER is not marked as allowing a boz-literal-constant.  Thus the original line in the program with TRANSFER technically does not conform to the Fortran standard.  By the way, INT intrinsic in the standard for conversion to integer type explicitly states acceptance of a boz-literal-constant.  You may be better off with using 32-bit integers for your data:

integer, parameter :: charFF = int( z"FF", kind=kind(charFF) )

You can then employ intrinsic procedures toward BITWISE manipulations with your data e.g., BTEST, IBITS, IBSET, etc. 

But note in principle, the use of CHARACTER type to "hold" bits of data is alright, where you may run into issues is with determining the storage sizes, the use of other intrinsics with objects of such type and other operations like in the original post with CHAR and SELECT CASE (but again, do make support request to inform yourself on Intel Fortran team's views on the matter).

Re: "my example is a small part of a much more complex bynary file processing," can you elaborate on the broad sketches of your needs (you can omit any sensitive details)?  Readers may then be able to comment on standard Fortran facilities toward your processing.

 

0 Kudos
Ron_Green
Moderator
799 Views

as for differences in v17 versus v18 and v19:  we've got a bug report opened on this:  After 17 a change was done that introduced a bug in comparisons for extended ASCII characters values 128-255 in SELECT CASE (maybe other comparisons too). Should get a fix in a future release that will get the v17 compiler behavior back.

 

0 Kudos
Reply