[comp.sys.mac.programmer] alloca for Think C 4.0: here it is

torch@attctc.Dallas.TX.US (Jay Finger) (02/09/90)

About a week ago I requested a copy of alloca for Think C 4.0.  I received
several descriptions of what alloca is supposed to do, along with the version
of alloca in Earle Horton's port of bison to MPW.  I also received several
requests for whatever I came up with, so here it is.

The alloca function below is completely inline:  it uses a few more words
of memory that way, but since it's inline it doesn't have to jack with
the return address or stack frame (from what I've seen ThinkC always
puts a LINK instruction at the beginning of the function, even if it's
all in assembler and you've got no local variables).

I was rather suprised to discover that inline functions must be pascal
style functions;  a C function would have been better because the
return value would be passed back in D0 instead of on the stack.

Anyhow, here's the declaration for alloca.  You'll probable want to put
in a file called "alloca.h" somewhere.  I've got bison (not the MPW
version; version 1.03 (8/23/89) from osu-cis) up and running after about
ten hours of work.  I haven't tested it with anything big yet, but this
alloca isn't breaking it.

---------------------- cut here --------------------------------------

pascal void *alloca(long size) =
  {
    0x201F,            /* MOVE.L  (SP)+,D0   ;get size                */
    0x5680,            /* ADDQ.L  #3,D0      ;make it a multiple of 4 */
    0x0240, 0xFFFC,    /* ANDI.W  #-4,D0                              */
    0x9FC0,            /* SUB.L   D0,SP      ;allocate it             */
    0x2F0F             /* MOVE.L  SP,-(SP)   ;return value on stack   */
  };

----------------------------------------------------------------------

Jay Finger,
{ames,mit-eddie}!attctc!torch
ames!torch@attctc

mikem@uhccux.uhcc.hawaii.edu (Mike Morton) (02/09/90)

Jay Finger writes:
>pascal void *alloca(long size) =
>  {
>    0x201F,            /* MOVE.L  (SP)+,D0   ;get size                */
>    0x5680,            /* ADDQ.L  #3,D0      ;make it a multiple of 4 */
>    0x0240, 0xFFFC,    /* ANDI.W  #-4,D0                              */
>    0x9FC0,            /* SUB.L   D0,SP      ;allocate it             */
>    0x2F0F             /* MOVE.L  SP,-(SP)   ;return value on stack   */
>  };

Since the "calling" C code has already done something like a:
       SUBQ #4, SP
to make room for a Pascal-style returned value, then isn't this
allocating 4 bytes more than needed?  I think changing -(SP) to
just (SP) would work, but haven't tried it.

 -- Mike Morton // P.O. Box 11299, Honolulu, HI  96828, (808) 676-6966 HST
      Internet: mikem@uhccux.uhcc.hawaii.edu
    (anagrams): Mr. Machine Tool; Ethical Mormon; Chosen Immortal; etc.

torch@attctc.Dallas.TX.US (Jay Finger) (02/10/90)

Mike Morton
cat allocax
From mikem@uhccux.UUCP Thu Feb  8 23:38:06 1990
Path: attctc!ames!elroy.jpl.nasa.gov!jarthur!uunet!samsung!munnari.oz.au!uhccux!mikem
From: mikem@uhccux.uhcc.hawaii.edu (Mike Morton)
Newsgroups: comp.sys.mac.programmer
Subject: Re: alloca for Think C 4.0: here it is
Keywords: alloca Think C
Message-ID: <6521@uhccux.uhcc.hawaii.edu>
Date: 9 Feb 90 05:38:06 GMT
References: <11376@attctc.Dallas.TX.US>
Reply-To: mikem@uhccux.UUCP (Mike Morton)
Organization: University of Hawaii
Lines: 19

In <6521@uhccux.uhcc.hawaii.edu> Mike Morton writes:
>Jay Finger writes:
>>pascal void *alloca(long size) =
>>  {
>>    0x201F,            /* MOVE.L  (SP)+,D0   ;get size                */
>>    0x5680,            /* ADDQ.L  #3,D0      ;make it a multiple of 4 */
>>    0x0240, 0xFFFC,    /* ANDI.W  #-4,D0                              */
>>    0x9FC0,            /* SUB.L   D0,SP      ;allocate it             */
>>    0x2F0F             /* MOVE.L  SP,-(SP)   ;return value on stack   */
>>  };
>
>Since the "calling" C code has already done something like a:
>       SUBQ #4, SP
>to make room for a Pascal-style returned value, then isn't this
>allocating 4 bytes more than needed?  I think changing -(SP) to
>just (SP) would work, but haven't tried it.

You got me.  You're right, almost.  Changing to (SP) would keep the correct
amount of space on the stack, but the pointer would then get screwed up:
the address returned would be the address of the return value itself, which
would then get popped off the stack, letting other things write into the
newly allocated block.

There are three ways to fix it (described from worst to (IMHO) best):

1: Move SP to D0, add 4, and then do a "MOVE.L D0,(SP)".  This takes two
   more instructions, and about two additional words.

2: Replace "MOVE.L SP,-(SP)" with "LEA 4(SP),(SP)".  The same number
   of instructions, but an extra word for the displacement.

3: Keep the "MOVE.L SP,-(SP)" at the bottom, but simply allocate four
   less bytes, making use of the four bytes that the caller already allocated
   for the return value.  Since #3 is already being added to the block size
   for word-alligning, subtracting 4 can be merged into the operation
   by replacing the ADDQ #3 with a SUBQ #1.  Same number of instructions,
   same number of words.

So anyhow, here's a new version (using method #3) that allocates the
correct number of bytes on the stack:

---------------------- cut here ----------------------
pascal void *alloca(long size) =
  {
    0x201F,         /* MOVE.L  (SP)+,D0   ;get size                       */
    0x5380,         /* SUBQ.L  #1,D0      ;long-word allign, allowing for */
    0x0240, 0xFFFC, /* ANDI.W  #-4,D0     ;  4 bytes already on the stack */
    0x9FC0,         /* SUB.L   D0,SP      ;allocate it                    */
    0x2F0F          /* MOVE.L  SP,-(SP)   ;return value on stack          */
  };
---------------------- the end! ----------------------

Jay Finger,
{ames,mit-eddie}!attctc!torch
ames!torch@attctc