[comp.sys.atari.st] MWC & large arrays -- help!

paul@cacilj.UUCP (Paul Close) (06/11/88)

I'm having problems with the following construct:

struct x {
	blah, blah ...
	struct y arr[64][64];
	};

where struct y is pretty small.  I've checked the "sizeof" on a Sun-3 with
the ints = shorts, and the sizeof(struct x) was 65500 or so -- just under
64k.  However, MWC complains about the size being too big until I trim it
down to ~16000 bytes!  The exact error is from cc0, and reads: "size of
struct too large".  Using 3.0, I also got a message about size_t.

This is just the definition -- the actual storage is malloced.  (Am I in
trouble using malloc()?  I know Malloc has bugs, but how is malloc()?)

Can some of you MWC gurus help me here?  I am quite familiar with C, but
this is my first big program on the ST.  BTW, this isn't a program I
wrote, I'm just experimenting with porting....

Thanks all!
-- 
Paul Close	paul@cacilj.CTS.COM 	...!{uunet, ucsd, crash}!cacilj!paul

Shaw's Principle:
  Build a system that even a fool can use, and only a fool will want to use it.

jgj@hcx2.SSD.HARRIS.COM (06/14/88)

I have experienced this problem too.  As far as I can tell, in 3.0, structures
are limited to 32Kb.  Also, elements of an array are limited to 32Kb.  Thus the
declaration
  char array[10][33000];
causes wrong code to be generated for references to array.  The problem is,
the compiler uses 16 bit quanitities to remember element sizes.  The code
that gets generated for
   cp=array[i]; 
is the base addresss of array plus i times the sign extended low order
16 bits of 33000!  Very frustrating.  I spent two hours of debugging before
I put the pieces of the puzzle together.
============================================================================
Jeffrey Glen Jackson  | Satan jeered, "You're dead meat Jesus, I'm gonna
jgj@ssd.harris.com    |     bust you up tonight."
x5120                 | Jesus said, "Go ahead, make my day."
                      | -- Carman, "The Champion"

jsp@sp7040.UUCP (John Peters) (06/19/88)

	I have ran into this problem before to.  My brother regularly 
corresponds with someone that helped with the 3.0 MCW developement.  so 
here is the reason.  The MWC compiler uses signed short offsets from a 
stack value for local variables.  this means that you have 15 bits or
32K to use as an offset, question answered.  This is not true of global
variables.  All global variables are long offset from a base address so
the problem does not exist and structures and arrays can be as big as
wanted.

	Hope this helped.  I was taught to not use global variables much but 
it seems that they have their place.

						--  Johnnie  --

sid@brambo.UUCP (Sid Van den Heede) (06/22/88)

In article <46700008@hcx2> jgj@hcx2.SSD.HARRIS.COM writes:
>
>I have experienced this problem too.  As far as I can tell, in 3.0, structures
>are limited to 32Kb.  Also, elements of an array are limited to 32Kb.  

I thought 3.0 was supposed to fix the problem with big arrays etc.
Here I was all excited that they said they fixed the problem and now I'll
have to forget about a program I wrote a couple of years ago that tried to
use big arrays.  Maybe in a year from now when 4.0 comes out??
-- 
Sid Van den Heede		Voice: 416-792-1137
sid@brambo.UUCP			FAX:   416-792-1536
...!uunet!mnetor!utgpu!telly!brambo!sid
Bramalea Software, Suite 406, 44 Peel Centre Dr, Brampton, Ontario  L6T 4B5

leo@philmds.UUCP (Leo de Wit) (06/23/88)

In article <427@sp7040.UUCP> jsp@sp7040.UUCP (John Peters) writes:
>
>	I have ran into this problem before to.  My brother regularly 
>corresponds with someone that helped with the 3.0 MCW developement.  so 
>here is the reason.  The MWC compiler uses signed short offsets from a 
>stack value for local variables.  this means that you have 15 bits or
>32K to use as an offset, question answered.  This is not true of global
>variables.  All global variables are long offset from a base address so
>the problem does not exist and structures and arrays can be as big as
>wanted.

