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

BUG: comparing INT*2PARAMETER with INT*4. X8000 - porting OpenVMS to iFORT

JP_SECTOR7_COM
New Contributor I
1,004 Views

We came across the following difference between OpenVMS FORTRAN and Ifort which seem like an ifort compiler bug.

Our Fortran Porting Tool detects and fixes occurrences - but - wanted to share.

I understand that the new fortran spec insists on INT('8000'X,2) = but - if this is a problem the ifort compiler should really "say" something.

PROGRAM rick
INTEGER*2 Int2
INTEGER*2 undef_i2ko
INTEGER*4 Int4
PARAMETER (undef_i2ko = '8000'X) ! DOESNT WORK
!PARAMETER (undef_i2ko = -32768) WORKS
!PARAMETER (undef_i2ko = INT('8000'X,2)) WORKS
Int2 = undef_i2ko
Int4 = Int2
write (*,'(" undef_i2ko : ",1Z4.4,I10)') undef_i2ko, undef_i2ko
write (*,'(" Int2 : ",1Z4.4,I10)') Int2, Int2
write (*,'(" Int4 : ",1Z8.8, I10)') Int4, Int4
! ===========================================================
! seem to substitute X8000 for undef_i2ko and not sign extend
! ===========================================================
IF (Int4 .NE. undef_i2ko) THEN
WRITE(*,*)' IF (Int4 .NE. undef_i2ko) Should not happen'
ELSE
WRITE(*,*)'seems ok'
ENDIF
END

iFORT:
undef_i2ko : 8000 -32768
Int2 : 8000 -32768
Int4 : FFFF8000 -32768
IF (Int4 .NE. undef_i2ko) Should not happen

 

VMS
undef_i2ko : 8000 -32768
XInt2 : 8000 -32768
XInt4 : FFFF8000 -32768
seems ok

 

1 Solution
Steve_Lionel
Honored Contributor III
944 Views

There is indeed a bug here. The IF is comparing an INTEGER(4) with an INTEGER(2). The standard says:

In the numeric relational operation
 x1 rel-op x2
 if the types or kind type parameters of x1 and x2 differ, their values are converted to the type and kind type parameter of the expression x1 + x2 before evaluation.

