- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
"Similarly, if any part of the actual argument is defined through a dummy argument, the actual argument can only be referenced through that dummy argument during execution of the procedure. For example, if the following statements are specified:
MODULE MOD_A
REAL :: A, B, C, D
END MODULE MOD_A
PROGRAM TEST
USE MOD_A
CALL SUB_1 (B)
...
END PROGRAM TEST
SUBROUTINE SUB_1 (F)
USE MOD_A
...
WRITE (*,*) F
END SUBROUTINE SUB_1
Variable B must not be directly referenced during the execution of SUB_1 because it is being defined through dummy argument F. However, B can be indirectly referenced through F (and directly referenced when SUB_1 completes execution)."
why then does this program work?
MODULE MOD_A
REAL :: A, B, C, D
END MODULE MOD_A
PROGRAM TEST
USE MOD_A
b=1.0
CALL SUB_1 (B)
write(*,*)B
END PROGRAM TEST
SUBROUTINE SUB_1 (F)
USE MOD_A
B=2.0
WRITE (*,*) B,F
f=3.0
END SUBROUTINE SUB_1
3.000000
Press any key to continue . . .
should it not give an error? I have written code like subroutine SUB_1 and I am concerned that it is incorrect, even though it seems to work. Have I been getting away with something that is wrong?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Intel Fortran does have an option /assume:dummy_aliases, which lets the compiler know that such aliases may exist and therefore optimizations related to that are inhibited.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Program Main
real x,y
common /block1/ x
equivalence (x,y)
call sub(y)
End Program Main
Subroutine Sub(y)
real x,y
common /block1/ x
x=5
return
End Subroutine Sub
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
x = 5.0
call sub (x,x)
...
subroutine sub (x,y)
x = x + 1.0
print *, y
...
Now does it print 6 or 5? The answer is that it could print either one, or maybe even 42 (though that is unlikely).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Roberts,
Your code is "correct" and the output is what was directed by the code, however, the output may not be what you intended.
The documentation is grammatically incorrect: "can only" implies it would be impossible to do otherwise. As you have seen, this is not so. Replace "can only" with "should only". i.e. as a good programming practice directive and not a statement of fact.
As Steve points out, it is possible that a good compiler could detect this and issue a warning. But do not rely on this as SUB_1 might be compiled in a sperate assembly and not available during the compilation time of program TEST.
Steve, please comment on the following:
As a measure to protect against this (subroutine compiled separately), consider using an interface declaration for the subroutine that contains the ONLY clause to protect B
INTERFACE
SUBROUTINE SUB_1(F)
USE MOD_A, ONLY: B
REAL :: F
END SUBROUTINE SUB_1
END INTERFACE
From the above interface it is implicit that B, from within MOD_A, will be referenced by SUB_1. And therefore any code calling SUB_1 (and using the INTERFACE declaration) could warn you if B were to be used as a dummy argument to SUB_1. And it could do so without having access to the source code of SUB_1.
Note, you may still have a good reason to pass B in the call so I do not think the code should insist on not permitting B as a calling argument. I haven't tested the above interfaceto see if IVF does perform this warning service. I'll leave that up to you.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It is not sufficient that the variable be "referenced" in order to violate the stamdard here, it must also be stored to or have its definition status change. As this could be in conditional code, it would have to be a run-time check. Intel Fortran does not do this check.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Well...,
I wouldn't want it to be an automaticruntime check as this would produce an Ab-End in a distributed runtime library. The programmer could write a sanity check, perhaps using LOC() to verify the arguments are safe to use, and if not take the appropriate action.
The real place for the warning is at compile time, as this is where the programming error is.
I suppose the ONLY construction could be expanded to include a different keyword for this purpose (NOARG?)
INTERFACE
SUBROUTINE FOO(F)
USE SomeMod, NOARG: A
REAL::F
END SUBROUTINE FOO
END INTERFACE
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If this is sort of what is happening, another question comes to mind. If I pass a variable (scalar, array, or array segment) to a subroutine and then use the %loc function in the subroutine to get the address of that variable, am I sure that I'm getting the address of the variable or could I be getting the address of a register or temp array?
Program MainPrg
real x
integer address
call sub1(x,address)
End Program MainPrg
Subroutine sub1(x,address)
real x
integer address
address=%loc(x)
End Subroutine sub1
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
A sanity check in your program could use %loc to test for improper argument usage.
Also, even if the argument is not registerized the code may have temporal issues where the compiler would not know if two variable names reference the same memory location(s) and the optimization removes seamingly removable statements. Assume F is dummy that references A
F=A+B
Y=A+Z
The optimization code would likely remember A for the second statementand not knowA wasmodified by F=.
Jim
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
>> If your program wants to do such aliasing, compile with /assume:dummy_aliases and then you won't have to worry about it.
That would be a partial fix since I would guess that the option effectively makes the dummies volatile (i.e. code always reaches into memory as opposed to keeping a copy in a register).
The reason this won't always work is that if you have multiple dummies the adverse interaction can span over multiple statements. To fix this would require some rather obtuse programming on the part of the compiler (e.g. a ring buffer for each variable). Additionally, the programmer may want or require the adverse interaction and the compiler wouldn't know the true intentions of the programmer.
These types of problems are particularly nasty to debug.
If the subroutine permits it, consider using pass by value or copy to local temps.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Was there a change in the optimization during version 9.1 that relates to module variables also being referenced as dummies?
In my program, I used to pass everything as dummies. I eventually got tired of doing that and started referencing the variables through modules. It is likely that somewhere I am guitly of referencing the same varible in different ways. So when I saw this thread, I added the assume:dummy_aliases, but it didn't fix the problem, perhaps because of:
"The reason this won't always work is that if you have multiple dummies the adverse interaction can span over multiple statements"
which I could be guilty of that also. (Before this thread, it never crossed my mind that a dummy argument might be stored in a different part of memory than the same variable referenced directly in a use module statement.)
When using a version newer than 9.1.3291.2005 (including version 10) I get the following:
In debug mode, everything is fine. In release mode, about 1 in 20 data sets causes a memory crash of the, "send report to Microsoft, variety.
If I stick to 9.1.3291, or older versions, I can run things ok with both debug and release. I don't think it is a recently added bug in my code, because my new code works fine with the older versions. Additionally, my code from more than a year ago (which is widely distributed) has the 1-in-20 problem if compiled with newer versions.
Something seems to have changed with the compiler. However, my program is around 100,000 lines and it could certainly be a memory leak on my end that is only now being triggered.
Any ideas. Did something change with this optimization after 9.1.3291?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Fortran is by default "pass by reference" therefore arguments represent the address of the data and not a copy of the data as in a "pass by value" system such a C/C++.
Due to this, if you pass a global variable (or one who's scope is outside of the subroutine local variables) then it is possible for the the program to have multiple symbolic references (aliases) to the same storage locations. As long as you are aware of this and take proper actions you should not get into trouble. You can also have aliases to local variables in a call if you use the same variable multiple times in the argument list.
It is not up to the compiler to prohibit you from doing this as it may be perfectly valid for you to do so with your function/subroutine.
Thecommon reasons of a program running in Debug mode but not in Release mode are:
a) Execution with un-initialized variables (often related to implicit variables)
b) Linking in the wrong runtime library (different calling conventions)
c) Stack limits different between Debug and Release mode
d) different .DLLs being loaded.
e) optimization issues
The easiest reason to test might be e). The suggested strategy is to
a) Create a new configuration, call it DebugRelease and specify that it is to copy the configuration settings from Debug configuration.
b) Compile and test the DebugRelease configuration to make sure it runs the same as the Debug configuration.
c) Selectively enable optimizations (keeping debug info) and test for each project.
d) When project found that causes problems then disable optimizations on project and then progress selectively through each file (or groups of files in the project) enabling optimizations.
e) use c) and d) in a manner similar to a binary search (do half of files, then half of half, ...)
f) if you manage to optimize all the files (with debug info) and if the program still runs then start disabling runtime checks (using the c) d) method)
g) if you manage to remove all runtime checks and keep optimizations then look consider the possibility of problem in the release mode of the runtime libraries linked into the application (e.g. you are linking in the incorrect RTL)
Good luck bug hunting
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The Fortran language has rules about what you can and cannot do with aliases. If you violate these rules, the results are unpredictable.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I appreciate the replies.
"it is possible for the the program to have multiple symbolic references (aliases) to the same storage locations. As long as you are aware of this and take proper actions you should not get into trouble."
That is what I thought, but from a previous post:
"The compiler's optimizer takes advantage of the standards prohibition against referencing an aliased argument if the routine causes the aliased variable to be redefined or become undefined."
The sort of thing that pops up in my code is like the following example:
MODULE MOD_A
REAL NodeArray(10)
END MODULE MOD_A
PROGRAM TEST
USE MOD_A
CALL SUB_1 (NodeArray(3))
...
END PROGRAM TEST
SUBROUTINE SUB_1 (Node)
REAL Node
...
CALL SUB_2 (Node)
END SUBROUTINE SUB_1
SUBROUTINE SUB_2 (Node)
USE MOD_A
REAL Node
...
Node = 5.0
NodeArray(3) = NodeArray(3) + 10.0
END SUBROUTINE SUB_2
I initially passed one element of an array (which could actually be an allocatablederived structure) down through some child subroutines. Later, in one of the child subroutines, I wanted to reference other elements of the array, so I added a use module statement back in, but left the dummy arguments in place. Is this problematic?
Regarding likely problems
a) Execution with un-initialized variables (often related to implicit variables)
b) Linking in the wrong runtime library (different calling conventions)
c) Stack limits different between Debug and Release mode
d) different .DLLs being loaded.
e) optimization issues
a) Caused me problems when I switched from CVF to Intel. I've put a lot of time into this one. However, neither a, b, nor c explain why my old code fails with a newer compilor, and my new code works with an old compilor. I'm not explicitly loading or linking any DLLs (static libraries, yes, DLLs no). So this would only be an issue if the compilors after 9.1.3291 load different DLLs.
e) seems to be the answer. I can start with a realease configuration and switch the Optimization setting from "maximise speed" to "disable" and the run time problems go away. Maximise speed is the /O2 setting? I'm running Intel under Visual Studio. What is the syntax to add the maximise speed setting to a single file?
Thanks once again.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
To set properties for a single file in a project, right-click on file name in sloution explorer, the pick properties, optimizations, --- set what you want.
For your other problems (aliases)
I suggest you add conditional compilation code
!DEC$ IF DEFINED (_DEBUG)
if((%loc(Node(1)).ge.%loc(NodeArray(1))
& .and. ((%loc(Node(size(Node))).le.%loc(NodeArray(size(NodeArray))))
& call Bug()
!DEC$ ENDIF
Node = 5.0
NodeArray(3) = NodeArray(3) + 10.0
If you have several such places to test then consider creating a subroutine to verify no conflict of arguments.
Jim
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You may want to try a build with the Static Verifier enabled. Please see the 10.0 documentation for details on that. Some of the warnings it give you may be for things that are not problems, but it can point out real errors. I would suggest downloading and installing the just-released 10.1 version if you want to do this, as SV is improved in that release.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If you have several (many) instances where you want sanity checks then a good way to perform the test is to make a logical function that takes the derived type and the suspected dummy variable and makes the test.
subroutine aSub(A, B, C)
use MOD_FOO
real :: A, B, C
ASSERT((.NOT.WITHIN(FOO,A)))
ASSERT((.NOT.WITHIN(FOO,B)))
ASSERT((.NOT.WITHIN(FOO,C)))
! your code here
...
end subroutine aSub
Then using the preprocessor #define ASSERT according to your requirements (non-code expansion for Release, call to bounds testing function and error for Debug configuration).
You can also use ASSERT to test for NaN, valid reference address (e.g. is %LOC(A).EQ.0). All kinds of good tests (sanity checkes) in the debug version of the code. Good testing leads to good coding.
Hint, note in my prior post FOO is a module derived type variable of Type (TypeFOO) which represents all the variables within MOD_FOO. Consider adding barrier variables to the type.
type TypeFoo
sequence
#ifdef _DEBUG
CHARACTER(LEN=16) :: _BEGIN_
#endif
... ! declare TypeFoo variables
#ifdef _DEBUG
CHARACTER(LEN=1) :: _END_
#endif
end type TypeFoo
The length of _BEGIN_ was chosen as to not interfere with SSE alignment. This can be UNION'ed with the first variable(s) if you do not wish to take up space. The LEN of _END_ can be adjusted to make TypeFoo a multiple of the largest type or derived type within TypeFoo. You do not have to use _BEGIN_ and _END_. Whatever you use, be consistent with all the derived types that you wish to test for conflict of use.
Then in your #include header files
#define WITHIN(t,v) ((%loc(v) .ge. t%_BEGIN_) .and. (%loc(v) .le. t%_END_))
#ifdef _DEBUG
#define ASSERT(x) if(.not. (x)) Call AssertFailure(__FILE__, __LINE__)
#else
#define ASSERT(x)
#endif
Macro WITHIN always gets declared, macro ASSERT is declared or not depending on your needs. You can have your F90 source code free of the !DEC$ conditional assemblies and have clean looking code, yet at the same time the same code is suitable for Debug and Release configurations.
It is not unusual to have two different ASSERT's one for Debugging and one for Release. You may want to test in your release code at least through Beta and some of the earlier revisions. In your production run, when performance matters configure such as to make ASSERT insert no code.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve
Sorry if I seem a bit slow on this (both in my response time and understanding).
"Offhand, I don't see a problem in the code example you posted. As long as you don't store into the same array element using two different names, you're ok. If you think your application has a problem with aliasing, use /assume:dummy-aliases - that's simpler than Jim's suggestion."
In my example
Node = 5
NodeArray(3) = NodeArray(3) + 10
Node is a real number that is an alias for the elment NodeArray(3). Isn't this storing into the same array element? Or do I not understand what storing into the same array element means?
I'm not sure what Jim means by the following:
">> If your program wants to do such aliasing, compile with /assume:dummy_aliases and then you won't have to worry about it.
That would be a partial fix since I would guess that the option effectively makes the dummies volatile (i.e. code always reaches into memory as opposed to keeping a copy in a register).
The reason this won't always work is that if you have multiple dummies the adverse interaction can span over multiple statements."
I had initially read this as "mulitple subroutines" not "multiple dummies". So I had thought thedummy_aliases wasn't going to help. However, if I had any problems with this, maybe the flag solved them. (But I guess I still wonder if my program might be guilty ofwhatever Jim is refering too.) In any event, it didn't solve the underlying problem.
I saw a post on the Static Verifier and did a search. It sounded like the first version had a memory problem with large programs and threw up a lot of warnings on things that were sloppy as opposed to problems. Do you know if the SV is going to be viable with a program that is around 100,000 lines and is broken into static libraries? Another reluctance I have is that I have code that was written in the 80's (common blocks and the like) and is very "sloppy" by modern programming style standards and I'm guessing that I will get many thousands of warning messages.
Jim, thanks for your detailed examples. I will chew over that when I get some time. However, I'm guessing that it would probably be as easy to strip out the dummy arguments and reference everything straight from my modules as to start populating everything with that many %loc statements.
Thanks for the info on setting flags. I didn't realize you could get a properties page for individual files. My experience with memory leaks is that you canmove things around (i.e.turn optimize off for individual files)and sometimes get the problem to disappear, but all you have done is tweaked thememory configuration andburied the underlying problem. So just becauseturning optimize off for some subroutinecausesa specificdata setto run ok,that doesn'tmean that the problem is really in that subroutine. Or am I being too pessimistic?

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page