Long offsets from a base address? What 68000 instruction do you have in
mind?? Probably you mean absolute addresses (with relocation that is).

Lets see how we can address memory on the MC68000:

1) (An) contents of the location pointed at by An (n = 0-7)
2) -(An) same as 1) but with predecrement of An
3) (An)+ same as 1) but with postincrement of An
4) w(An) word displacement from An; w is a 16 bit signed offset.
5) b(An,Rx) byte displacement with index; b being a 8 bit signed offset.
6) There are also the PC-relative adressing modes; basically like 4) and 5)
7) Absolute short (16 bit signed)
8) Absolute long (32 bit; of course limited by a 24 bit databus).

Your local variables are typically adressed by a(A6), with a being a
negative value for local variables, and a positive one for parameters.
    Static and global data? 1), 2) and 3) kommt nicht in frage, as it
would require loading the address register for each different variable.
4) is widely used by various compilers, but means that only 64K can be
addressed (GEMDOS initializes some address registers to point to the
start of the initialized and uninitialized data spaces; these addresses
can be found on the processes' basepage). 5) seems hardly likely, have
to waste two registers.
    Leaves us with 7): only for programs in low memory (or I/O
references); not useful for most cases (unless you can enforce this on
your program).  And 8): Absolute long. Note that the address generated
will be a long address relative to the start of the text segment; this
becomes relocated when the program gets loaded (GEMDOS does that for
you). This is the default that Lattice C uses (but you can have type 4)
addressing by a compiler option).

Speaking of addressing modes, I would prefer type 4) if the data fits
into 64K; the instruction is shorter and also faster than absolute
addressing. If the data is over 64K you'll probably have to use absolute
addressing (or else you could use something like LEA (An,Dx),Am and then
use Am; but this requires an additional overhead). There's also another
case in which absolute addressing is almost mandatory: when you make an
interrupt routine. When the program that sets up the interrupt vector
exits (memory resident), the data base register will be destroyed. In
this case I prefer absolute addresses.

>	Hope this helped.  I was taught to not use global variables much but 
>it seems that they have their place.

    You can often use static variables instead of global ones; they
have a more restricted scope and will be put in the same program
segment(s).  As for not using global variables, this is a tendency that
has come forth from the structured programming gurus; I think that you
may use it as a general rule. However, there are very often
values/variables in your program that have a program-wide or
module-wide scope; it would be both foolish and inefficient to not use
that fact.

>						--  Johnnie  --

      Leo.

jason@lakesys.UUCP (Jason) (06/24/88)

In article <411@brambo.UUCP>, sid@brambo.UUCP (Sid Van den Heede) writes:
> In article <46700008@hcx2> jgj@hcx2.SSD.HARRIS.COM writes:
> >I have experienced this problem too.  As far as I can tell, in 3.0, structures
> >are limited to 32Kb.  Also, elements of an array are limited to 32Kb.  
> 
> I thought 3.0 was supposed to fix the problem with big arrays etc.
> [Rest of article deleted]
> Sid Van den Heede		Voice: 416-792-1137

	Version 3.0 does handle ARRAYS that are larger than 32k... I've never
had any array ELEMENTS that've exceeded 32k (or any structures by themselves
which were that big) so I can't verify/deny what was said about that. However,
I DO know that MWC 3.0 properly handles large arrays (how large, I'm not sure)

	Just for kicks and giggles, why would anyone want elements/structures
that were >32k? Or, put differently, what's in it? Huge arrays? (Or 16384
ints? :)

	Jason - Not your average iconoclast.

"The first office copiers were, as is well known, monks." - David Owen

jac423@leah.Albany.Edu (Julius A Cisek) (06/25/88)

This is in response to the question about large structures in MWC (INEWS
is not letting me include the article!)

