[comp.lang.fortran] COMMON and SAVE statements

ray@rogue.llnl.gov (Ray, Scott) (08/03/90)

I have been taught that it is good programming practice to use SAVE
statements in conjunction with labeled COMMON blocks to insure that the
variables in COMMON get saved when exiting a program module.  Apparently,
the FORTRAN 77 standard makes no such guarantee unless the SAVE statement
is used.  Thus, when writing my own codes I religiously stick in the
SAVE statement.  However, I work with a lot of hand-me-down codes
written by other people who take no such precautions and have never
encountered any problems that could be traced to the COMMON variables
being lost due to the lack of a SAVE statement.  So, two questions
come to mind:

1. Are there any quasi-FORTRAN 77 compliant compilers on machines in
   widespread use in the 1990's where COMMON variables can actually
   become undefined when a program module is exited and a SAVE statement
   has not been used?  In other words, is the SAVE statement really
   necessary in practice (ignoring the standard)?  If so, on which
   machines and under what conditions?

2. What could possibly be the motivation for the standard allowing
   variables in COMMON to be become undefined without a SAVE statement?
   I can't think of a case where this would be desirable behavior.
   Hence why isn't it built into the COMMON framework?

Note that I am restricting these questions to variables in COMMON.  Using
a SAVE with local variables is a much more understandable issue.

					Scott Ray
					ray@icdc.llnl.gov

maine@elxsi.dfrf.nasa.gov (Richard Maine) (08/04/90)

On 3 Aug 90 09:05:43 GMT, ray@rogue.llnl.gov (Ray, Scott) said:

Ray> 1. Are there any quasi-FORTRAN 77 compliant compilers on machines in
Ray>    widespread use in the 1990's where COMMON variables can actually
Ray>    become undefined when a program module is exited and a SAVE statement
Ray>    has not been used?  In other words, is the SAVE statement really
Ray>    necessary in practice (ignoring the standard)?  If so, on which
Ray>    machines and under what conditions?

On CDC Cyber systems running NOS (I don't know about the newer NOS/VE
systems; I haven't used them) using the segment loader (basically a
form of memory overlay).  Non-saved COMMON blocks could be swapped out
of memory when the referencing routines returned.  Program code and
non-saved local variables were also swapped out.

As I recall, even saved COMMON blocks and local variables could be
swapped out of memory, but they were copied to disk and restored
as appropriate.  The non-saved ones were just discarded and became
corrupted with whatever next happened to use the same memory.

I recall the CDC compilers as being pretty good about standard
conformance.  They didn't support some of the extensions I've since
become accustomed to (lower case and long variable names come to mind),
but they did honest FORTRAN pretty well.

Ray> 2. What could possibly be the motivation for the standard allowing
Ray>    variables in COMMON to be become undefined without a SAVE statement?
Ray>    I can't think of a case where this would be desirable behavior.
Ray>    Hence why isn't it built into the COMMON framework?

I guess to save memory space on systems where it is tight (relative to
your requirements).  It certainly was tight on the Cybers of that
vintage.  I sure don't miss those days.  Segmentation caused lots of
interesting "features".  Of course, it also taught me to use the SAVE
statement religiously where needed.




--

Richard Maine
maine@elxsi.dfrf.nasa.gov [130.134.64.6]

jrbd@craycos.com (James Davies) (08/04/90)

In article <65861@lll-winken.LLNL.GOV> ray@rogue.llnl.gov writes:
>
>2. What could possibly be the motivation for the standard allowing
>   variables in COMMON to be become undefined without a SAVE statement?
>   I can't think of a case where this would be desirable behavior.
>   Hence why isn't it built into the COMMON framework?

From the Fortran 77 standard, page 17-4, section 17.3:

	(6)  The execution of a RETURN statement or and END
	     statement within a subprogram causes all entities
	     within the subprogram to become undefined except for
	     the following:

			(...)
		(d) Entities in a named common block that appears in
		    the subprogram and appears in at least one other
		    program unit that is either directly or
		    indirectly referencing the subprogram.

Basically, this means that the standard allows the common storage to
be reused for other purposes when a subprogram exits and no other
currently active subprogram references it.  This would allow a smart
compiler and/or linker to use the same area for two named common
blocks as long as they aren't both active on the same branch of the
calling tree.  (In practice, I don't know of any compiler that does this.
It would probably break a lot of programs, especially programs that don't
routinely declare every named common block in the main program.)

