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

Optimization changes passing of arguments? (Compiler Bug?)

rwg
Novice
1,044 Views
Following source code (in two diffent files)

program testprj_fortran

implicit none

double precision:: d1(12)=(/1,2,3,4,5,6,7,8,9,0,0,0/)

call swap(d1,d1)
write(*,*) d1
read(*,*)
end program testprj_fortran

subroutine swap(dm1,dm2)
DOUBLE PRECISION DM1(12),DM2(12),DMH(9)
DMH(1)=DM1(1)
DMH(2)=DM1(4)
DMH(3)=DM1(7)
DMH(4)=DM1(2)
DMH(5)=DM1(5)
DMH(6)=DM1(8)
DMH(7)=DM1(3)
DMH(8)=DM1(6)
DMH(9)=DM1(9)
DM2(10)=DMH(1)*DM1(10)
DM2(11)=DMH(2)*DM1(10)
DM2(12)=DMH(3)*DM1(10)
DO I=1,9
DM2(I)=DMH(I)
enddo
END

gives following output in Debug-Mode or when /Od is used (this is the correct result)

1.00000000000000 4.00000000000000 7.00000000000000
2.00000000000000 5.00000000000000 8.00000000000000
3.00000000000000 6.00000000000000 9.00000000000000
0.000000000000000E+000 0.000000000000000E+000 0.000000000000000E+000

but this in Release-Mode (which is wrong)

1.00000000000000 4.00000000000000 7.00000000000000
2.00000000000000 5.00000000000000 8.00000000000000
7.00000000000000 8.00000000000000 9.00000000000000
0.000000000000000E+000 0.000000000000000E+000 0.000000000000000E+000

I tried this with compiler versions 11.1.64, 11.1.60, 11.1.51, 11.0.74 and 10.1.25. All compilers give the same result.

My Compiler Options in Release-Mode are:

/nologo /module:"Release\\\\" /object:"Release\\\\" /libs:static /threads /c


What is wrong? Any Ideas?

0 Kudos
11 Replies
bendel_boy1
Beginner
1,044 Views
You pass d1 as input & output.

The optimiser 'knows' that arrays will not overlap, so it recognises that DMH is an unneeded temporary array, and refactors to work directly with DM1 and DM2. This is why you get duplicates for 7 & 8. At different optimisation levels you might get different duplicates. You might be better off writing it as a function that returns an array.