The only thing I can think of right now is that the problem is with the
ST, and not the MWC. In Lazer C you are restricted to 32K arrays and
structures and since it is because of the way the ST partitions memory,
I'd have to say that MWC would have the same problem...

I could be wrong, so please no flames.
-- 
What about technology, computers, .------------------. J.A.Cisek
nuclear fusion?  I'm terrified of |Spectral Fantasies| jac423@leah.albany.edu
radiation, I hate the television. `------------------' jac423@rachel.albany.edu

michel@megamax.UUCP (Michel Rynderman) (06/27/88)

In Laser C you can have arrays of any size.

Michel@megamax
-- 
Anyone who would like a reply to their mail sent to me needs to give a 
uucp path. The mailer on our system is weird. Either that or give me a 
tel. number and I'll give you a call.
UUCP: pollux!megamax!michel PHONE: 214-987-4931

wayneck@tekig5.TEK.COM (Wayne Knapp) (06/28/88)

In article <767@lakesys.UUCP>, jason@lakesys.UUCP (Jason) writes:
> 
> 	Just for kicks and giggles, why would anyone want elements/structures
> that were >32k? Or, put differently, what's in it? Huge arrays? (Or 16384
> ints? :)

You must be joking, or maybe your are just new to programming.  Yes the
problems I ran into in school could be sloved with very small amounts of
memory.  After all when there are 300+ people using a 1000% overloaded 
mainframe just how complex can you make the problems. :-)

Anyway here is a few that can require more than 32K access in arrays:

           1) Zbuffer for 3D graphics
           2) data logging 
           3) look ahead calcuation done to increase speed
           4) speed sheets
           5) decent word processor
           6) music
           7) ram disk
               on and on

Almost any type program can benefit from the "EASY" access of memory.  When
one has a high level compiler why should he have to worry about array sizes
as long as there is enough real memory.

                                       Wayne Knapp

jason@lakesys.UUCP (Jason) (06/28/88)

In article <2921@tekig5.TEK.COM>, wayneck@tekig5.TEK.COM (Wayne Knapp) writes:
> In article <767@lakesys.UUCP>, jason@lakesys.UUCP (Jason) writes:
> > 
> > 	Just for kicks and giggles, why would anyone want elements/structures
> > that were >32k? Or, put differently, what's in it? Huge arrays? (Or 16384
> > ints? :)
> 
> You must be joking, or maybe your are just new to programming.  Yes the

	Nope, not joking.

> [...]
> Anyway here is a few that can require more than 32K access in arrays:
> [Stuff listed]
> Almost any type program can benefit from the "EASY" access of memory.  When
> one has a high level compiler why should he have to worry about array sizes
> as long as there is enough real memory.
> 
>                                        Wayne Knapp

	Nope, being doing it for a little while... (Primarily on micros, which
affects ones mindset regarding memory).

	But, I don't see why anything mentioned would have to have >32K
ELEMENTS. One could easily enough (and, possibly, more conveniently, depending
on how one was handling one's memory allocation) have a pointer to an array
imbedded in a structure. I suppose my not being able to see why is pretty much
irrelevant, as if someone wants to do something, they should be able to...

	"High level compiler"? C, the most popular bloated macro assembler? :)

	Jason - Not your average iconoclast.

braner@batcomputer.tn.cornell.edu (braner) (06/28/88)

[]

I think the original question was _not_ naive:  why would one need
a _structure_ (rather than an array) that is more than 32K in size?
That's what many 68000 compilers cannot handle:  structure fields
that are offset more than 32K from the beginning of the structure.
That's because a field in a structure is accessed by adding an offset
(a constant calculated at compile time) to the base address.  On the
68000, the obvious, compact, efficient method is to use the indexed
addressing mode, but that limits you to an offset of +-32K.
That is very different from _array_ access, which (usually) involves
a calculation at run time:  the address of a[i] is base_of_a[] +
i * sizeof (element of a[]).  That's slower.  If you want a structure
like:
	struct humongous {
		int	dis;
		int	data[1000000];
		float	dat;
	}
you'll have a problem with most compilers (the offset of 'dat' is too large).
But you can do it like this:
	struct not_so_humongous {
		int	dis;
		int	*data;
		float	dat;
	}
where 'data' is just a pointer and you set it to point to the array that
is allocated separately.  What you win is far greater efficiency when
accessing more typical structures.

Of course, a _very_ smart compiler could switch from one addressing mode
to another depending on the size of a structure.

Note concerning the opposite from structures of arrays:  arrays of structures.
You might certainly want to use a very large array of many small structures.
Laser C has a bug in doing pointer arithmetic on pointers to structures, as
I have posted a while ago.  In short, struct mystruct a[i] works fine, even
for i very large, but struct mystruct *p;  p += i;  fails (uses the wrong
address) if (i * sizeof (mystruct) > 64K) and i is an int.  So use
p = &p[i];  instead.   This bug holds for arrays of _structures_ only.

- Moshe Braner

hase@netmbx.UUCP (Hartmut Semken) (06/29/88)

In article <720@leah.Albany.Edu> jac423@leah.Albany.Edu (Julius A Cisek) writes:
>The only thing I can think of right now is that the problem is with the
>ST, and not the MWC. In Lazer C you are restricted to 32K arrays and
>structures and since it is because of the way the ST partitions memory,
>I'd have to say that MWC would have the same problem...

Hihi, the ST's 68000 partitions memory as one, 16MByte chunk.
The GLUE-chip partitions memory as follows: 4 Meg RAM, 11 Meg <nothing> (Bus
Error/two bombs), 1 Meg of "stuff" (ROM, i/o).

Are you mixing up 8088's segmented adressing sheme ant the ST?
>
>I could be wrong, so please no flames.

Of course not.

hase
-- 
Hartmut Semken, Lupsteiner Weg 67, 1000 Berlin 37 hase@netmbx.UUCP
High on a rocky promontory sat an Electric Monk on a bored horse. (D. Adams)

rosenkra@Alliant.COM (Bill Rosenkranz) (06/30/88)

----
regarding large arrays, are we talking about local arrays (defined inside a
function) or globals? i know that even the first st version of alcyon
(for example) has no problems with a global like

	unsigned int	array[100000];

though local arrays of this size are probably not possible (have never even
needed to try it out).

an obvious solution to this whole problem is to Malloc (not malloc) the space
and then refer to the pointer. this works with 1 dimensional arrays but
multidimensional arrays would be tricky.

-bill

leo@philmds.UUCP (Leo de Wit) (07/01/88)

In article <5327@batcomputer.tn.cornell.edu> braner@tcgould.tn.cornell.edu (braner) writes (amongst other things):
>I think the original question was _not_ naive:  why would one need
>a _structure_ (rather than an array) that is more than 32K in size?
>That's what many 68000 compilers cannot handle:  structure fields
>that are offset more than 32K from the beginning of the structure.
>That's because a field in a structure is accessed by adding an offset
>(a constant calculated at compile time) to the base address.  On the
>68000, the obvious, compact, efficient method is to use the indexed
>addressing mode, but that limits you to an offset of +-32K.

Maybe it is good to mention that exactly the same goes for actual
parameters and automatic variables; most compilers use a frame pointer
register (link register , typically A6) to index from. The link
instruction itself also takes a offset of +-32K. So if you can avoid it,
don't put big arrays or other variables on the stack (there's an other
danger with huge stacks: it can run into your heap).

         Leo.

leo@philmds.UUCP (Leo de Wit) (07/01/88)

In article <2073@alliant.Alliant.COM> rosenkra@alliant.UUCP (Bill Rosenkranz) writes:
>regarding large arrays, are we talking about local arrays (defined inside a
>function) or globals? i know that even the first st version of alcyon
>(for example) has no problems with a global like
>
>	unsigned int	array[100000];
>
>though local arrays of this size are probably not possible (have never even
>needed to try it out).
>
>an obvious solution to this whole problem is to Malloc (not malloc) the space
>and then refer to the pointer. this works with 1 dimensional arrays but
>multidimensional arrays would be tricky.
>
>-bill

Just specify the correct pointer type, for instance if you want an
array of this type:

    unsigned int array[200][500];

then your pointer should be declared:

    int (*arrp)[500]; /* that's just 1 pointer, for pointing to an int [500];*/

you initiate it as follows:

    arrp = (int (*)[500])Malloc(200 * sizeof(*arrp)); /* isn't that nice 8-) */

and now you can say for instance:

    arrp[155][430] = 12345;

In fact you can use all normal pointer conversions, such as sizeof, *,
&, [], 'arrp' being a pointer of the same type as 'array'.

Note that the () are obligatory;

    int *arrp[500];

are 500 pointers to int, and that's something quite different!

As for big auto arrays, that should be avoided; the most effective
addressing mode for them being a word offset from the frame pointer (so
a restriction of 32K). Of course you can use big static arrays if the
function is not used recursive; these are local too.

    Leo.

braner@batcomputer.tn.cornell.edu (braner) (07/03/88)

In article <542@philmds.UUCP> leo@philmds.UUCP (Leo de Wit) writes:
>
>Just specify the correct pointer type, for instance if you want an
>array of this type:
>
>    unsigned int array[200][500];
>
>then your pointer should be declared:
>
>    int (*arrp)[500]; /* that's just 1 pointer, for pointing to an int [500];*/
>
>you initiate it as follows:
>
>    arrp = (int (*)[500])Malloc(200 * sizeof(*arrp)); /* isn't that nice 8-) */

- err, s.b. Malloc((long)200*500*sizeof(int));
As written above it allocates space for 200 pointers, not arrays.

BUT, a better method is to Malloc or malloc or simply statically allocate
an array of 200 pointers, then allocate (in a for() loop) 200 1-D arrays
of 500 ints, and initialize the pointers to the 1-D arrays.  Now the
pointers can be used as matrix rows:

>and now you can say for instance:
>
>    arrp[155][430] = 12345;
>
>In fact you can use all normal pointer conversions, such as sizeof, *,
>&, [], 'arrp' being a pointer of the same type as 'array'.

Note that for this method you DO write:
>
>    int *arrp[200];	/* not 500 */

With this technique you can get around malloc's 64K limit with portable code,
and matrix access is FASTER, too!  Also, both dimensions of the matrix
can be decided upon at run time (e.g., can be given by parameters to
a function).  In the first method, and in statically allocated arrays,
the dimensions are fixed at compile time, a deficiency of C.

- Moshe Braner

leo@philmds.UUCP (Leo de Wit) (07/04/88)

In article <5366@batcomputer.tn.cornell.edu> braner@tcgould.tn.cornell.edu (braner) writes:
>In article <542@philmds.UUCP> leo@philmds.UUCP (Leo de Wit) writes:
>>
>>Just specify the correct pointer type, for instance if you want an
>>array of this type:
>>
>>    unsigned int array[200][500];
>>
>>then your pointer should be declared:
>>
>>    int (*arrp)[500]; /* that's just 1 pointer, for pointing to an int [500];*/
>>
>>you initiate it as follows:
>>
>>    arrp = (int (*)[500])Malloc(200 * sizeof(*arrp)); /* isn't that nice 8-) */
>
>- err, s.b. Malloc((long)200*500*sizeof(int));
>As written above it allocates space for 200 pointers, not arrays.

That is NOT correct, you should read better first before critisizing
someone else's stuff. It would have been, if it said 'sizeof(arrp)'.
But no, it says 'sizeof(*arrp)'; and while (*arrp) is an int[500] - the
object which arrp points at - it is correct as it stands.

>BUT, a better method is to Malloc or malloc or simply statically allocate
>an array of 200 pointers, then allocate (in a for() loop) 200 1-D arrays
>of 500 ints, and initialize the pointers to the 1-D arrays.  Now the
>pointers can be used as matrix rows:

You're changing the subject. The original problem was not to use a
different scheme, it said: while you can use Malloc to allocate a large
one-dimensional array, it will be difficult for a higher dimension. The
tendency of my article was simply that this isn't difficult at all,
just use a pointer of the correct type. Yes, I know to how to set up
dope vectors, and note that your 'loop' is not so time & space efficient
if you allocate the 200 arrays separately.  Better allocate it in one
chunk (together with a pointer array), then use a for loop to set up
the pointers. Furthermore it depends on the situation whether your
pointer array is 'better'; might as well use non-constant pointers into
the array, this will even prove faster.

>>and now you can say for instance:
>>
>>    arrp[155][430] = 12345;
>>
>>In fact you can use all normal pointer conversions, such as sizeof, *,
>>&, [], 'arrp' being a pointer of the same type as 'array'.
>
>Note that for this method you DO write:
>>
>>    int *arrp[200];	/* not 500 */

You misquoted me. I never said that. The original said:

    then your pointer should be declared:
    
        int (*arrp)[500]; /* that's just 1 pointer, for pointing to an int [500];*/

and a bit further:

    Note that the () are obligatory;
    
        int *arrp[500];
    
    are 500 pointers to int, and that's something quite different!

What I meant to say was that you had to use () for the pointer
declaration I used.  Furthermore, while I'm declaring a pointer (that
is ONE pointer) to a int [500], the 500 is correct. (and should NOT be
200; it should be 200 in your case).

>With this technique you can get around malloc's 64K limit with portable code,
>and matrix access is FASTER, too!  Also, both dimensions of the matrix
>can be decided upon at run time (e.g., can be given by parameters to
>a function).  In the first method, and in statically allocated arrays,
>the dimensions are fixed at compile time, a deficiency of C.

You make it sound as if my code wasn't portable; it IS (at least on
every decent compiler). As far as speed is involved, I think using an
extra pointer of type int * into the array dynamically is still faster,
and uses less space; what if I had as an example:

char carr[20000][5];

bit of a waste doing this with pointer arrays, don't you think?
As far as the dimensions is conceirned I agree; but this again was not
the original problem. Besides, if you want both dimensions free, you
have to allocate the pointer array dynamically too. And then all your
pointer efficiency is gone (using double indirections).

>- Moshe Braner
>
>

   Leo.

kirchner@uklirb.UUCP (07/11/88)

Hello,
just from a code-generator-writers point of view:

THERE IS ABSOLUTELY NO REASON TO LIMIT LOCAL OR GLOBAL OR ANY OTHER
MEMORY STRUCTURE TO 64K IN THE 68000.

I once wrote the generator for Pascal-SC ( the one with those
unique features for numeric applications, but a good pascal anyway -:) ),
and since numerics deal with large matrices etc. I had to access all
memory I could get. C uses the same access mechanisms as pascal, so
the same could be done there.

And this is how I did it:

All local variables and the globals also are accessed via an address-
register. Let me call them Al and Ag. As expected variables with
offset <32k are accessed via offs16(Al), or offs16(Ag).

If the offset does not fit into 16 bits, I generate:

       movea.l     Al,Ax          ; Ax is a scratch register
       adda.l      #offs32,Ax     ; now Ax points to the variable
       move.l      (Ax),Dx        ; access it.

Now remember: the address in Ax can be reused for subsequent accesses to the
same variable, and it can be used with a 16-bit-offset to access other
variables which are 'near' the first one. So with a little optimization
ALL memory can be accessed with only little overhead, which must not be paid
when variables are 'near' the Al/Ag anyway.

( I would not like to write a codegenerator in the same way for an 8086/-286 )

R. Kirchner

rosenkra@Alliant.COM (Bill Rosenkranz) (07/14/88)

---
like i originally said: multidimensional arrays would be tricky :^)

-bill