In the presence of enough interprocedural information, a compiler could also
use this provision of the standard to aid in optimization - if a common
block was allowed to become undefined at subprogram exit, then variables
in the common block need not be treated as output from the subprogram,
and this might help dead code elimination, for example.

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (08/04/90)

In article <65861@lll-winken.LLNL.GOV>, ray@rogue.llnl.gov (Ray, Scott) writes:
> 2. What could possibly be the motivation for the standard allowing
>    variables in COMMON to be become undefined without a SAVE statement?

Overlays.  Notionally, a COMMON block comes into existence when a
program unit mentioning it is entered, and remains in existence as
long as there is a running program unit that mentions it.  After that
it can go away.  The specification in the standard allows an
implementation to just deallocate the block then, and reallocate it
with undefined contents next time it comes into existence, just like
a local variable.  The standard _also_ allows an implementation to
keep common blocks around forever, just like local variables.

>    I can't think of a case where this would be desirable behavior.

Remember, computers used to be _tiny_.  There's a slow sorting routine
called quicksort which was invented about 1960 so that sorting could be
done _at all_ on a machine with about 256 words of main memory and
16k words of backing store.  By the time of F77, that kind of limitation
was the unlamented past, but 8Mbytes on your desktop was still the future.
Using overlay techniques with data as well as code meant that you _could_
get as much memory re-use out of Fortran as you could out of Algol or Pascal.

-- 
Distinguishing between a work written in Hebrew and one written in Aramaic
when we have only a Latin version made from a Greek translation is not easy.
(D.J.Harrington, discussing pseudo-Philo)

shenkin@cunixf.cc.columbia.edu (Peter S. Shenkin) (08/06/90)

In article <65861@lll-winken.LLNL.GOV> ray@rogue.llnl.gov writes:
>2. What could possibly be the motivation for the standard allowing
>   variables in COMMON to be become undefined without a SAVE statement?

This would allow  storage taken up by COMMON blocks not currently in use to
be used for other purposes;  eg, to store automatic variables in other 
functions, or to store active COMMON blocks.

I believe that the standard requires COMMON blocks to be saved until the
entire tree of functions using them has exited;  thus COMMON blocks declared
in MAIN will be saved without an explicit SAVE anyway.  Would someone out there
more knowledgable than I please correct me if I am incorrect, or confirm this
if I am correct?

	-P.
************************f*u*cn*rd*ths*u*cn*gt*a*gd*jb**************************
Peter S. Shenkin, Department of Chemistry, Barnard College, New York, NY  10027
(212)854-1418  shenkin@cunixc.cc.columbia.edu(Internet)  shenkin@cunixc(Bitnet)
***"In scenic New York... where the third world is only a subway ride away."***

hirchert@ux1.cso.uiuc.edu (Kurt Hirchert) (08/07/90)

In article <65861@lll-winken.LLNL.GOV> ray@rogue.llnl.gov writes:
>2. What could possibly be the motivation for the standard allowing
>   variables in COMMON to be become undefined without a SAVE statement?
>   I can't think of a case where this would be desirable behavior.
>   Hence why isn't it built into the COMMON framework?

a. As others have noted, the original motivation was overlays.  Most people
   seem to see this as an obsolete feature now that address spaces have become
   so much larger.  I agree that it is rare today to have so much code that
   a program will not fit in memory, but data usage has kept pace with memory
   sizes, do data overlaying would still be beneficial.  I have heard some
   second-hand reports of systems that would do this, but since I haven't seen
   them myself, I can't swear that they actually exist.

b. In a MIMD parallel processing environment, it would be possible to create
   separate instances of an unSAVEd COMMON block for each processor (or each
   task), so that multiple copies of a function or loop can be executed
   simultaneously operating on the "same" COMMON block.  (Some vendors have
   created special TASK COMMONs rather than use the SAVE/noSAVE attribute to
   make this distinction.)

Also, as someone else pointed out, if you declare your COMMON block in your
main program, you don't need to SAVE them explicitly.  (This indirect SAVE
behavior may be why vendors created TASK COMMON rather than implementing
unSAVEd COMMON this way.)
-- 
Kurt W. Hirchert     hirchert@ncsa.uiuc.edu
National Center for Supercomputing Applications

gilmore@vax1.acs.udel.EDU (Scott Gilmore) (08/07/90)

