[net.lang.c] Potential optimisation?

bbanerje@sjuvax.UUCP (B. Banerjee) (01/19/85)

Hi,

Please don't flame me, despite what my .signature entry may say.  This
is in the spirit of honest enquiry.  I don't know whether the following
is feasible in the presence of signals and the like.

I was thinking of the possible ways that C could be sped up, in a
general fashion.  Part of the philosophy of using procedural languages
such as C, is that the incentive is present to break up the program
into small manageable functions.  Much of this incentive is lost if the
function call is overly expensive.

1) The current process of passing parameters on the stack has many
advantages.  Primary among these are the capabilities of declaring
routines that take a variable number of arguments (*Yes*, they are
often necessary, and even clean).  Also, a consistent calling interface
is desirable when linking in separately compiled, or assembly language
routines.  Unfortunately, this adds a great deal of unnecessary
overhead.

One way to handle this would be to handle calls to 'static' functions
differently, based on observed usage in the rest of the file (NOTE:
this probably would require multiple passes).  Parameterless static
functions could be called via a 'jsr' or equivalent.  Functions with
fewer than 'n' constant arguments could have their arguments passed in
registers.  Static functions whose usage indicated a VARARGS usage
would have the parameters passed in the usual fashion.  Static
functions which are only referenced once or twice could be expanded
inline.  Now, so far there is nothing new here.  However....

I took a look at a lot of C code on my (4.2 BSD) system.  An informal
guess would be that over 50% of the functions in the source files could
be declared as 'static'.  Now, let us say that we have another keyword
'exported' which is used to label those functions which are called from
other source files.  All functions which were *not* declared to be
*exported* would be considered static by default.  This would allow the
efficient generation of code.  It would also be easier to read code
that used this, as one would not have to sit down with a cross
reference listing.  Furthermore, register allocation could be done on
an inter-functional basis.  Lastly, the code could be portable through
the use of ...

# define exported /* foobar */

in a header file, effectively stripping them in the case where they
were not understood.

2)  In a UNIX C compiler (to the best of my knowledge) two assembly
procedures CSV and CRET are used to save and restore the registers in
the *called* procedure.  I fail to see why this is desirable.  The
*calling* procedure has full knowledge of which registers are being
used and can save them itself.  This may not result in savings, but I
don't see where it can result in a performance degradation.

3)  Automatic data definitions are always allocated space on the
stack.  This is fine in the presence of recursive functions.  However,
in practice, recursive functions are not very heavily used.  Some means
of data flow analysis might allow the allocation of automatic data
statically at compile time, with each datum at a constant offset from
the start of the object file.  The data flow analysis could enable the
re-use of space.  This would allow processes to take up less space
while running, as the maximum stack size would be known at compile
time.  Of course, recursive functions would still have their local data
allocated on the stack.

Well, what do you think.  I would appreciate some feedback on this.
Please reply by mail.  If the responses warrant it, I will summarize to
this group.

Regards,

-- 
				Binayak Banerjee
		{allegra | astrovax | bpa | burdvax}!sjuvax!bbanerje
P.S.
	Send Flames, I love mail.

dillon@ucbvax.ARPA (The Sherif "Matt D.") (01/22/85)

> Hi,
> 
> Please don't flame me, despite what my .signature entry may say.  This
> is in the spirit of honest enquiry.  I don't know whether the following
> is feasible in the presence of signals and the like.
> 
> I was thinking of the possible ways that C could be sped up, in a
> general fashion.  Part of the philosophy of using procedural languages
> such as C, is that the incentive is present to break up the program
> into small manageable functions.  Much of this incentive is lost if the
> function call is overly expensive.
> 
> 1) The current process of passing parameters on the stack has many
> advantages.  Primary among these are the capabilities of declaring
> routines that take a variable number of arguments (*Yes*, they are
> often necessary, and even clean).  Also, a consistent calling interface
> is desirable when linking in separately compiled, or assembly language
> routines.  Unfortunately, this adds a great deal of unnecessary
> overhead.
> 
> One way to handle this would be to handle calls to 'static' functions
> differently, based on observed usage in the rest of the file (NOTE:
> this probably would require multiple passes).  Parameterless static
> functions could be called via a 'jsr' or equivalent.  Functions with
> fewer than 'n' constant arguments could have their arguments passed in
> registers.  Static functions whose usage indicated a VARARGS usage
> would have the parameters passed in the usual fashion.  Static
> functions which are only referenced once or twice could be expanded
> inline.  Now, so far there is nothing new here.  However....
> 
> I took a look at a lot of C code on my (4.2 BSD) system.  An informal
> guess would be that over 50% of the functions in the source files could
> be declared as 'static'.  Now, let us say that we have another keyword
> 'exported' which is used to label those functions which are called from
> other source files.  All functions which were *not* declared to be
> *exported* would be considered static by default.  This would allow the
> efficient generation of code.  It would also be easier to read code
> that used this, as one would not have to sit down with a cross
> reference listing.  Furthermore, register allocation could be done on
> an inter-functional basis.  Lastly, the code could be portable through
> the use of ...
> 
> # define exported /* foobar */
> 
> in a header file, effectively stripping them in the case where they
> were not understood.
> 
> 2)  In a UNIX C compiler (to the best of my knowledge) two assembly
> procedures CSV and CRET are used to save and restore the registers in
> the *called* procedure.  I fail to see why this is desirable.  The
> *calling* procedure has full knowledge of which registers are being
> used and can save them itself.  This may not result in savings, but I
> don't see where it can result in a performance degradation.
> 
> 3)  Automatic data definitions are always allocated space on the
> stack.  This is fine in the presence of recursive functions.  However,
> in practice, recursive functions are not very heavily used.  Some means
> of data flow analysis might allow the allocation of automatic data
> statically at compile time, with each datum at a constant offset from
> the start of the object file.  The data flow analysis could enable the
> re-use of space.  This would allow processes to take up less space
> while running, as the maximum stack size would be known at compile
> time.  Of course, recursive functions would still have their local data
> allocated on the stack.
> 
> Well, what do you think.  I would appreciate some feedback on this.
> Please reply by mail.  If the responses warrant it, I will summarize to
> this group.
> 
> Regards,
> 
> -- 
> 				Binayak Banerjee
> 		{allegra | astrovax | bpa | burdvax}!sjuvax!bbanerje
> P.S.
> 	Send Flames, I love mail.

	Flame?... I wouldn't think of it.  I see a flaw in your thinking,
