[comp.sys.hp] alloca

net@tub.UUCP (Oliver Laumann) (08/09/90)

I need an implementation of alloca() for the HP9000/3xx.  The alloca()
from libPW.a (which makes use of malloca/free) doesn't work for my 
application; I need an alloca() that actually allocates space on the
stack.  I came up with the following (I snarfed it from the Sun-3's
libc.a and converted the syntax):

_alloca:
    mov.l	(%sp),%a0
    mov.l	4(%sp),%d0
    addq.w	&3,%d0
    and.l	&-4,%d0
    sub.l	%d0,%a7
    mov.l	%sp,%d0
    addq.w	&8,%d0
    jmp		(%a0)

Unfortunately it doesn't work on the HP9000/3xx.  Sometime after my
application has invoked alloca() the first time, the contents of a
register (a local variable) is garbled.

Is it possible to write a "real" alloca() for the HP at all, or is
there some sort of conflict with the C compiler (i.e. does the way
the stack pointer is handled make usage of alloca() impossible)?

Thanks,
--
    Oliver Laumann, Technical University of Berlin, Germany.
    pyramid!tub!net   net@TUB.BITNET   net@tub.cs.tu-berlin.de

mjs@hpfcso.HP.COM (Marc Sabatella) (08/09/90)

>Is it possible to write a "real" alloca() for the HP at all, or is
>there some sort of conflict with the C compiler (i.e. does the way
>the stack pointer is handled make usage of alloca() impossible)?

The conventional alloca() depends on the frame pointer / stack pointer model,
in which a function references its local and parameters off of the frame
pointer.  alloca() diddles the stack pointer and returns, hoping that no one
will notice, since all references are off a6 not a7, and a7 will be restored
on the unlk.

The Series 300 C compiler is smart enough to remove link/unlk pairs and convert
references off a6 into references off a7.  For this, it needs complete
information about a7, and alloca() breaks the basic assumption that the stack
pointer is preserved across the call.  If you do not optimize (not even with
"+O1"), you may be able to get away with using the standard alloca().

But I strongly advise against it.  By its very nature, alloca() is non-portable
(ie, it won't even work on machines that don't use the fp/sp model), and if
one day the "remove link/unlk" feature is moved out of the optimizer and into
the compiler proper, it will cease to function on the 300.

--------------
Marc Sabatella (marc@hpmonk.fc.hp.com)
Disclaimers:
	2 + 2 = 3, for suitably small values of 2
	Bill and Dave may not always agree with me

rer@hpfcdc.HP.COM (Rob Robason) (08/10/90)

Oliver> Is it possible to write a "real" alloca() for the HP at all

I've seen at least one hack that claimed to be an alloca() for the 300.
The problem is that the author declined to guarantee that it would work
from one release to the next.  So it was of little use.  I think this is
an inherent problem with alloca()s because they rely on knowledge about
how the stack is layed out in a specific implementation, if that changes
due to a compiler improvement, for example, it's busted.

While I know there are some pretty significant applications that make
heavy use of alloca(), it has proved so troublesome that none of the
standards organizations have dared touch it.  Neither POSIX, SVID, XPG3,
OSF nor ANSI-C support alloca().  ANSI-C, in fact makes this point in the
rationale:

    "Some implementations provide a function (often called alloca) which
    allocates the requested object from automatic storage; the object is
    automatically freed when the calling function exits.  Such a
    function is not efficiently implementable in a variety of
    environments, so it was not adopted in the standard."

For this reason, most standards (and HP) are recommending that functions
and applications be modified to use malloc/free or some other standard
mechanism in order to be portable to the widest range of standards
conforming systems.

Many of the applications I've looked at that used alloca did so out of
laziness, rather than need:  It was a convenient way to be sure that
everything was freed without having to think.  In these cases the fix is
easy.  There are some applications where it will be hard, but possible,
to work around alloca being absent.

I know this isn't what you wanted to hear.  You may obtain an alloca
from another source and find it adequate for now.  You just need to know
that it's not necessarily the best way to solve the problem.

Rob "Don't kill the messenger" Robason

shankar@hpclscu.HP.COM (Shankar Unni) (08/14/90)

> >Is it possible to write a "real" alloca() for the HP at all, or is
> >there some sort of conflict with the C compiler (i.e. does the way
> >the stack pointer is handled make usage of alloca() impossible)?
> 
> The conventional alloca() depends on the frame pointer / stack pointer model,
> in which a function references its local and parameters off of the frame
> pointer.  alloca() diddles the stack pointer and returns, hoping that no one
> will notice, since all references are off a6 not a7, and a7 will be restored
> on the unlk.

And this is exactly why it is hard to make a "real" alloca() (whatever that
is) work on an 800.

The 800 does not have a separate frame pointer - every local variable,
including parameters, is referenced off SP (the top-of-stack pointer).
Changing SP thus has terrible consequences.

I suppose it would be possible to build alloca() into the compiler itself
(i.e. affect the code generation for a function based on whether it calls
alloca() or not), but alloca() being so non-standard, it was decided not to
do so.