In article <1990Aug6.215727.21612@ux1.cso.uiuc.edu> hirchert@ux1.cso.uiuc.edu (Kurt Hirchert) writes:
>Also, as someone else pointed out, if you declare your COMMON block in your
>main program, you don't need to SAVE them explicitly. 
>-- 
>Kurt W. Hirchert     hirchert@ncsa.uiuc.edu
>National Center for Supercomputing Applications

What about BLOCK DATA subprograms?  Does this implicit save behavior also 
apply to them?
-- 
Scott Gilmore                                       gilmore@vax1.udel.edu
Mechanical Engineering and Center for Composite Materials, U. of Delaware

hirchert@ux1.cso.uiuc.edu (Kurt Hirchert) (08/07/90)

In article <6814@vax1.acs.udel.EDU> gilmore@vax1.udel.edu (Scott Gilmore) writes:
>In article <1990Aug6.215727.21612@ux1.cso.uiuc.edu> hirchert@ux1.cso.uiuc.edu (Kurt Hirchert) writes:
>>Also, as someone else pointed out, if you declare your COMMON block in your
>>main program, you don't need to SAVE them explicitly. 
>
>What about BLOCK DATA subprograms?  Does this implicit save behavior also 
>apply to them?
>-- 
>Scott Gilmore                                       gilmore@vax1.udel.edu
>Mechanical Engineering and Center for Composite Materials, U. of Delaware

No.  If a variable or array in a COMMON block is initialized (through a BLOCK
DATA) and not subsequently redefined, it will remain defined even if not SAVEd,
but that's all.  In other words, if you are using a value in COMMON as a kind
of global constant, it will work, but the mere fact that you initialize a
COMMON block is not enough in general to make it retain values between CALLs.
(In the overlay model, this means that an unSAVEd COMMON can still be moved
out to a branch overlay with the initialization of that COMMON being done
each time the overlay is loaded.)
-- 
Kurt W. Hirchert     hirchert@ncsa.uiuc.edu
National Center for Supercomputing Applications

fisher@Alliant.COM (Larry Fisher) (08/11/90)

On 3 August 1990, Richard Maine) wrote:
>
>On CDC Cyber systems running NOS (I don't know about the newer NOS/VE
>systems; I haven't used them) using the segment loader (basically a
>form of memory overlay).  Non-saved COMMON blocks could be swapped out
>of memory when the referencing routines returned.  Program code and
>non-saved local variables were also swapped out.
>
>As I recall, even saved COMMON blocks and local variables could be
>swapped out of memory, but they were copied to disk and restored
>as appropriate.  The non-saved ones were just discarded and became
>corrupted with whatever next happened to use the same memory.
>
Ah, yes, the segmented loader.  One of the least-used features of the
CYBERS; right next to LO72 and the 8-BIT subroutines.

Yeah, saved COMMON blocks were written back to disk when a segment
was "swapped" out.  A handy feature of the segmented loader was that
the code didn't have to have SAVE statements --- named COMMON blocks
could be saved via the segmented loader SAVE directive.  Equally
helpful is the save switch on the Fortran compiler here at Alliant.

>I guess to save memory space on systems where it is tight (relative to
>your requirements).  It certainly was tight on the Cybers of that
>vintage.  I sure don't miss those days.  Segmentation caused lots of
>interesting "features".  Of course, it also taught me to use the SAVE
>statement religiously where needed.

Yeah.  An interesting feature [severe defiency] of the CYBER loader
was that you couldn't even get a external reference cross-reference
map if the program didn't fit in 400000B (131k words).  I, like others,
ended up writing a set of programs to cross-reference routines and
common blocks.  The program call-tree could be manipulated and
segmented loader directives generated.  Such fun :-).
-- 
Larry Fisher			Domain:	fisher@alliant.com
Alliant Computer Systems	UUCP:	{mit-eddie|linus}!alliant!fisher
Littleton, MA 01460		Phone:	(508) 486-1449

bam@bnlux0.bnl.gov (Bruce A. Martin) (08/17/90)

In Article 3664 of comp.lang.fortran, ray@rogue.llnl.gov (Ray, Scott) asked:
>...
>1. Are there any quasi-FORTRAN 77 compliant compilers on machines in
>   widespread use in the 1990's where COMMON variables can actually
>   become undefined when a program module is exited and a SAVE statement
>   has not been used?  In other words, is the SAVE statement really
>   necessary in practice (ignoring the standard)?  If so, on which
>   machines and under what conditions?
>
>2. What could possibly be the motivation for the standard allowing
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   variables in COMMON to be become undefined without a SAVE statement?
>   I can't think of a case where this would be desirable behavior.
>   Hence why isn't it built into the COMMON framework?
>
>Note that I am restricting these questions to variables in COMMON.  Using
>a SAVE with local variables is a much more understandable issue.
>
>					Scott Ray
>					ray@icdc.llnl.gov

