2 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3 * See the copyright notice in the ACK home directory, in the file "Copyright".
5 * Author: Ceriel J.H. Jacobs
8 /* D E S I G N A T O R E V A L U A T I O N */
10 /* $Id: desig.c,v 1.43 1994/06/24 12:40:36 ceriel Exp $ */
12 /* Code generation for designators.
13 This file contains some routines that generate code common to address
14 as well as value computations, and leave a description in a "desig"
15 structure. It also contains routines to load an address, load a value
38 extern arith NewPtr();
39 extern char options[];
42 WordOrDouble(ds, size)
46 /* Check if designator is suitable for word or double-word
49 if ((int) (ds->dsg_offset) % word_align == 0) {
50 if (size == word_size) return 1;
51 if (size == dword_size) return 2;
59 if (size == word_size) {
62 else if (size == dword_size) {
74 if (size == word_size) {
77 else if (size == dword_size) {
91 /* Try to load designator with word or double-word operation.
94 switch (WordOrDouble(ds, size)) {
99 C_loe_dnam(ds->dsg_name, ds->dsg_offset);
101 else C_lol(ds->dsg_offset);
105 C_lde_dnam(ds->dsg_name, ds->dsg_offset);
107 else C_ldl(ds->dsg_offset);
115 register t_desig *ds;
118 /* Try to store designator with word or double-word operation.
121 switch (WordOrDouble(ds, size)) {
126 C_ste_dnam(ds->dsg_name, ds->dsg_offset);
128 else C_stl(ds->dsg_offset);
132 C_sde_dnam(ds->dsg_name, ds->dsg_offset);
134 else C_sdl(ds->dsg_offset);
140 /* Return 1 if the type indicated by tp has a size that is a
141 multiple of the word_size and is also word_aligned
143 #define word_multiple(tp) \
144 ( (int)(tp->tp_size) % (int)word_size == 0 && \
145 tp->tp_align >= word_align)
147 /* Return 1 if the type indicated by tp has a size that is a proper
148 dividor of the word_size, and has alignment >= size or
149 alignment >= word_align
151 #define word_dividor(tp) \
152 ( tp->tp_size < word_size && \
153 (int)word_size % (int)(tp->tp_size) == 0 && \
154 (tp->tp_align >= word_align || \
155 tp->tp_align >= (int)(tp->tp_size)))
157 #define USE_LOI_STI 0
158 #define USE_LOS_STS 1
159 #define USE_LOAD_STORE 2
160 #define USE_BLM 3 /* like USE_LOI_STI, but more restricted:
161 multiple of word_size only
168 /* Find out how to load or store the value indicated by "ds".
170 - suitable for BLM/LOI/STI
171 - suitable for LOI/STI
172 - suitable for LOS/STS/BLS
173 - suitable for calls to load/store/blockmove
176 if (! word_multiple(tp)) {
177 if (word_dividor(tp)) return USE_LOI_STI;
178 return USE_LOAD_STORE;
180 if (! fit(tp->tp_size, (int) word_size)) return USE_LOS_STS;
185 register t_desig *ds;
188 /* Generate code to load the value of the designator described
193 switch(ds->dsg_kind) {
198 if (DoLoad(ds, tp->tp_size)) break;
202 switch (suitable_move(tp)) {
212 CodeConst(tp->tp_size, (int)pointer_size);
216 sz = WA(tp->tp_size);
217 if (ds->dsg_kind != DSG_PFIXED) {
218 arith tmp = NewPtr();
221 STL(tmp, pointer_size);
222 CodeConst(-sz, (int) pointer_size);
224 LOL(tmp, pointer_size);
228 CodeConst(-sz, (int) pointer_size);
232 CodeConst(tp->tp_size, (int) pointer_size);
233 CAL("load", (int)pointer_size + (int)pointer_size);
243 crash("(CodeValue)");
246 ds->dsg_kind = DSG_LOADED;
252 /* Check for an assignment to a FOR-loop control variable
254 if (nd->nd_class == Def) {
255 register t_def *df = nd->nd_def;
257 if (df->df_flags & D_FORLOOP) {
260 "assignment to FOR-loop control variable");
261 df->df_flags &= ~D_FORLOOP;
262 /* only procude warning once */
268 register t_desig *ds;
271 /* Generate code to store the value on the stack in the designator
275 switch(ds->dsg_kind) {
277 if (DoStore(ds, tp->tp_size)) break;
282 switch (suitable_move(tp)) {
290 CodeConst(tp->tp_size, (int) pointer_size);
294 CodeConst(tp->tp_size, (int) pointer_size);
296 CodeConst(pointer_size + pointer_size + WA(tp->tp_size),
308 crash("(CodeStore)");
311 ds->dsg_kind = DSG_INIT;
314 CodeCopy(lhs, rhs, sz, psize)
315 register t_desig *lhs, *rhs;
318 /* Do part of a copy, which is assumed to be "reasonable",
319 so that it can be done with LOI/STI or BLM.
325 lhs->dsg_offset += sz;
326 rhs->dsg_offset += sz;
328 if (sz <= dword_size) {
341 CodeMove(rhs, left, rtp)
342 register t_desig *rhs;
343 register t_node *left;
346 /* Generate code for an assignment. Testing of type
347 compatibility and the like is already done.
348 Go through some (considerable) trouble to see if a BLM can be
352 register t_type *tp = left->nd_type;
357 switch(rhs->dsg_kind) {
359 CodeDesig(left, &lhs);
360 if (rtp->tp_fund == T_STRING) {
361 /* size of a string literal fits in an
362 int of size word_size
367 CAL("StringAssign", (int)pointer_size + (int)pointer_size + (int)dword_size);
373 CodeDesig(left, &lhs);
374 if (lhs.dsg_kind == DSG_FIXED &&
375 fit(tp->tp_size, (int) word_size) &&
376 (int) (lhs.dsg_offset) % word_align ==
377 (int) (rhs->dsg_offset) % word_align) {
379 arith size = tp->tp_size;
381 while (size && sz < word_align) {
382 /* First copy up to word-aligned
385 if (!((int)(lhs.dsg_offset)%(sz+sz))) {
388 else CodeCopy(&lhs, rhs, (arith) sz, &size);
392 sz = (int) size % (int) word_size;
394 CodeCopy(&lhs, rhs, size, &size);
398 /* And then copy remaining parts
402 CodeCopy(&lhs, rhs, (arith) sz, &size);
412 assert(! loadedflag || rhs->dsg_kind == DSG_FIXED);
418 CodeDesig(left, &lhs);
421 switch (suitable_move(tp)) {
428 CodeConst(tp->tp_size, (int) pointer_size);
433 CodeConst(tp->tp_size, (int) pointer_size);
434 CAL("blockmove", 3 * (int)pointer_size);
444 register t_desig *ds;
446 /* Generate code to load the address of the designator described
450 switch(ds->dsg_kind) {
452 if (ds->dsg_offset) {
453 C_adp(ds->dsg_offset);
459 C_lae_dnam(ds->dsg_name, ds->dsg_offset);
462 C_lal(ds->dsg_offset);
463 if (ds->dsg_def) ds->dsg_def->df_flags |= D_NOREG;
467 if (! DoLoad(ds, pointer_size)) {
477 crash("(CodeAddress)");
481 ds->dsg_kind = DSG_PLOADED;
484 CodeFieldDesig(df, ds)
486 register t_desig *ds;
488 /* Generate code for a field designator. Only the code common for
489 address as well as value computation is generated, and the
490 resulting information on where to find the designator is placed
491 in "ds". "df" indicates the definition of the field.
494 if (ds->dsg_kind == DSG_INIT) {
495 /* In a WITH statement. We must find the designator in the
496 WITH statement, and act as if the field is a selection
498 So, first find the right WITH statement, which is the
499 first one of the proper record type, which is
500 recognized by its scope indication.
502 register struct withdesig *wds = WithDesigs;
506 while (wds->w_scope != df->df_scope) {
511 /* Found it. Now, act like it was a selection.
514 wds->w_flags |= df->df_flags;
515 assert(ds->dsg_kind == DSG_PFIXED);
518 switch(ds->dsg_kind) {
521 ds->dsg_offset += df->fld_off;
527 ds->dsg_kind = DSG_PLOADED;
528 ds->dsg_offset = df->fld_off;
532 crash("(CodeFieldDesig)");
538 register t_desig *ds;
540 /* Generate code for a variable represented by a "def" structure.
541 Of course, there are numerous cases: the variable is local,
542 it is a value parameter, it is a var parameter, it is one of
543 those of an enclosing procedure, or it is global.
545 register t_scope *sc = df->df_scope;
548 /* Selections from a module are handled earlier, when identifying
551 assert(ds->dsg_kind == DSG_INIT);
553 if (df->df_flags & D_ADDRGIVEN) {
554 /* the programmer specified an address in the declaration of
555 the variable. Generate code to push the address.
557 CodeConst(df->var_off, (int) pointer_size);
558 ds->dsg_kind = DSG_PLOADED;
564 /* this variable has been given a name, so it is global.
565 It is directly accessible.
567 ds->dsg_name = df->var_name;
569 ds->dsg_kind = DSG_FIXED;
573 if ((difflevel = proclevel - sc->sc_level) != 0) {
574 /* the variable is local to a statically enclosing procedure.
576 assert(difflevel > 0);
578 df->df_flags |= D_NOREG;
579 if (df->df_flags & (D_VARPAR|D_VALPAR)) {
580 /* value or var parameter
582 C_lxa((arith) difflevel);
583 if ((df->df_flags & D_VARPAR) ||
584 IsConformantArray(df->df_type)) {
585 /* var parameter or conformant array.
586 The address is passed.
591 ds->dsg_kind = DSG_PLOADED;
595 else C_lxl((arith) difflevel);
596 ds->dsg_kind = DSG_PLOADED;
597 ds->dsg_offset = df->var_off;
601 /* Now, finally, we have a local variable or a local parameter
603 if ((df->df_flags & D_VARPAR) ||
604 IsConformantArray(df->df_type)) {
605 /* a var parameter; address directly accessible.
607 ds->dsg_kind = DSG_PFIXED;
609 else ds->dsg_kind = DSG_FIXED;
610 ds->dsg_offset = df->var_off;
616 register t_desig *ds;
618 /* Generate code for a designator. Use divide and conquer
623 switch(nd->nd_class) { /* Divide */
626 if (nd->nd_NEXT) CodeDesig(nd->nd_NEXT, ds);
628 switch(df->df_kind) {
630 CodeFieldDesig(df, ds);
634 CodeVarDesig(df, ds);
638 crash("(CodeDesig) Def");
643 assert(nd->nd_symb == '[' || nd->nd_symb == ',');
645 CodeDesig(nd->nd_LEFT, ds);
647 CodePExpr(nd->nd_RIGHT);
650 /* Now load address of descriptor
652 if (IsConformantArray(nd->nd_type)) {
654 assert(nd->nd_class == Def);
657 off = df->var_off + pointer_size;
658 if (proclevel > df->df_scope->sc_level) {
659 C_lxa((arith) (proclevel - df->df_scope->sc_level));
665 C_loc(nd->nd_type->arr_low);
667 c_lae_dlb(nd->nd_type->arr_descr);
672 ds->dsg_kind = DSG_INDEXED;
676 assert(nd->nd_symb == '^');
680 switch(ds->dsg_kind) {
682 ds->dsg_kind = DSG_PLOADED;
688 CodeValue(ds, nd->nd_type);
689 ds->dsg_kind = DSG_PLOADED;
694 ds->dsg_kind = DSG_PFIXED;
698 crash("(CodeDesig) Uoper");
703 crash("(CodeDesig) class");