|
forums.silverfrost.com Welcome to the Silverfrost forums
|
View previous topic :: View next topic |
Author |
Message |
mecej4
Joined: 31 Oct 2006 Posts: 1886
|
Posted: Tue Apr 28, 2015 4:42 am Post subject: Computed GO TO triggers optimiser bug |
|
|
A program with about 4,000 lines of text was producing incorrect results when compiled with /OPT. With considerable effort, I was able to pare down the code to the following reproducer.
Code: | program drvr
implicit none
integer :: i,j
do i=0,2
call cgo(i,j)
write(*,*)i,j
end do
end program
subroutine cgo(i,j)
implicit none
integer, intent(in) :: i
integer, intent(out) :: j
!
if (i > 0) then
go to (10, 20) i
end if
j=0; return
10 j=3*i-1; return
20 j=2*i+1; return
end subroutine cgo |
When I compiled this using the 7.10 compiler with the /OPT option, the optimiser completely removed the IF block, and running the program gave the erroneous output
instead of the correct output, which is
[P.S., 15 June 2015: This bug is also present in FTN95-7.20]
Last edited by mecej4 on Mon Jun 15, 2015 11:15 pm; edited 1 time in total |
|
Back to top |
|
|
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 7927 Location: Salford, UK
|
Posted: Tue Apr 28, 2015 7:59 am Post subject: |
|
|
Thanks for the feedback. I have logged this for investigation. |
|
Back to top |
|
|
LitusSaxonicum
Joined: 23 Aug 2005 Posts: 2388 Location: Yateley, Hants, UK
|
Posted: Tue Apr 28, 2015 11:10 am Post subject: |
|
|
Someone deprecated the IF block because it contained the deprecated computed GOTO.
Political correctness in Fortran? Where will it all end?
Seriously, now I know what caused me to distrust /OPT - my code contained a single computed GOTO, legacy of an IBM1130 circa 1970. Many thanks MECEJ. Time to send it where the Holleriths and arithmetic IFs went.
I'll bet an assigned GOTO is even worse.
Eddie |
|
Back to top |
|
|
mecej4
Joined: 31 Oct 2006 Posts: 1886
|
Posted: Tue Apr 28, 2015 12:22 pm Post subject: |
|
|
The ASSIGN and Assigned GO TO statements were "Deleted features" in F95. The Computed GO TO statement, however, was merely "Obsolescent" in F95, and as far as I know every current compiler accepts it.
The optimiser problem was caused by the presence of computed GO TO in well-respected but old code. If fact, the optimiser bug does not arise if the computed GO TO is used the way it was intended to be used, without the "if (i > 0)then" thrown in as a defensive (?) measure.
The 2003 standard says in 8.2.2:
Quote: | Execution of a computed GO TO statement causes evaluation of the scalar integer expression. If this value is i such that 1 <= i <= n where n is the number of labels in label-list, a transfer of control occurs so that the next statement executed is the one identified by the i-th label in the list of labels. If i is less than 1 or greater than n, the execution sequence continues as though a CONTINUE statement were executed. |
The last sentence in the quote is what makes the optimiser-bug inducing IF..ENDIF superfluous.
Last edited by mecej4 on Mon Jun 06, 2016 7:13 pm; edited 1 time in total |
|
Back to top |
|
|
LitusSaxonicum
Joined: 23 Aug 2005 Posts: 2388 Location: Yateley, Hants, UK
|
Posted: Tue Apr 28, 2015 1:10 pm Post subject: |
|
|
I had forgotten ASSIGN. My bet was betting on certainty! |
|
Back to top |
|
|
John-Silver
Joined: 30 Jul 2013 Posts: 1520 Location: Aerospace Valley
|
Posted: Tue Apr 28, 2015 4:27 pm Post subject: |
|
|
the appears to give the same error if you run it as f77 code too.
Strange that if the calculated goto command was 'obsolete' that the compiler doesn't flag as an error either ?
( unknown command 'go to (**,**)' would maybe be a useful message for example :O) ) |
|
Back to top |
|
|
mecej4
Joined: 31 Oct 2006 Posts: 1886
|
Posted: Tue Apr 28, 2015 6:50 pm Post subject: |
|
|
If you run the F77 fixed form version of the test program but compile using FTN77 4.03 instead of FTN95, the resulting program runs correctly with or without /OPT. |
|
Back to top |
|
|
IanLambley
Joined: 17 Dec 2006 Posts: 490 Location: Sunderland
|
Posted: Wed Apr 29, 2015 12:29 pm Post subject: |
|
|
What happens if you replace it with:
Code: |
subroutine cgo(i,j)
implicit none
integer, intent(in) :: i
integer, intent(out) :: j
!
select case(i)
case(1)
j=3*i-1
case(2)
j=2*i+1
case default
j=0
end select
end subroutine cgo
|
Regards
Ian |
|
Back to top |
|
|
davidb
Joined: 17 Jul 2009 Posts: 560 Location: UK
|
Posted: Wed Apr 29, 2015 10:21 pm Post subject: |
|
|
Well the test for i>0 in the code fragment below (copied from above) is redundant. Also it doesn't provide any "safety net" when i = 3 for example.
Code: |
if (i > 0) then
go to (10, 20) i
end if
j=0; return
10 j=3*i-1; return
20 j=2*i+1; return
|
All you need is the following as control goes to the next line if i isn't 1 or 2 because "go to (10, 20) 3" is the same as "CONTINUE".
Code: |
go to (10, 20) i
j=0; return
10 j=3*i-1; return
20 j=2*i+1; return
|
Or use Ian's solution above.
All this said, the purpose of this thread is to point out a bug with the optimiser when /opt is used. _________________ Programmer in: Fortran 77/95/2003/2008, C, C++ (& OpenMP), java, Python, Perl |
|
Back to top |
|
|
LitusSaxonicum
Joined: 23 Aug 2005 Posts: 2388 Location: Yateley, Hants, UK
|
Posted: Sat May 02, 2015 2:44 pm Post subject: |
|
|
Isn't this the simplest solution (66):
Code: | J = 0
IF ((I-1)*(I-2)) 20, 10, 20
10 J = 3*I - 1
20 CONTINUE |
or (77):
Code: | J = 0
IF ((I-1)*(I-2) .EQ. 0) J = 3*I - 1 |
or even:
Code: | J = 0
IF (I .EQ. 1 .OR. I .EQ. 2) J = 3*I - 1 |
The safety net is provided.
Two expressions for J are unnecessary, and if the multiple IFs or computed GOTO must be provided, then surely J=2 and J=5 make calculation redundant.
Whether or not I+I+I-1 or 2*I + I/2 is faster with the routine called many times if a question I leave to others, but certainly it is less clear.
I find that the much unloved arithmetic IF sometimes has a beauty all of its own!
Eddie |
|
Back to top |
|
|
mecej4
Joined: 31 Oct 2006 Posts: 1886
|
Posted: Sat May 02, 2015 3:23 pm Post subject: |
|
|
Eddie, your modifications do not give the correct result when I = 2, for which J = 2*I + 1, not 3*I - 1.
I note in this thread a tendency to over-analyse a simple reproducer program. The actual computed GOTO in the larger program was
Code: | GOTO (999,999,130,150,170,190,210,230,250,270,290,310,330,350,500) I | Would you care to tackle such GOTO-s, with the possibility that a target label (e.g., 999) may appear more than once in the list?
Please note that, as far as I know, FTN95 does not have a problem with compiling computed GOTO statements correctly. It is only when the computed GOTO is preceded by an IF statement that the compiler produces incorrect code. |
|
Back to top |
|
|
davidb
Joined: 17 Jul 2009 Posts: 560 Location: UK
|
Posted: Sat May 02, 2015 4:30 pm Post subject: Re: |
|
|
mecej4 wrote: | Eddie, your modifications do not give the correct result when I = 2, for which J = 2*I + 1, not 3*I - 1.
|
eh?
2*2 + 1 = 5
3*2 - 1 = 5 _________________ Programmer in: Fortran 77/95/2003/2008, C, C++ (& OpenMP), java, Python, Perl |
|
Back to top |
|
|
LitusSaxonicum
Joined: 23 Aug 2005 Posts: 2388 Location: Yateley, Hants, UK
|
Posted: Sat May 02, 2015 5:01 pm Post subject: |
|
|
Mecej4,
Quote: | your modifications do not give the correct result when I = 2, for which J = 2*I + 1, not 3*I - 1 |
For I=2, (not using Fortran syntax)
2x2 = 4 then add 1 = 5 (J = 2*I + 1)
3x2 = 6 then minus 1 = 5 (J = 3*I - 1)
Now where have I gone wrong? For the life of me I can't see where I erred and failed to get the right answer, which is 5. Perhaps I is REAL, and the computed GOTO is of that ghastly short-lived type that was the work of the devil (to quote Dan).
3i-1 = 2i +1 solves to give i=2, if you prefer algebra to arithmetic. True, it only works for i=2, but it (obviously) gives the right answer for i=1 as well.
You were too quick off the mark, old boy!
Of course, but the reproducer problem was a crock of the proverbial, and indeed, the arithmetic GOTO with statement numbers in the full problem is probably the simplest and most elegant solution to the task presented. But then Backus was a genius, and those who followed him might not have been.
The alternative is a long IF THEN ELSE IF construct, or maybe CASE if you prefer.
So your (unnecessary) goal keeper throws FTN95. Certainly needs fixin'.
My own regular goal keeper, as in:
Code: | IF (A .EQ. 0.0D0) THEN
do a whole lot of error reporting, probably resulting in a jump
ELSE
C = B/A
ENDIF |
makes FTN95 nag me that comparing to zero is a bad thing to do. Not in this context, Silverfrost me old china. At least when it has finished giving me GBH of the eyeball, it works.
Eddie |
|
Back to top |
|
|
LitusSaxonicum
Joined: 23 Aug 2005 Posts: 2388 Location: Yateley, Hants, UK
|
Posted: Sat May 02, 2015 5:19 pm Post subject: |
|
|
DavidB,
Your simplicity shames me. I was too busy making coffee, scoffing down a biscuit, and composing what I thought was a witty reply to Mecej4, whose command of the intricacies of the latest Fortran standard usually leaves me open-mouthed in awe and admiration!
Eddie
Last edited by LitusSaxonicum on Sat May 02, 2015 5:43 pm; edited 1 time in total |
|
Back to top |
|
|
mecej4
Joined: 31 Oct 2006 Posts: 1886
|
Posted: Sat May 02, 2015 5:30 pm Post subject: |
|
|
Ah, now I see what Eddie did! It did not occur to me to examine the content of the target statements to modify the GOTO statement. DavidB and Eddie, you are both correct, but you can see the risk of writing such code, and subsequently modifying, say, 2*I + 1 to 2*I + 5. And yes, Eddie, you are wickedly witty! |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|