Several posters then pointed out that variables could lose their value
when the COMMON block is part of an overlay.  Some also noted that,
back in the good old days when kilobytes were scare, you couldn't affort
to keep everything around just in case somebody would need it later.

Also, in Article 3695, hirchert@ux1.cso.uiuc.edu (Kurt Hirchert) stated that:
>...
>a. As others have noted, the original motivation was overlays.  

reluctant as I am to quibble with someone as lucid and (usually) precise
as KWH, I must say that this misses the point somewhat:  

	Overlays had little or nothing to do with the
	"motivation" for the SAVE statement!

The "motivation" was simply that different processors handled memory 
in different ways.  Some (especialy Burroughs) actually used automatic
allocation, and gave up memory that wasn't needed.  

[ Of course, IBM "invented" virtual memory a decade later.	]
[ However in those days, efficient use of resources just wasn't	]
[ considered be part of a good marketing strategy in Armonk.	]
[ And besides, who cares about Algol machines, anyhow?  ;^)	]
[ And, now back to your local station.	]

It was often stated during discussions (while 77 was being developed) that
what was really needed was an UNSAVE statement, so that the default was SAVE.
However, the best we could do was add SAVE because the (66) default already
was that unused blocks were vulnerable to loss.  Upward compatiblility
required them to stay so.  

				-=o=-

To understand "the motivation for the standard allowing" something, one
must consider what a language standard is and why it exists.  A language
standard not only defines the legal forms (syntax, combinations, etc.) 
but it must also specify the interpretation -- if any -- for every 
form (and combination) that is legal.  Thus, the standard is realy two
documents in one:  one to say what is permissible in the language (and
therefore in a program), and another to say what a conforming processor
must do.  Unfortunately, these two purposes can get confused (often by
the readers, and sometimes by the writers).

Consequently, a standard cannot say that something is legal for one
processor but illegal for another.  Nor can it provide alternate
interpretations for the same form.  When processors differ in the way they
handle something, and when that difference can affect program behavior, 
the best a standard can do is to say that the interpretation (i.e. the
behavior of the program) is "processor dependent" -- EOR -- disallow it.

One way to introduce processor dependence without outlawing too many
programs is to say that a value may become "undefined" (which means
unpredictable) under certain circumstances, but that the program is
still legal if the value is never used.  It is the *reference* to the
undefined value that makes the program nonstandard, not its creation.
(Unfortunately, this is hard to detect and creates "completeness" problems.)

				-=o=-

In X3.9-1978, Section 1.4 ("Conformance") says that an "executable program ()
conforms to this standard if it uses only those forms and relationships 
described herein and if the executable program has an interpretation 
according to this standard".  Section 1 notes in Appendix B also contains
a useful discussion of conformance issues.

By ANSI rules, the standard may not say anything about programs that are
nonstandard -- not even to limit what a standard-performing processor may
do to them!  Therefore, saying that a program is not standard (e.g. uses 
an undefined value) has exactly the same effect as saying that its behavior
is "processor dependent".  The standard is required to be silent about
the behavior of nonstandard programs!  