though.  Registers, by definition CANNOT change from original values after
a subroutine call returns.  So, the compiler pushes the registers on the
stack before a call, and pulls them back after a call.  This is nessasary
considering you can have constructs such as 'register int charlie'.  
Variables in registers go extremely fast, as you might guess.  Also, many
assembly languages such as Perkin-Elmer3230 provide a single instruction
for 'pushing' registers on the stack.

	You can't ignore registers.

	Well that's my piece of the action....Anybody else?



	

ksbszabo@wateng.UUCP (Kevin Szabo) (01/23/85)

Re: A followup with 100 lines of quoted article....

ARGH!! Please don't follow up to an article and include the WHOLE original
posting! Take a few minutes and very carefully pull out the parts 
that set the context of the note, and point to your argument.

Now I feel better.
-- 
Kevin Szabo  watmath!wateng!ksbszabo (U of Waterloo VLSI Group, Waterloo Ont.)

ag4@pucc-h (Angus Greiswald the fourth) (01/23/85)

> > 2)  In a UNIX C compiler (to the best of my knowledge) two assembly
> > procedures CSV and CRET are used to save and restore the registers in
> > the *called* procedure.  I fail to see why this is desirable.  The
> > *calling* procedure has full knowledge of which registers are being
> > used and can save them itself.  This may not result in savings, but I
> > don't see where it can result in a performance degradation.

>      ... Registers, by definition CANNOT change from original values after
> a subroutine call returns.

Not sure I follow you there.  Which definition are you talking about?

>                         [saving and restoring registers] is nessasary
> considering you can have constructs such as 'register int charlie'.  

If the calling procedure saves all the registers that are being used,
and restores them itself, then the called procedure can do anything it
pleases with the registers, including, of course, use register variables.

--
" ... "

Jeff Lewis                                         vvvvvvvvvvvv
{decvax|ucbvax|allegra|seismo|harpo|teklabs|ihnp4}!pur-ee!lewie
                                                   ^^^^^^^^^^^^

robert@gitpyr.UUCP (Robert Viduya) (01/25/85)

> 2)  In a UNIX C compiler (to the best of my knowledge) two assembly
> procedures CSV and CRET are used to save and restore the registers in
> the *called* procedure.  I fail to see why this is desirable.  The
> *calling* procedure has full knowledge of which registers are being
> used and can save them itself.  This may not result in savings, but I
> don't see where it can result in a performance degradation.
> 

Then there's the Pyramid 90x machines where the registers (at least 32 of
them) are 'saved' (not really 'saved', more like 'pushed down') by the
machine itself without the need of special assembly procedures.  But that
topic was discussed a few months ago.


				robert
-- 
Robert Viduya
    Office of Computing Services
    Georgia Institute of Technology, Atlanta GA 30332
    Phone:  (404) 894-4669

...!{akgua,allegra,amd,hplabs,ihnp4,masscomp,ut-ngp}!gatech!gitpyr!robert
...!{rlgvax,sb1,uf-cgrl,unmvax,ut-sally}!gatech!gitpyr!robert

brooks@lll-crg.ARPA (Eugene D. Brooks III) (01/31/85)

> > 2)  In a UNIX C compiler (to the best of my knowledge) two assembly
> > procedures CSV and CRET are used to save and restore the registers in

Only on pdp11's,  VAXES simply use call and ret and a register mask