Now that the GNU C compiler has been ported to the 800 series, that would
be a good place to try out such techniques, and evaluate them.

All in all, it's probably best to stay as far away from alloca() as
possible. If you *have* to use alloca() (i.e. someone else's software, and
you can't / won't change it), you can use some good PD alloca.c that does
not fiddle with SP. The code generated will be no worse than if you
actually modified the code to call malloc()/free().

-----
Shankar Unni                                   E-Mail: 
Hewlett-Packard California Language Lab.     Internet: shankar@hpda.hp.com
Phone : (408) 447-5797                           UUCP: ...!hplabs!hpda!shankar

DISCLAIMER:
This response does not represent the official position of, or statement by,
the Hewlett-Packard Company.  The above data is provided for informational
purposes only.  It is supplied without warranty of any kind.

moore%cdr.utah.edu@cs.utah.edu (Tim Moore) (08/15/90)

In article <1340135@hpclscu.HP.COM> shankar@hpclscu.HP.COM (Shankar Unni) writes:
>>> [Is alloca() possible on HP machines]?

>> in which a function references its local and parameters off of the frame
>> pointer.  alloca() diddles the stack pointer and returns, hoping that no one
>> will notice, since all references are off a6 not a7, and a7 will be restored
>> on the unlk.

You could use gcc on your 300 series machine, where alloca is built in.

>And this is exactly why it is hard to make a "real" alloca() (whatever that
>is) work on an 800.
>
>The 800 does not have a separate frame pointer - every local variable,
>including parameters, is referenced off SP (the top-of-stack pointer).
>Changing SP thus has terrible consequences.
>
>I suppose it would be possible to build alloca() into the compiler itself
>(i.e. affect the code generation for a function based on whether it calls
>alloca() or not), but alloca() being so non-standard, it was decided not to
>do so.
>
>Now that the GNU C compiler has been ported to the 800 series, that would
>be a good place to try out such techniques, and evaluate them.

The 800 port of gcc also has built in support for alloca. gcc also uses
a frame pointer everywhere, for better or worse. Supposedly gcc 2.0
will have better support for not using a frame pointer, which can be
an important optimization.

>All in all, it's probably best to stay as far away from alloca() as
>possible. If you *have* to use alloca() (i.e. someone else's software, and
>you can't / won't change it), you can use some good PD alloca.c that does
>not fiddle with SP. The code generated will be no worse than if you
>actually modified the code to call malloc()/free().

There are all sorts of reasons why alloca is nice; the luxury of not
having to call free () is only one of them. Another feature is
automatic deallocation of storage on catching a signal or a longjmp.
While I don't really want to rekindle the alloca flames that appear
periodically in comp.lang.c, I would personally use alloca freely and
rely on compiler support, or the PD code for broken :-) machines that
don't support alloca.

>
>-----
>Shankar Unni                                   E-Mail: 
>Hewlett-Packard California Language Lab.     Internet: shankar@hpda.hp.com
>Phone : (408) 447-5797                           UUCP: ...!hplabs!hpda!shankar
Tim Moore                     moore@cs.utah.edu {bellcore,hplabs}!utah-cs!moore
"Ah, youth. Ah, statute of limitations."
		-John Waters

net@tub.UUCP (Oliver Laumann) (08/17/90)

In article <1990Aug15.101314.9626@hellgate.utah.edu> moore%cdr.utah.edu@cs.utah.edu (Tim Moore) writes:

> There are all sorts of reasons why alloca is nice; the luxury of not
> having to call free () is only one of them. Another feature is
> automatic deallocation of storage on catching a signal or a longjmp.

Yes, there are more uses for alloca() than you may dream of in your
worst alloca-nightmares.  One of the reasons why the application that
I have ported to the HP9000 needs alloca() is that it must adjust the
stack pointer on entry to main().  The program starts like this:

    main (ac, av) char **av; {
	char foo;
	if (Was_Dumped) {
	    (void)alloca (INITIAL_STK_OFFSET - (original_stkbase - &foo));
	} else {
	    original_stkbase = &foo;
	    (void)alloca (INITIAL_STK_OFFSET);
	}
	Main (ac, av);
	/*NOTREACHED*/
    }

Yes, I know, this is probably not portable to all existing machine
architectures.  But the feature for which this functionality is
required (creation of an executable from the running program) is
inherently non-portable itself.  (Of course, this version of
main() can be un-#ifdef-ed on systems where "dumping" cannot be
supported; a conventional main() is included.)

Regards,
--
    Oliver Laumann, Technical University of Berlin, Germany.
    pyramid!tub!net   net@TUB.BITNET   net@tub.cs.tu-berlin.de

jrc@hpdmd48.boi.hp.com (Jim Conrad) (08/21/90)

I'm surprised no one has mentioned the implementation of alloca() distributed
with GNU EMACS for the 9000.

Jim Conrad
jrc@hpbsrl

rer@hpfcdc.HP.COM (Rob Robason) (08/24/90)