The result of this is that "undefined", "illegal", and "processor 
dependent" all mean the same thing:  i.e. that the situation is not 
covered by the standard and that the standard-conforming processor is 
free to do as it pleases to such a program (including resetting every
fourth variable to a random number and proceeding merrily along without 
telling you!!  Or maybe like changing the owner's password!).

				-=o=-

Returning to the main point, the "motivation" behind most of X3.9-1966
was to describe the *intersection* of the behaviors of all existing
Fortran processors (plus a few cleanups and extensions), and to exclude
from the language things that would cause processor-dependent behavior.

Therefore, if some existing processors treated a situations in a particular
way (like having more than six characters in a storage unit, or like
reusing memory for unused locals and common blocks) -- or even if it 
merely seemed reasonable that some future processors *might* want to
do things that way -- then the motivation of X3.4.3 was to write the
standard so as to allow that implementation while defining the parts
of the interpretation that needed to be consistent.  

The DO loop provides several good examples of this:  Some processors
keep the index in a variable while others keep it in registers and 
maybe store its last value or next value at the end; some fetch the
final value and increment first, while others compare to memory or
fetch them later; some processors have only three registers for nested
loops; etc.  Therefore, the committee defined a subset of the possible
loop arrangements which would have the same behavior on all processors,
and outlawed the rest.  This is why DO parameters may not be altered
within the loop and DO index values are undefined afterwards -- the
standard says that all bets are off if go outside this subset, but it
cannot say what exactly what will happen.

The moral of the story is that standards "allow" for differing behavior
that could occur on some processors by saying that a form is illegal
or that the value is not dependable (and therefore is not legally usable).


BAM		     			     -/s/-
    (bam@bnlux0.bnl.gov)		 Bruce A. Martin	
[Address given for identification only.] Grumman Space Systems
[Every conceivable disclaimer applies!!] c/o National Synchrotron Light Source
[Opinions are mine only, & will change,] Bldg. 725C, Brookhaven National Lab.	
[without notice, whenever appropriate!!] Upton, NY  11973	(516) 282-3712	

[DISCLAIMER:  The statements made herein do not necessarily reflect those of 
any other individual, group, organization, corporation, or government agency.  
My work on X3J3 does not in any way represent official policies or positions
of my past or present employers nor those of any other sponsor or affiliate.]

bam@bnlux0.bnl.gov (Bruce A. Martin) (08/17/90)

>...
>I believe that the standard requires COMMON blocks to be saved until the
>entire tree of functions using them has exited;  thus COMMON blocks declared
>in MAIN will be saved without an explicit SAVE anyway.  Would someone out there
>more knowledgable than I please correct me if I am incorrect, or confirm this
>if I am correct?
>

Correct.  However, the standard requires that if SAVE is specified for a
given block in one procedure, it must be so specified in ALL procedures
(other than the main program) which reference it!

At the last minute (San Diego, 1977 Jan.), somebody realized that a loader
could have problems when the the last subroutine says that some COMMON block
declared by all of the preceding ones had to be kept in SAVE space.  This 
led to the rule that you must say SAVE in all or none of the subroutines.
Logically, this should apply when the block is in main, but that was too
hard to swallow.  Therefore, a loader could still have a problem when the
main program is the last module to be loaded!  ;-)

Section 8.9 is a bit confusing if you take pieces of it out of context.
The *effect* of putting a block in main is the same as if you had had a
SAVE statement in each subroutine that really used it.  However, if you
do specify SAVE in one of the subroutines -- even tho it doesn't change
anything -- then you must specify it in the others.  

Some readers are confused by the words which say that when the block appears
in the main program then "a SAVE statement in the subprogram has no efect".
It has no effect, but it is still required in ALL of those subprograms if
it appears in ANY of them.  It is "optional" only in the main program.A

I think there was an interpretation item on this in one of the FIBs.


BAM		     			     -/s/-
    (bam@bnlux0.bnl.gov)		 Bruce A. Martin	
[Address given for identification only.] Grumman Space Systems
[Every conceivable disclaimer applies!!] c/o National Synchrotron Light Source
[Opinions are mine only, & will change,] Bldg. 725C, Brookhaven National Lab.	
[without notice, whenever appropriate!!] Upton, NY  11973	(516) 282-3712	

jerry@violet.berkeley.edu (Jerry Berkman) (09/13/90)

In article <2065@bnlux0.bnl.gov> bam@bnlux0.bnl.gov (Bruce A. Martin) writes:
>
>The DO loop provides several good examples of this ...
> ... the committee defined a subset of the possible
>loop arrangements which would have the same behavior on all processors,
>and outlawed the rest.  This is why DO parameters may not be altered
>within the loop and DO index values are undefined afterwards -- the
>standard says that all bets are off if go outside this subset, but it
>cannot say what exactly what will happen.
>
>
>BAM		     			     -/s/-
>    (bam@bnlux0.bnl.gov)		 Bruce A. Martin	

I got a little confused about whether "standard" is referring to the
1966 or 1977 standard.  In the 1977 standard (section 11.10.2):

	"When a DO-loop becomes inactive, the DO-variable of the
	 DO-loop retains its last defined value."
	
	- Jerry Berkman, U.C. Berkeley, (415)642-4804
	  jerry@violet.berkeley.edu

(normal disclaimers: opinions are my own, not my employers, etc.) opinions are my own, not my employers, etc.)