- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
If, in the body of a program, in a call to the INT intrinsic with second argument kind=int64, I use as first argument a boz-literal-constant such that either (A) the bit #31 is the highest bit specified and has value one (rightmost bit is #0) or (B) the boz constant is an octal constant where the two highest bit specified are #32 set to zero and #31 set to one (that is, the most significant octal digit is a 2 or a 3), I obtain the result I would expect according to the 2008 version of the Fortran standard (section 13.3.3):
"When a boz-literal-constant is the argument A of the intrinsic function INT or REAL, if the length of the sequence of bits specified by A is less than the size in bits of a scalar variable of the same type and kind type parameter as the result, the boz-literal-constant is treated as if it were extended to the length equal to the size in bits of the result by padding on the left with zero bits [...],"
and the result is a positive integer number; e.g.,
integer(kind=int64) :: Vz !76543210 Vz = int(z'80000000', kind=int64) write(*,'(a, 24x, a)') "Position", "76543210" write(*,'(a,i18,1x,z16)') "Vz = ", Vz, Vz
results in
Position 76543210 Vz = 2147483648 80000000
However, if this happens when setting the value of a parameter, the boz-literal-constant seems to be padded with ones to the left: the code
!76543210 integer(kind=int64), parameter :: Pz = int(z'80000000', kind=int64) write(*,'(a, 24x, a)') "Position", "76543210" write(*,'(a,i18,1x,z16)') "Pz = ", Pz, Pz
results in a negative integer
Position 76543210 Pz = -2147483648 FFFFFFFF80000000
I initially thought I might be interpreting incorrectly the standard, and that this behaviour could be related to the last sentence in the Result Value section of the INT intrinsic (section 13.7.81):
"The interpretation of a bit sequence whose most significant bit is 1 is processor dependent."
However, (a) I think this only makes sense if the most significant bit is 1 after the padding/truncation described in 13.3.3 has taken place, and (b) this would not include the octal case described in (B) above, since in that case the most significant bit specified is indeed zero.
Would it be possible for you to clarify whether my interpretation of the standard is wrong, or whether there might be a bug in the compiler?
I am experiencing this behaviour with the Intel compiler versions 16.0.3, 17.0.2 and 18.0.0 20170510. I am attaching a source file that exemplifies this - the outputs I obtain with the three versions above are the same:
$ ifort minbozint.f90 -o minbozint.ifort -check all -warn all -std08 && ./minbozint.ifort Position 76543210 Pz = -2147483648 FFFFFFFF80000000 Po = -2147483648 FFFFFFFF80000000 Pb = -2147483648 FFFFFFFF80000000 Vz = 2147483648 80000000 Vo = 2147483648 80000000 Vb = 2147483648 80000000
Thank you very much for your help.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Whichever choice is correct, the compiler ought to be consistent about it. My reading of the standard is that the value should be padded with zeroes. That it is not is a compiler bug.
That last sentence about "processor-dependent" is referring to the final value of A, after padding or truncation (if any). There's nothing in the standard that says a leftmost bit of 1 means a negative value - the standard goes out of its way to discuss the "bit model" (13.3) in terms of "non-negative" values. The sentence is not relevant to HOW the compiler does its padding or truncation.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Whichever choice is correct, the compiler ought to be consistent about it. My reading of the standard is that the value should be padded with zeroes. That it is not is a compiler bug.
That last sentence about "processor-dependent" is referring to the final value of A, after padding or truncation (if any). There's nothing in the standard that says a leftmost bit of 1 means a negative value - the standard goes out of its way to discuss the "bit model" (13.3) in terms of "non-negative" values. The sentence is not relevant to HOW the compiler does its padding or truncation.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you for your report! This issue is better to be reported via our Online Service Center at https://supporttickets.intel.com/
Instructions on how to file a ticket are available here:
https://software.intel.com/en-us/articles/how-to-create-a-support-request-at-online-service-center
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
z'80000000'
Is interpreted as INTEGER(4)
int(z'80000000', kind=int64)
Converts an INTEGER(4) to INTEGER(8)... with sign propagation.
use z'0000000080000000'
or try z'080000000'
thus forcing the literal to 36 bits (IOW into 64-bit internal form).
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It should not be doing sign propagation.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear All,
Thank you for your replies.
Steve: Thank you for your clarifications regarding the interpretation of the standard - and congratulations on your election as convenor of WG5!
Jim: Thank you, there are a number of workarounds that I could use, but that wasn't what I was asking for. I think that what you say about interpretations and conversions is not correct: boz-literal-constants such as z'80000000' are not interpreted standalone, they are only valid in a few situations specified by the standard, and their interpretation has to follow section 13.3. According to the standard, there is no "interpretation as integer(kind=int32) and then conversion to integer(kind=int64)", there's a direct interpretation as integer(kind=int64) after the padding with zeroes described above has taken place. If the compiler was doing a conversion from int32 to int64, that would not be in agreement with the standard and would be the source of the issue here reported.
Kind regards,
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I was going to say that Quote #4 makes no sense, but it is kinda consistent with test programs for ifort 16.0. Consider:
module M use ISO_FORTRAN_ENV implicit none interface bitseq module procedure bs1,bs2,bs4,bs8 end interface bitseq contains subroutine bs1(X) implicit none integer(INT8), intent(IN) :: X write(*,'(3(g0),Z0)') 'KIND = ',KIND(X),', X = ',X end subroutine bs1 subroutine bs2(X) implicit none integer(INT16), intent(IN) :: X write(*,'(3(g0),Z0)') 'KIND = ',KIND(X),', X = ',X end subroutine bs2 subroutine bs4(X) implicit none integer(INT32), intent(IN) :: X write(*,'(3(g0),Z0)') 'KIND = ',KIND(X),', X = ',X end subroutine bs4 subroutine bs8(X) implicit none integer(INT64), intent(IN) :: X write(*,'(3(g0),Z0)') 'KIND = ',KIND(X),', X = ',X end subroutine bs8 end module M program P use M implicit none call bitseq(Z'80000000') call bitseq(Z'080000000') call bitseq(Z'0000000080000000') end program P
The output with both 32- and 64-bit compilers is:
KIND = 8, X = 80000000 KIND = 8, X = 80000000 KIND = 8, X = 80000000
So that in an ordinary expression, the KIND is 8 in all 3 cases. However:
program P implicit none integer, parameter :: K1 = KIND(Z'80000000') integer, parameter :: K2 = KIND(Z'080000000') integer, parameter :: K3 = KIND(Z'0000000080000000') write(*,'(*(g0))') 'K1 = ',K1 write(*,'(*(g0))') 'K2 = ',K2 write(*,'(*(g0))') 'K3 = ',K3 end program P
Yields the output:
K1 = 4 K2 = 8 K3 = 8
Which is consistent with the prediction of @jimdempseyatthecove. Now we have to ask: is the fact that the BOZ constant is used in an initialization expression or a specification expression that triggers the bug? Let's try an example with only a specification function:
module M use ISO_FORTRAN_ENV implicit none interface bitseq module procedure bs1,bs2,bs4,bs8 end interface bitseq contains pure function bs1(X) implicit none integer bs1 integer(INT8), intent(IN) :: X bs1 = KIND(X) end function bs1 pure function bs2(X) implicit none integer bs2 integer(INT16), intent(IN) :: X bs2 = KIND(X) end function bs2 pure function bs4(X) implicit none integer bs4 integer(INT32), intent(IN) :: X bs4 = KIND(X) end function bs4 pure function bs8(X) implicit none integer bs8 integer(INT64), intent(IN) :: X bs8 = KIND(X) end function bs8 pure function F1(X) integer, intent(IN) :: X integer F1(bitseq(Z'80000000')) F1 = X end function F1 pure function F2(X) integer, intent(IN) :: X integer F2(bitseq(Z'080000000')) F2 = X end function F2 pure function F3(X) integer, intent(IN) :: X integer F3(bitseq(Z'0000000080000000')) F3 = X end function F3 end module M program P use M implicit none write(*,'(*(g0))') 'SIZE(F1(0)) = ',SIZE(F1(0)) write(*,'(*(g0))') 'SIZE(F2(0)) = ',SIZE(F2(0)) write(*,'(*(g0))') 'SIZE(F3(0)) = ',SIZE(F3(0)) end program P
Output with ifort:
SIZE(F1(0)) = 8 SIZE(F2(0)) = 8 SIZE(F3(0)) = 8
So it's OK in just a specification expression. Curious that the bug requires such a specific trigger, and really has two components: one as a BOZ extension and one as standard BOZ usage.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
Thanks, I should re-read docs re: INT:
If a is a binary, octal, or hexadecimal literal constant, the value of the result is the value whose bit sequence according to the model in Bit Model is the same as that of a as modified by padding or truncation according to the following:
If the length of the sequence of bits specified by a is less than the size in bits of a scalar variable of the same type and kind type parameter as the result, the binary, octal, or hexadecimal literal constant is treated as if it were extended to a length equal to the size in bits of the result by padding on the left with zero bits.
So it appears that in the case of an argument to INT, the (8-character) hex literal lost its hex-iness.
Here is an alternate test case to RO's:
program TestHex implicit none if(Z'80000000' .gt. 0) then print *, "gt 0" else print *, "lt 0" endif if(Z'80000000' .gt. 0_8) then print *, "gt 0_8" else print *, "lt 0_8" endif if(int(Z'80000000',kind=8) .gt. 0) then print *, "kind 8, gt 0" else print *, "kind 8, lt 0" endif end program TestHex lt 0 gt 0_8 kind 8, gt 0
This illustrates that the interpretation is correct (for the above code example, and V17u1).
I can see how this bug passed inspection.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
V17 is ok
program TestHex implicit none integer, parameter :: int64 = 8 integer(kind=int64) :: Vz,Vx !76543210 Vz = int(z'80000000', kind=int64) Vx = int(z'80000000', kind=int64) + 0_8 write(*,'(a, 24x, a)') "Position", "76543210" write(*,'(a,i18,1x,z16)') "Vz = ", Vz, Vz write(*,'(a,i18,1x,z16)') "Vx = ", Vx, Vx end program TestHex Position 76543210 Vz = 2147483648 80000000 Vx = 2147483648 80000000
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think you're missing what ifort is doing to assign the KIND of a BOZ literal in Quotes #8 and #9 above. In the first two cases of Quote #8, the BOZ literal, being one of the operands to a 2-operand operator, takes the KIND of the other operand, as per the ifort docs. In the last case of Quote #8 and in Quote #9, the standard usage of a BOZ literal is happening in the execution-part of the program, where ifort is doing the right thing. Put the same syntax in the specification-part of the program and I am pretty sure that it will fail, just as in Quote #1.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
jme wrote:
Steve: Thank you for your clarifications regarding the interpretation of the standard - and congratulations on your election as convenor of WG5
That hasn't actually happened yet, and it is very likely that there will be no "election" in that no other candidates have volunteered! My nomination still needs to be approved by the US SC22 Steering Committee and then confirmed by the ISO committees. One might say I "didn't duck fast enough" when asked, but in truth it was an honor I was pleased to be able to accept.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ooh, here's another test I wanted to try but I don't have recent enough ifort. What output does this produce on the most recent version of ifort?
module M use ISO_FORTRAN_ENV implicit none contains subroutine bitseq(X) class(*) X select type(X) type is(integer(int8)) write(*,'(*(g0))') 'KIND = ',KIND(X) type is(integer(int16)) write(*,'(*(g0))') 'KIND = ',KIND(X) type is(integer(int32)) write(*,'(*(g0))') 'KIND = ',KIND(X) type is(integer(int64)) write(*,'(*(g0))') 'KIND = ',KIND(X) end select end subroutine bitseq end module M program P use M implicit none class(*), allocatable :: X X = Z'80000000' call bitseq(X) X = Z'080000000' call bitseq(X) end program P
Replacing X = Z'80000000' with allocate(X,source=Z'80000000') causes an access violation on the ALLOCATE statement in ifort 16.0.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
KIND = 8
KIND = 8
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R
) 64, Version 18.0.0.083 Beta Build 20170510
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
jme wrote:
.. Jim: Thank you, there are a number of workarounds that I could use, but that wasn't what I was asking for. ..
@jme,
Please, pray tell which other workaround will you use? Since the problem presented in the original post is within the context of a named constant, I thnk you are going to struggle coming up with even one other sensible workaround, let alone "a number of" them.
And since what is at stake is a compiler bug, it is largely meaningless what the standard says, especially in section 13.3, when it comes to developing workarounds. Regardless of how the verbiage in the standard evolves, there is only ever an infinite array of bugs that separate a compiler implementation from the text and Jim's statement in Quote #4 appears closer to what may actually be going on in Intel Fortran implementation and his workaround seems to make best sense:
program p use, intrinsic :: iso_fortran_env, only : int64, compiler_version implicit none write (*,*) "Compiler Version: ", compiler_version() blk1: block !76543210 integer(kind=int64), parameter :: Pz = int(z'80000000', kind=int64) write (*,*) "Block 1:" write (*,'(a, 24x, a)') "Position", "76543210" write (*,'(a,i18,1x,z16)') "Pz = ", Pz, Pz end block blk1 blk2: block !76543210 integer(kind=int64), parameter :: Pz = int(z'080000000', kind=int64) write (*,*) "Block 2:" write (*,'(a, 24x, a)') "Position", "76543210" write (*,'(a,i18,1x,z16)') "Pz = ", Pz, Pz end block blk2 blk3: block !76543210 integer(kind=int64), parameter :: Pz = int(z'0000000080000000', kind=int64) write (*,*) "Block 3:" write (*,'(a, 24x, a)') "Position", "76543210" write (*,'(a,i18,1x,z16)') "Pz = ", Pz, Pz end block blk3 stop end program p
Upon execution,
Compiler Version: Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel( R) 64, Version 18.0.0.083 Beta Build 20170510 Block 1: Position 76543210 Pz = -2147483648 FFFFFFFF80000000 Block 2: Position 76543210 Pz = 2147483648 80000000 Block 3: Position 76543210 Pz = 2147483648 80000000
If you have not done so, please follow up as suggested by Devorah in Quote #3 and report an incident at Intel's Online Service Center (OSC),, for only then is there some assurance Intel staff will follow up on the compiler bug.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
FWIW, in my 50 years of programming I've experienced too many compiler errors to count. Once discovered, life must go on. i.e. when code must get finished - produce a work around, don't wait for a fix. The trick is (one gets better the more the do this) to "divine" a probable cause, test the premise, and construct a work around. With fortuitous luck, the work around will be non-intrusive as well as have no impact on performance.
In this case, do not be too picky about adding an otherwise unnecessary 0 to the literal.
Also node, that a well constructed fix will work when the bug is removed from the compiler.
I think jme's post was simply a disclosure of a bug, and not a plea for a work around.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ticket submitted.
I was not completely sure that this was a bug, but I thought it might be one, and I was mostly seeking confirmation.
I had noticed that adding one or more zeros fixed the issue (at least for the binary and hex constants), like Jim did, and I think this is the most elegant workaround. However, in the end this is about initialising an integer, so you could just compute its value manually (in this case, initialise to 2147483648_int64), or INT(<boz-literal-constant with bit #31 set to zero>, kind=int64) + 2_int64**31_int64, etc.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
jme wrote:
Ticket submitted.
Thank you!
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page