jrc> I'm surprised no one has mentioned the implementation of alloca()
jrc> distributed with GNU EMACS for the 9000.

This is the same as the version shipped in libPW.a on HP-UX.  It is in the
public domain and was written by D A Gwyn.  This version has the problems
described previously of using malloc and a garbage collection scheme which
is invoked when it is called subsequently.

Rob

tgl@zog.cs.cmu.edu (Tom Lane) (08/27/90)

In article <5570477@hpfcdc.HP.COM>, rer@hpfcdc.HP.COM (Rob Robason) writes:
> jrc> I'm surprised no one has mentioned the implementation of alloca()
> jrc> distributed with GNU EMACS for the 9000.
> 
> This is the same as the version shipped in libPW.a on HP-UX.  It is in the
> public domain and was written by D A Gwyn.  This version has the problems
> described previously of using malloc and a garbage collection scheme which
> is invoked when it is called subsequently.

Au contraire.  Recent versions of GNU Emacs include both Gwyn's package and
assembly-level hacks for some specific machines, one of which is the 300
series.  The 300-specific code does a real alloca by decrementing SP.
It is fairly specific to HP's cc because it knows about the compiler's
register save/restore habits.  I believe it stops working with the HPUX 7.0
cc if you turn optimization up past +O1; presumably this is because the
compiler may start using SP-relative addressing instead of a frame pointer.
But Emacs works just fine with this code and +O1 optimization; I use it
daily.

-- 
				tom lane
Internet: tgl@cs.cmu.edu
UUCP: <your favorite internet/arpanet gateway>!cs.cmu.edu!tgl
BITNET: tgl%cs.cmu.edu@cmuccvma
CompuServe: >internet:tgl@cs.cmu.edu

mev@hpfcso.HP.COM (Mike Vermeulen) (08/27/90)

> Recent versions of GNU Emacs include both Gwyn's package and
> assembly-level hacks for some specific machines, one of which is the 300
> series.

The 300 series assembly alloca in the GNU emacs distribution works by:
1) bumping SP and 2) copying the old stack top so that all SP based addresses
now refer to the copies of objects on top of the stack.

> I believe it stops working with the HPUX 7.0 cc if you turn optimization up
> past +O1

I believe it stopped working at HPUX 6.5/+O2 because the potential addition of
the save/restore of floating point registers meant that a larger stack top had
to be copied.  Increasing the stack top size to 88 bytes (6 data registers,
4 address registers, 6 floating point registers), makes emacs work witho
ut
complaint.

This alloca method is still fragile because if the peephole optimizer were to
change frame pointer based addressing of locals/parameters to stack pointer
based addressing; then the size of the stack top still may not be adequate when
given too many locals/parameters.

--mev

standard disclaimer: this is not an official HP response.

piet@cs.ruu.nl (Piet van Oostrum) (08/29/90)

In article <10328@pt.cs.cmu.edu>, tgl@zog (Tom Lane) writes:
 |
 |Au contraire.  Recent versions of GNU Emacs include both Gwyn's package and
 |assembly-level hacks for some specific machines, one of which is the 300
 |series.  The 300-specific code does a real alloca by decrementing SP.
 |It is fairly specific to HP's cc because it knows about the compiler's
 |register save/restore habits.  I believe it stops working with the HPUX 7.0
 |cc if you turn optimization up past +O1; presumably this is because the
 |compiler may start using SP-relative addressing instead of a frame pointer.
 |But Emacs works just fine with this code and +O1 optimization; I use it
 |daily.

But note that the distributed version has a bug in it that can cause stack
corruption. Here is the correct version:

	text
	set	PROBE,-128	# safety for C frame temporaries
	set	MAXREG,22	# d2-d7, a2-a5, fp2-fp7 may have been saved
	global	_alloca
_alloca:
	mov.l	(%sp)+,%a0	# return addess
	mov.l	(%sp)+,%d0	# number of bytes to allocate
	mov.l	%sp,%a1		# save old sp for register copy
	mov.l	%sp,%d1		# compute new sp
	sub.l	%d0,%d1		# space requested
	and.l	&-4,%d1		# round down to longword
	sub.l	&MAXREG*4,%d1	# space for saving registers
	mov.l	%d1,%sp		# save new value of sp
	tst.b	PROBE(%sp)	# create pages (sigh)
	mov.l	%a2,%d1		# save reg a2
	mov.l	%sp,%a2
	move.w	&MAXREG-1,%d0
copy_regs_loop:			/* save caller's saved registers */
	mov.l	(%a1)+,(%a2)+
	dbra	%d0,copy_regs_loop
	mov.l	%a2,%d0		# return value
	mov.l	%d1,%a2		# restore a2
	add.l	&-4,%sp		# adjust tos
	jmp	(%a0)		# rts
-- 
Piet* van Oostrum, Dept of Computer Science, Utrecht University,
Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands.
Telephone: +31-30-531806   Uucp:   uunet!mcsun!ruuinf!piet
Telefax:   +31-30-513791   Internet:  piet@cs.ruu.nl   (*`Pete')