From: jlg@cochiti.lanl.gov (Jim Giles)
Subject: Re: Scientists as Programmers (was Re: Smal
Organization: Los Alamos National Laboratory
Date: Tue, 1 Sep 1992 15:57:02 GMT

In article <1992Aug31.233148.471@ccu1.aukuni.ac.nz>, ecmtwhk@ccu1.aukuni.ac.nz (Thomas Koenig) writes:
|> jlg@cochiti.lanl.gov (Jim Giles) writes:
|> 
|> [about subroutine calls]
|> 
|> >The *real* cost is in
|> >register scheduling (including canonical interface protocols) around
|> >the call, as well as a break in optimization basic-blocks (and many `live'
|> >values must be assumed `killed' by the call).  Herman Rubin was right
|> >to begin with, procedure calls are, and will remain for a long time, 
|> >among the most expensive of operations.  Calls would be expensive even if
|> >the specific branch instructions used to implement and return from them
|> >were *free*.
|> 
|> Depends on the architecture you are using. On a MIPS, for example, the
|> ucode optimizer does global register optimization across function calls,
|> so a subroutine call is relatively cheap.

Unfortunately, I don't have the machine you mention.  However, I'm 
willing to bet that if you compare inlined code to code which makes 
calls, the inlined code will be *considerably* faster - even in your
environment that makes such calls so "cheap."  In fact, I seem to 
remember that the MIPS stuff includes (or has researched) ways to 
inline code relatively automatically - they would have wasted time 
on such a feature if the calls were already cheap.

|> [...]
|> On more conventional systems, try and avoid using global variables in
|> loops with subroutine calls. This should keep the optimizer happy (and
|> your code clearer, too).

On all machines, I write to make my code clear *first*.  I optimize it
after that.  Globals are usually *introduced* for the purposes of
clarity.  They are usually *kept* because they are more efficient as
well (one less level of indirection within the subroutine when referencing
them).  Optimization is broken whether you pass the data as globals
OR parameters - either way, the variables are referenced *outside* the 
control of the local routine and it must be assumed that they might have 
been changed.

Clarity is achieved, not by forcing a strict hierarchical ordering on
your data usage, but by localizing data to the routines to which it is
relevant.  Placing the data into a named global object (like a MODULE
for example) and referencing that object *only* from the routines to
which the data is relevant is one of the ways to localize the data.  If 
you are lucky, you can place all the relevant routines *in* the MODULE, 
but  this is not always the most clear nor the most efficient solution.
(Besides, the data is still global, from the point of view of the routines
within the MODULE.  It is not visible from outside though.  This level
between "global" and "local" might be called "parochial data."  It
introduces similar optimization problems - but they should be resolvable
if the *whole* module is always compiled together.)

Arbitrary rules of coding based on some CS prof's esthetic preferences
generally leads to less efficient *and* less clear code.  Each case
is different.  Clarity calls for judgement, and efficiency *somtimes*
introduces compromises.

-- 
J. Giles