FUNCTION swap(d1) RESULT (d2)
REAL:: d2(UBOUND(d1)) ! Whatever is the correct syntax
...
0 Kudos
IanH
Honored Contributor III
1,044 Views
Have a read of 12.4.1.7 in the Fortran 2003 standard (there's a link to it off the main page of the forum - similar words will be present in previous standards), particularly the example given in Note 12.29.

That section places limits on what can be done to dummy arguments that are associated with the same (part of an) actual argument, without there being things like TARGET/POINTER attributes etc - you can't define any part of the dummy arguments that overlap. I think you are breaking those limits. All bets are off.

An alternative work around to the (possibly better) function call suggestion would be to change the call to be:
[fortran]call swap((d1),d1)
[/fortran]
where the first dummy argument is then associated with an actual argument that is an expression (that happens to involve d1) and not directly to the variable d1. I think your code would then be standard conforming.

Implementation detail (?) - but when the compiler sees the expression "(d1)" it will probably create a temporary array, fill that temporary with the value of d1 (as per the expression) and then call the swap procedure. The function call approach may also result in the creation of a temporary array, but it may avoid the need to fill (copy) the temporary with the value of d1 prior to the call. Regardless of that detail (and note that the optimiser may be smart enough to avoid temporaries and copies anyway) as the code with the expression or function call becomes standard conforming you can rely on the overall behaviour, which would be as you originally expected.

0 Kudos
rwg
Novice
1,044 Views

I have read chapter 12.4.1.7 of ISO/IEC FCD 1539-1:2004(E) (hope that's the document your refered to) but I can not see what it has to do with my example. Chapter 12.4.1.7 deals with references to outer defined variables (which is not the case in my example) and with defining, redefining and undefinig of arguments (which is also not done in my example). To avaid missunderstanding change swap to

subroutine swap(dm1,dm2)
DOUBLE PRECISION DM1(12),DM2(12),DMH(10)
DMH(1)=DM1(1)
DMH(2)=DM1(4)
DMH(3)=DM1(7)
DMH(4)=DM1(2)
DMH(5)=DM1(5)
DMH(6)=DM1(8)
DMH(7)=DM1(3)
DMH(8)=DM1(6)
DMH(9)=DM1(9)
DMH(10)=DM1(10)
DM2(10)=DMH(1)*DMH(10)
DM2(11)=DMH(2)*DMH(10)
DM2(12)=DMH(3)*DMH(10)
DO I=1,9
DM2(I)=DMH(I)
enddo
END

You can see that there isn'tan overlap of the dummy arguments during the assignments. But this example also fails.
DMH in swap was only added to make swap callablewith the same arguments and as far as I understand the FORTRAN Standard this has to be allowed. I think the optimizer of the FORTRAN Compiler did too much.

0 Kudos
IanH
Honored Contributor III
1,044 Views
That's the doc! The section I'm referring to is titled "Restrictions on entities associated with dummy arguments". Read note 12.29 which highlights an implication of the nearby normative text about action on an entity only being taken through the (i.e. one) dummy argument.

Assignment is one way of defining a variable. Because you have two dummy arguments (dm1 and dm2) associated with the same entity (d1) (and the dummies don't have target/pointer attributes etc) you cannot assign to any part of either of them. The order of assignments doesn't matter and the presence of the DMH variable doesn't matter.

This restriction on aliasing is a Fortran language feature as it allows (or simplifies) certain optimisations.
0 Kudos
rwg
Novice
1,044 Views

I see you are absolutly right. Because of my restricted knowledge of the english language I didn't realize that 'define' included 'assign'.

It's surprising that this 'error' does not appear if 'I don't assign values to DM2(10:12) and that these assignments destroy DM2(1:9)!

I have lots of F77 programs where this type of argument passing is done. In most cases this works without any error. Is there a rule when this type of argument passing fails?

In F77 this was common practice so I think this restriction came with F90,F95 or F2003. Does someone know?



0 Kudos
Steven_L_Intel1
Employee
1,044 Views
Nope - it was illegal in F77 as well. Some earlier compilers didn't try to optimize dummy arguments, but even VAX Fortran, a F77 compiler did. There is a /assume:dummy_aliases option which will disable such optimizations, but I'd recommend that you restructure the code to be legal Fortran instead.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,044 Views
This is a good example of where a working program (that may have been working for decades) is not assurance that the program is bug-free.

In the Northern latitudes this is what we would call "Walking on thin ice". The fact that you have walked across a frozen pond does not assure you that it is safe to walk across that frozen pond. (does not assure that the ice is thick enough to safely walk across).

>>It's surprising that this 'error' does not appear if 'I don't assign values to DM2(10:12) and that these assignments destroy DM2(1:9)!

This is a case where the 'symptom' of the programming error does not appear. (or had not appeared for a long time)

Another way to think of this is a single threaded analog of what occures in a multi-threaded race condition. The way the code was written, the compiler was free to rearrange the statements to produce the stated results. Or you could say the compiler had more liberties than you assumed/experienced.

If you have many such subroutines/functions that have this problem then by disabling optimizations for these subroutines/functions may reduce/eliminate the 'symptom' although it will not correct the programming error.

If you want the optimizations for the cases when the dummy args do not overlap, yet permit occasional calls with overlappingdummies, then you will need to insert a test for overlapping dummies .or. create a new function/subroutine where you test for same dummies, overlapping dummies, non-overlapping dummies.

Jim Demspey
0 Kudos
mecej4
Honored Contributor III
1,044 Views
The late E.W.Dijkstra, a great man, wrote:

"computing's central challenge, viz. 'How not to make a mess of it', has not been met"

That dictum applies very well here.

That you have code in which some rules of Fortran were broken yet worked correctly has the hallmarks of a self-made trap. There is no guaranteed penalty (i.e., wrong results) for writing buggy code. However, escaping from penalty is not guaranteed, either.

0 Kudos
Les_Neilson
Valued Contributor II
1,044 Views

Alas when working with legacy libraries, some 25+ years old, these things crop up.
Just this week I found the same problem

subroutine trans(matrix, inar, outar)
calculate tempar as function of matrix and inar
assign tempar to outar
end

call trans(mat, p1, p1)
appeared in lots of places

Interestingly :
32bit debug and release worked ok
64bit debug worked ok
64bit release failed :-(

It took me several days to track down the problem (using print statements)especially as debug 64bit worked.

No doubt there are other pieces of code doing similar things waiting to trip me up.

Les

PS
Microsoft have put further obstacles inmy way by not allowing debugging of mixed (managed and unmanaged) code for 64bit compilation in VS2008.
Ihaven't been able tofind out if this restrictionis removed in VS2010

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,044 Views
Quoting Les Neilson


Microsoft have put further obstacles inmy way by not allowing debugging of mixed (managed and unmanaged) code for 64bit compilation in VS2008.
Ihaven't been able tofind out if this restrictionis removed in VS2010

Yes, that's a pain. However, it is not allowed only to debug them simultaneously (in the same debug session). If you want to debug only an unmanaged component, set it as a startup project, and set up the managed .exe as the "executable for debug session". Additionally, make sure that the debugger model in project settings is "Native only" (rather than "Automatic").

0 Kudos
Steven_L_Intel1
Employee
1,044 Views
Microsoft have put further obstacles inmy way by not allowing debugging of mixed (managed and unmanaged) code for 64bit compilation in VS2008.
Ihaven't been able tofind out if this restrictionis removed in VS2010


Microsoft appears to claim that this works in VS 2010 if the .NET code uses the .NET Framework 4.0. I have not yet been able to verify this.
0 Kudos
Reply