(You'd then need to find that rule that basically says convert to the kind with the higher range - INTEGER(4) in this case.)

But if I look at the (x86) assembly code for the comparison, I see this:

 

 

;;; ! ===========================================================
;;; ! seem to substitute X8000 for undef_i2ko and not sign extend
;;; ! ===========================================================
;;; IF (Int4 .NE. undef_i2ko) THEN

  0019f 8b 45 fc         mov eax, DWORD PTR [-4+ebp]            
$LN112:
  001a2 3d 00 80 00 00   cmp eax, 32768                         
$LN113:
  001a7 74 4f            je .B1.10 ; Prob 50%                   
$LN114:

 

 

It's easier to see what's going wrong when you view this in the debugger, but I can't copy from there. The comment has it right - the cmp instruction is comparing the value Z'FFFF8000' from Int4  with the constant Z'00008000' - these are not equal. The compiler is failing to promote the INTEGER(2) named constant to INTEGER(4), as the standard says it must.

Now, I agree that this program is VERY non-standard, but I firmly believe that this is a bug and should be reported through the Online Service Center.

View solution in original post

11 Replies
andrew_4619
Honored Contributor II
995 Views

ifort /stand test.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.1 Build 20201112_000000
Copyright (C) 1985-2020 Intel Corporation. All rights reserved.

test.f90(5): warning #6924: Fortran 2018 does not allow this constant. ['8000'X]
PARAMETER (undef_i2ko = '8000'X) ! DOESNT WORK
------------------------^
test.f90(2): warning #6916: Fortran 2018 does not allow this length specification. [2]
INTEGER*2 Int2
--------^
test.f90(3): warning #6916: Fortran 2018 does not allow this length specification. [2]
INTEGER*2 undef_i2ko
--------^
test.f90(4): warning #6916: Fortran 2018 does not allow this length specification. [4]
INTEGER*4 Int4
--------^
Microsoft (R) Incremental Linker Version 14.16.27039.0
Copyright (C) Microsoft Corporation. All rights reserved.

-out:test.exe
-subsystem:console
test.obj

 

You are expecting non-standard Fortran from one compiler  to behave in the same non-standard way in another compiler.

 

0 Kudos
JP_SECTOR7_COM
New Contributor I
993 Views
Opps - pasted wring version   
 
PROGRAM rick
         INTEGER*2 Int2
         INTEGER*2 undef_i2ko
         INTEGER*4 Int4
         PARAMETER (undef_i2ko = '8000'X) ! DOESNT WORK
         !PARAMETER (undef_i2ko = -32768) WORKS
         !PARAMETER (undef_i2ko = INT('8000'X,2))   WORKS
         Int2 = undef_i2ko
         Int4 = Int2
         write (*,'(" undef_i2ko : ",1Z4.4,I10)') undef_i2ko, undef_i2ko
         write (*,'(" Int2 : ",1Z4.4,I10)') Int2, Int2
         write (*,'(" Int4 : ",1Z8.8, I10)') Int4, Int4
! ===========================================================
! seem to substitute X8000 for undef_i2ko and not sign extend
! ===========================================================
         IF (Int4 .NE. undef_i2ko) THEN
          WRITE(*,*)' IF (Int4 .NE. undef_i2ko) Should not happen'
        ELSE
          WRITE(*,*)'seems ok'
        ENDIF
       END
0 Kudos
andrew_4619
Honored Contributor II
992 Views
PROGRAM rick
    INTEGER(2) :: Int2
    INTEGER(2), parameter :: undef_i2ko = int(z'8000', 2)
    INTEGER(4) :: Int4
    Int2 = undef_i2ko
    Int4 = Int2
    write (*,'(" undef_i2ko : ",1Z4.4,I10)') undef_i2ko, undef_i2ko
    write (*,'(" Int2 : ",1Z4.4,I10)') Int2, Int2
    write (*,'(" Int4 : ",1Z8.8, I10)') Int4, Int4
    ! ===========================================================
    ! seem to substitute X8000 for undef_i2ko and not sign extend
    ! ===========================================================
    IF (Int4 .NE. undef_i2ko) THEN
       WRITE(*,*)' IF (Int4 .NE. undef_i2ko) Should not happen'
    ELSE
       WRITE(*,*)'seems ok'
    ENDIF
END
C:\Users\cadfi\OneDrive\Desktop\zzz>ifort /stand test.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.1 Build 20201112_000000
Copyright (C) 1985-2020 Intel Corporation.  All rights reserved.

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

-out:test.exe
-subsystem:console
test.obj

C:\Users\cadfi\OneDrive\Desktop\zzz>test
 undef_i2ko : 8000    -32768
 Int2 : 8000    -32768
 Int4 : FFFF8000    -32768
 seems ok
0 Kudos
JP_SECTOR7_COM
New Contributor I
988 Views
yes - as I put in the program - setting undef_i2ko to -32768 or INT('8000'x,2) both work.

the interesting point is that printing int2, in4, undef_i2ko ALL print as -32768 SO - WHY is the comparison failing ??
0 Kudos
JP_SECTOR7_COM
New Contributor I
991 Views
0 Kudos
JP_SECTOR7_COM
New Contributor I
991 Views
No - expecting it to sign extend the hex constant - OR - emit an error message .. actually really expecting the '8000'X to be assigned to undef_i2ko as a normal variable and have the sign extension taken care of.
0 Kudos
andrew_4619
Honored Contributor II
987 Views

it is not standard fortran in fixed or free format.  '8000'X is not valid Fortran it is a not standard language extension.  Compile with /stand option. The example I showed is standard and works.

0 Kudos
andrew_4619
Honored Contributor II
978 Views

a 4 byte integer can't be bitwise identical to a 2 byte integer, they have a different number of bits. 

0 Kudos
JP_SECTOR7_COM
New Contributor I
960 Views
The bug is NOT doing bitwise compare - it's a sign entension bug.

if undek_i2ko == -32768 and int4 == -32768 they should be exactly the same, regardless of the # of bits.

otherwise you would have to program every "compare" to compare against variables of exactly the same bit width.



0 Kudos
andrew_4619
Honored Contributor II
951 Views

int(z'8000',2) = -32768

int(z'8000',4) = 32768 

They are not the same 

 

0 Kudos
Steve_Lionel
Honored Contributor III
945 Views

There is indeed a bug here. The IF is comparing an INTEGER(4) with an INTEGER(2). The standard says:

In the numeric relational operation
 x1 rel-op x2
 if the types or kind type parameters of x1 and x2 differ, their values are converted to the type and kind type parameter of the expression x1 + x2 before evaluation.

(You'd then need to find that rule that basically says convert to the kind with the higher range - INTEGER(4) in this case.)

But if I look at the (x86) assembly code for the comparison, I see this:

 

 

;;; ! ===========================================================
;;; ! seem to substitute X8000 for undef_i2ko and not sign extend
;;; ! ===========================================================
;;; IF (Int4 .NE. undef_i2ko) THEN

  0019f 8b 45 fc         mov eax, DWORD PTR [-4+ebp]            
$LN112:
  001a2 3d 00 80 00 00   cmp eax, 32768                         
$LN113:
  001a7 74 4f            je .B1.10 ; Prob 50%                   
$LN114:

 

 

It's easier to see what's going wrong when you view this in the debugger, but I can't copy from there. The comment has it right - the cmp instruction is comparing the value Z'FFFF8000' from Int4  with the constant Z'00008000' - these are not equal. The compiler is failing to promote the INTEGER(2) named constant to INTEGER(4), as the standard says it must.

Now, I agree that this program is VERY non-standard, but I firmly believe that this is a bug and should be reported through the Online Service Center.

Reply