* added compilers lcc and bcc (linux86)
[mascara-docs.git] / compilers / linux86-0.16.17 / bcc / genloads.c
blobefa3725389c070b523372707d19d5b3b9fc560eb
1 /* genloads.c - generate loads of registers and memory for bcc */
3 /* Copyright (C) 1992 Bruce Evans */
5 #include "bcc.h"
6 #include "byteord.h"
7 #include "condcode.h"
8 #include "gencode.h"
9 #include "reg.h"
10 #include "sc.h"
11 #include "scan.h"
12 #include "sizes.h"
13 #include "type.h"
15 FORWARD void badaddress P((void));
16 FORWARD void blockpush P((struct symstruct *source));
17 FORWARD void loadadr P((struct symstruct *source, store_pt targreg));
18 FORWARD void loadlongindirect P((struct symstruct *source, store_pt targreg));
19 FORWARD void outnamoffset P((struct symstruct *adr));
20 FORWARD void outnnadr P((struct symstruct *adr));
21 FORWARD fastin_pt pushpull P((store_pt reglist, bool_pt pushflag));
23 PUBLIC void addoffset(source)
24 struct symstruct *source;
26 #ifdef I8088
27 if (source->level == OFFKLUDGELEVEL)
29 outadd();
30 outregname(source->storage);
31 outcomma();
32 outimmed();
33 outnamoffset(source);
34 outnl();
35 if (source->storage & (AXREG | ALREG))
36 unbumplc();
37 if (source->level == OFFKLUDGELEVEL)
38 source->level = EXPRLEVEL;
39 source->offset.offi = 0;
41 else
42 #endif
43 if (source->offset.offi != 0)
45 addconst(source->offset.offi, source->storage);
46 source->offset.offi = 0;
50 PUBLIC void address(source)
51 struct symstruct *source;
53 if (source->indcount == 0)
54 bugerror("taking address of non-lvalue");
55 else
57 if (source->type->constructor & (ARRAY | FUNCTION))
58 bugerror("botched indirect array or function");
59 else if (--source->indcount == 0 && source->storage == GLOBAL &&
60 !(source->flags & LABELLED) && *source->name.namep == 0)
61 source->storage = CONSTANT;
62 source->type = pointype(source->type);
66 PRIVATE void badaddress()
68 bugerror("bad address");
71 PRIVATE void blockpush(source)
72 struct symstruct *source;
74 struct symstruct *length;
75 offset_T spmark;
76 uoffset_T typesize;
78 typesize = source->type->typesize;
79 length = constsym((value_t) typesize);
80 length->type = uitype;
81 address(source);
82 modstk(spmark = sp - (offset_T) typesize);
83 #ifdef STACKREG
84 regtransfer(STACKREG, DREG);
85 #else
86 #ifdef MC6809 /* XXX ? */
87 regtransfer(LOCAL, DREG);
88 #else
89 #include "need STACKREG and stackregstr"
90 #endif
91 #endif
92 push(length);
93 push(source);
94 pushreg(DREG);
95 call("_memcpy");
96 outnl();
97 modstk(spmark);
98 indirec(source);
101 PUBLIC void exchange(source, target)
102 struct symstruct *source;
103 struct symstruct *target;
105 store_t tempreg;
107 regexchange(source->storage, target->storage);
108 tempreg = target->storage;
109 target->storage = source->storage;
110 source->storage = tempreg;
113 /*-----------------------------------------------------------------------------
114 getindexreg()
115 returns the "best" available index register
116 -----------------------------------------------------------------------------*/
118 PUBLIC store_pt getindexreg()
120 if (!(reguse & INDREG0))
121 return INDREG0;
122 if (!(reguse & INDREG1))
123 return INDREG1;
124 if (!(reguse & INDREG2))
125 return INDREG2;
126 #if NOTFINISHED
127 #ifdef I80386
128 if (i386_32)
130 if (!(reguse & DATREG1))
131 return DATREG1;
132 if (!(reguse & DATREG2))
133 return DATREG2;
135 #endif
136 #endif
137 bugerror("out of index regs");
138 return 0;
141 /*-----------------------------------------------------------------------------
142 indexadr(index leaf, pointer leaf)
143 is used by the index and add and subtract (pointer) routines
144 it handles expressions like
145 pointer + index
146 &array[index]
147 the target becomes register direct with offset
148 (except for index = 0, when nothing is changed)
149 constant indexes are optimised by leaving them as offsets
150 register direct pointers are optimised by leaving the offset alone
151 (except for PC register direct, since there is no LEAX D,PC)
152 -----------------------------------------------------------------------------*/
154 PUBLIC void indexadr(source, target)
155 struct symstruct *source;
156 struct symstruct *target;
158 #ifdef MC6809
159 bool_t canABX;
160 #endif
161 uoffset_T size;
162 store_pt sourcereg;
163 struct typestruct *targtype;
164 store_pt targreg;
166 if (!(target->type->constructor & (ARRAY | POINTER)))
168 bugerror("cannot index");
169 return;
171 size = target->type->nexttype->typesize;
172 if (source->storage == CONSTANT)
174 if (source->offset.offv != 0)
176 if (target->indcount != 0)
177 loadany(target);
178 target->offset.offi += source->offset.offv * size;
180 return;
182 if (target->storage & ALLDATREGS)
183 push(target);
184 if ((store_t) (sourcereg = target->storage) & ~reguse & allindregs)
185 targreg = sourcereg;
186 else
187 targreg = getindexreg();
188 #ifdef I8088
189 if ((store_t) sourcereg == GLOBAL && target->indcount == 0 &&
190 !(source->type->scalar & CHAR) && source->storage != DREG)
191 load(source, targreg);
192 else
193 #endif
194 load(source, DREG);
196 #ifdef I8088
197 softop(MULOP, constsym((value_t) size), source);
198 #endif
199 #ifdef MC6809
201 /*-----------------------------------------------------------------------------
202 do some calculations in advance to decide if index can be done with ABX
203 -----------------------------------------------------------------------------*/
205 if ((store_t) targreg == XREG && source->type->scalar & CHAR &&
206 size < CANABXCUTOFF)
207 canABX = TRUE;
208 else
210 canABX = FALSE;
211 softop(MULOP, constsym((value_t) size), source);
214 #endif
216 /*-----------------------------------------------------------------------------
217 deal with constant target - constant becomes offset, result in DREG
218 -----------------------------------------------------------------------------*/
220 if (target->storage == CONSTANT)
222 target->storage = DREG;
223 return;
226 /*-----------------------------------------------------------------------------
227 load target if it is indirect or GLOBAL or canABX so D or B can be added
228 otherwise, it is register direct (maybe S register, maybe with offset)
229 and the offset can be left after adding DREG
230 -----------------------------------------------------------------------------*/
232 #ifdef I8088
233 if (target->indcount != 0)
235 targtype = target->type;
236 target->type = itype;
237 add(source, target);
238 target->type = targtype;
239 return;
241 if ((store_t) sourcereg == GLOBAL)
243 target->storage = source->storage;
244 target->level = OFFKLUDGELEVEL;
245 return;
247 #endif
248 #ifdef MC6809
249 if (canABX || (store_t) sourcereg == GLOBAL)
251 load(target, targreg);
252 sourcereg = targreg;
254 else if (target->indcount != 0)
256 targtype = target->type;
257 target->type = itype;
258 add(source, target);
259 target->type = targtype;
260 return;
262 if (canABX)
263 while (size--)
264 outABX();
265 else
266 #endif
268 #ifdef I8088
269 if ((store_t) targreg != (store_t) sourcereg)
270 regtransfer(sourcereg, targreg);
271 outadd();
272 outregname(targreg);
273 outncregname(DREG);
274 #endif
275 #ifdef MC6809
276 outlea();
277 outregname(targreg);
278 outtab();
279 outregname(DREG);
280 outncregname(sourcereg);
281 #endif
283 if ((store_t) sourcereg == LOCAL)
284 #ifdef FRAMEPOINTER
285 target->offset.offi -= framep;
286 #else
287 target->offset.offi -= sp;
288 #endif
289 target->storage = targreg;
292 PUBLIC void indirec(source)
293 struct symstruct *source;
295 if (!(source->type->constructor & (ARRAY | POINTER)))
296 bugerror("illegal indirection");
297 else if (source->indcount == (indn_t) - 1)
298 limiterror("too many indirections (256)");
299 else
301 if (source->storage & ALLDATREGS)
302 transfer(source, getindexreg());
303 if (!((source->type = source->type->nexttype)->constructor &
304 (ARRAY | FUNCTION)))
305 ++source->indcount;
306 if (source->storage == CONSTANT)
307 source->storage = GLOBAL;
311 /*-----------------------------------------------------------------------------
312 load(source leaf, target register)
313 loads the specified register without changing any others (except CC)
314 if the type is long or float, DREG is paired with the target register
315 the result has no offset
316 -----------------------------------------------------------------------------*/
318 PUBLIC void load(source, targreg)
319 struct symstruct *source;
320 store_pt targreg;
322 if (source->type->scalar & DLONG)
324 if (source->storage == CONSTANT)
325 loadreg(source, targreg);
326 else if (source->indcount == 0)
328 #if DYNAMIC_LONG_ORDER
329 if (!long_big_endian)
330 #endif
331 #if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN == 0
333 if ((store_t) targreg == DREG)
334 source->storage = DREG;
336 #endif
337 if (source->storage != (store_t) targreg)
338 transfer(source, targreg);
339 if (source->offset.offi != 0)
340 bugerror("loading direct long with offset not implemented");
342 else
343 loadlongindirect(source, targreg);
345 else if (source->type->scalar & DOUBLE)
347 if (source->storage == targreg && source->indcount == 0)
348 return;
349 if (source->storage == CONSTANT)
351 #ifdef I80386
352 if (i386_32)
354 loadconst(((offset_T *) source->offset.offd)[0], DREG);
355 loadconst(((offset_T *) source->offset.offd)[1], targreg&~DREG);
357 else /* XXX - more for non-386 */
358 #endif
360 int regs, i, off=1;
361 loadconst(((unsigned short *) source->offset.offd)[0], DREG);
362 regs = (targreg&~DREG);
363 for(i=1; i; i<<=1)
365 if( regs&i )
366 loadconst(
367 ((unsigned short *) source->offset.offd)[off++],
372 else
374 push(source);
375 poplist(targreg | DREG); /* actually it's the full reg list */
377 source->storage = targreg; /* XXX - multi for non-386 */
378 source->indcount = 0;
379 source->flags = 0;
380 if (source->level == OFFKLUDGELEVEL)
381 source->level = EXPRLEVEL;
382 source->offset.offi = 0;
384 else if (source->type->scalar & FLOAT && source->storage == CONSTANT)
386 float val;
388 val = *source->offset.offd;
389 #ifdef I80386
390 if (i386_32)
391 loadconst(((offset_T *) &val)[0], targreg); /* XXX 386 */
392 else
393 #endif
395 loadconst(((unsigned short *) &val)[0], DREG);
396 loadconst(((unsigned short *) &val)[1], targreg&~DREG);
399 #ifdef I80386
400 else if (!i386_32 && source->type->scalar & FLOAT)
401 #else
402 else if (source->type->scalar & FLOAT)
403 #endif
405 /* Treat a float just like a long ... */
406 if (source->indcount == 0)
408 if (source->storage != (store_t) targreg)
409 transfer(source, targreg);
410 if (source->offset.offi != 0)
411 bugerror("loading direct float with offset not implemented");
413 else
414 loadlongindirect(source, targreg);
416 else if (source->indcount == 0 && source->storage != CONSTANT)
417 loadadr(source, targreg);
418 else if (source->type->scalar ||
419 source->type->constructor & (ARRAY | POINTER))
420 loadreg(source, targreg);
421 else
422 bugerror("attempting to load non-scalar non-pointer");
425 PRIVATE void loadadr(source, targreg)
426 struct symstruct *source;
427 store_pt targreg;
429 if ((store_t) targreg & ALLDATREGS)
431 if (source->storage == GLOBAL)
433 #ifdef MC6809
434 if (posindependent)
436 pushreg(INDREG0);
437 loadreg(source, INDREG0);
438 transfer(source, DREG);
439 recovlist(INDREG0);
441 else
442 #endif
443 loadreg(source, targreg);
445 if (source->storage == LOCAL)
446 #ifdef FRAMEPOINTER
447 source->offset.offi -= framep;
448 #else
449 source->offset.offi -= sp;
450 #endif
451 if (source->type->scalar & CHAR)
452 targreg = BREG;
453 #ifdef I8088
454 if (source->storage == DREG)
455 addoffset(source);
456 #endif
457 if (source->storage != (store_t) targreg)
458 transfer(source, targreg);
459 addoffset(source);
461 else if (source->storage & ALLDATREGS)
463 addoffset(source);
464 transfer(source, targreg);
466 else if (source->storage != (store_t) targreg ||
467 source->offset.offi != 0 || source->level == OFFKLUDGELEVEL)
468 loadreg(source, targreg);
471 PUBLIC void loadany(source)
472 struct symstruct *source;
474 if (source->indcount != 0 || source->offset.offi != 0 || /* kludge u cmp */
475 source->level == OFFKLUDGELEVEL || !(source->storage & allregs))
477 if (source->type->scalar & RSCALAR)
478 load(source, doubleregs & ~DREG);
479 else if ((source->storage == CONSTANT &&
480 !(source->type->scalar & DLONG))
481 || source->type->scalar & CHAR)
482 load(source, DREG);
483 else if (source->storage & ~reguse & allregs)
484 load(source, source->storage);
485 else if (((reguse & allindregs) == allindregs ||
486 ((!(source->type->constructor & (ARRAY | POINTER)) &&
487 source->indcount != 0) &&
488 !(source->type->scalar & DLONG))))
489 load(source, DREG);
490 else
491 load(source, getindexreg());
495 PRIVATE void loadlongindirect(source, targreg)
496 struct symstruct *source;
497 store_pt targreg;
499 sc_t flags;
500 offset_T offset;
501 store_t reg;
502 struct typestruct *type;
504 if (source->level == OFFKLUDGELEVEL)
505 addoffset(source); /* else kludge is lost and offsets big */
506 flags = source->flags;
507 offset = source->offset.offi;
508 reg = source->storage;
509 type = source->type;
510 source->type = itype;
511 loadreg(source, DREG);
512 source->flags = flags;
513 source->storage = reg;
514 source->indcount = 1;
515 source->offset.offi = offset + accregsize;
516 loadreg(source, targreg);
517 source->type = type;
520 PUBLIC void loadreg(source, targreg)
521 struct symstruct *source;
522 store_pt targreg;
524 offset_T longhigh;
525 offset_T longlow;
527 if (source->storage == CONSTANT)
529 if (source->type->scalar & CHAR && (store_t) targreg & ALLDATREGS)
530 targreg = BREG;
531 longlow = (offset_T) source->offset.offv;
532 if (source->type->scalar & DLONG)
534 longlow &= (offset_T) intmaskto;
535 longhigh = (offset_T) (source->offset.offv >> INT16BITSTO)
536 & (offset_T) intmaskto;
537 if ((store_t) targreg != LONGREG2) /* loading the whole long */
539 #if DYNAMIC_LONG_ORDER
540 if (long_big_endian)
541 #endif
542 #if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN
543 loadconst(longhigh, DREG);
544 #endif
545 #if DYNAMIC_LONG_ORDER
546 else
547 #endif
548 #if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN == 0
550 loadconst(longlow, DREG);
551 longlow = longhigh;
553 #endif
556 loadconst(longlow, targreg);
557 source->storage = targreg;
558 source->offset.offi = 0;
560 else
562 #ifdef I8088
563 if (source->indcount == 0 && source->storage != GLOBAL &&
564 (source->offset.offi != 0 || source->level == OFFKLUDGELEVEL))
566 if ((store_t) targreg == source->storage)
568 addoffset(source);
569 return;
571 source->indcount = 1; /* fake for outadr() to produce "()" */
572 outlea();
574 else
576 #ifdef I8088
577 /* Added acess to CPU registers. Just declare _AX etc. as
578 * extern int, and you can use them to get/set
579 * the register values. (vak) */
580 if (source->storage == GLOBAL && !(source->flags & LABELLED) &&
581 *source->name.namep != 0 &&
582 strncmp(source->name.namep, "__", 2) == 0)
584 if (strcmp (source->name.namep, "__AX") == 0)
586 /* Load AX register - do nothing. */
587 done:
588 if (targreg != AXREG)
589 bugerror("specified access of register clone variable not implemented");
590 source->storage = AXREG; /* in register for further use */
591 source->flags = 0;
592 if (source->level == OFFKLUDGELEVEL)
593 source->level = EXPRLEVEL;
594 source->offset.offi = 0; /* indcount was adjusted by outadr */
595 return;
597 if (strcmp (source->name.namep, "__BX") == 0) { outstr ("mov\tax,bx\n"); goto done; }
598 if (strcmp (source->name.namep, "__CX") == 0) { outstr ("mov\tax,cx\n"); goto done; }
599 if (strcmp (source->name.namep, "__DX") == 0) { outstr ("mov\tax,dx\n"); goto done; }
600 if (strcmp (source->name.namep, "__SP") == 0) { outstr ("mov\tax,sp\n"); goto done; }
601 if (strcmp (source->name.namep, "__BP") == 0) { outstr ("mov\tax,bp\n"); goto done; }
602 if (strcmp (source->name.namep, "__SI") == 0) { outstr ("mov\tax,si\n"); goto done; }
603 if (strcmp (source->name.namep, "__DI") == 0) { outstr ("mov\tax,di\n"); goto done; }
604 if (strcmp (source->name.namep, "__CS") == 0) { outstr ("mov\tax,cs\n"); goto done; }
605 if (strcmp (source->name.namep, "__DS") == 0) { outstr ("mov\tax,ds\n"); goto done; }
606 if (strcmp (source->name.namep, "__ES") == 0) { outstr ("mov\tax,es\n"); goto done; }
607 if (strcmp (source->name.namep, "__SS") == 0) { outstr ("mov\tax,ss\n"); goto done; }
608 if (strcmp (source->name.namep, "__FLAGS") == 0) { outstr ("pushf\npop\tax\n"); goto done; }
610 #endif
611 outload();
612 if (source->storage == GLOBAL && source->indcount != 0 &&
613 (store_t) targreg & (AXREG | ALREG))
614 unbumplc();
616 #endif
617 #ifdef MC6809
618 if (source->indcount == 0 &&
619 (source->storage != GLOBAL || posindependent))
620 outlea();
621 else
623 outload();
624 if ((store_t) targreg == YREG)
625 bumplc();
627 #endif
628 movereg(source, targreg);
632 PUBLIC void makelessindirect(source)
633 struct symstruct *source;
635 store_pt lreg;
637 if (!((store_t) (lreg = source->storage) & ~reguse & allindregs))
638 lreg = getindexreg();
639 while (source->indcount > MAXINDIRECT)
640 loadreg(source, lreg);
641 #if MAXINDIRECT > 1
642 if (source->indcount == MAXINDIRECT &&
643 (source->type->typesize > maxregsize ||
644 source->type->constructor & FUNCTION))
646 source->indcount = 1;
647 loadreg(source, lreg);
648 source->indcount = 1;
650 #endif
653 PUBLIC void movereg(source, targreg)
654 struct symstruct *source;
655 store_pt targreg;
657 if ((store_t) targreg & ALLDATREGS && source->type->scalar & CHAR)
658 targreg = BREG;
659 #ifdef I8086
660 if (source->type->scalar & CHAR &&
661 targreg != BREG && targreg != DATREG1B ) {
662 bugerror("moving char sym into int register");
664 #endif
665 #ifdef I80386
666 if (i386_32 && source->type->scalar & SHORT &&
667 source->indcount <= 1)
669 outshortregname(targreg);
670 bumplc();
672 else
673 #endif
674 outregname(targreg);
675 if (source->storage == CONSTANT)
676 adjlc((offset_T) source->offset.offv, targreg);
677 #ifdef I8088
678 outcomma();
679 #endif
680 outadr(source);
681 source->storage = targreg; /* in register for further use */
682 source->flags = 0;
683 if (source->level == OFFKLUDGELEVEL)
684 source->level = EXPRLEVEL;
685 source->offset.offi = 0; /* indcount was adjusted by outadr */
688 PUBLIC void onstack(target)
689 register struct symstruct *target;
691 target->storage = LOCAL;
692 target->flags = TEMP;
693 if (target->level == OFFKLUDGELEVEL)
694 target->level = EXPRLEVEL;
695 target->indcount = 1;
696 target->offset.offi = sp;
699 PUBLIC void outadr(adr)
700 struct symstruct *adr;
702 outnnadr(adr);
703 outnl();
706 PUBLIC void outcregname(reg)
707 store_pt reg;
709 outcomma();
710 outregname(reg);
713 PRIVATE void outnamoffset(adr)
714 struct symstruct *adr;
716 if (adr->flags & LABELLED)
717 outlabel(adr->name.label);
718 else
719 outccname(adr->name.namep);
720 if (adr->offset.offi != 0)
722 if (adr->offset.offi > 0)
723 outplus();
724 outshex(adr->offset.offi);
726 bumplc2();
727 #ifdef I80386
728 if (i386_32)
729 bumplc2();
730 #endif
733 /* print comma, then register name, then newline */
735 PUBLIC void outncregname(reg)
736 store_pt reg;
738 outcomma();
739 outnregname(reg);
742 PRIVATE void outnnadr(adr)
743 struct symstruct *adr;
745 bool_t indflag;
747 indflag = FALSE;
748 #ifdef I8088
749 if (adr->indcount >= MAXINDIRECT)
750 indflag = TRUE;
751 #endif
752 #ifdef MC6809
753 outtab();
754 if (adr->indcount >= MAXINDIRECT && (adr->indcount & 1) == 0)
756 indflag = TRUE; /* indirection means double indirect */
757 outindleft();
759 #endif
760 switch (adr->storage)
762 case CONSTANT:
763 outimmadr((offset_T) adr->offset.offv);
764 break;
765 #ifdef I8088
766 case DREG:
767 if (indflag || adr->offset.offi != 0 || adr->level == OFFKLUDGELEVEL)
768 badaddress();
769 else
770 outregname(DREG);
771 break;
772 #endif
773 #ifdef I8088
774 case DATREG1:
775 case DATREG2:
776 #ifdef I80386
777 if (indflag && !i386_32)
778 #else
779 if (indflag)
780 #endif
782 outnl();
783 badaddress();
784 break;
786 #endif
787 case INDREG0:
788 case INDREG1:
789 case INDREG2:
790 if (adr->level == OFFKLUDGELEVEL)
792 #ifdef I8088
793 if (!indflag)
794 #endif
795 outimmed();
796 outnamoffset(adr);
798 #ifndef MC6809
799 else if (adr->offset.offi != 0)
800 #endif
801 outoffset(adr->offset.offi);
802 #ifdef I8088
803 if (indflag)
804 outindleft();
805 outregname(adr->storage);
806 # ifdef XENIX_AS
807 if (indflag)
808 outindright();
809 # endif
810 #endif
811 #ifdef MC6809
812 if (indflag && adr->offset.offi != 0 && is5bitoffset(adr->offset.offi))
813 bumplc();
814 outcregname(adr->storage);
815 #endif
816 break;
817 case LOCAL:
818 #ifdef I8088
819 # ifdef FRAMEPOINTER
820 if (framep == 0)
821 bugerror("no frame pointer");
822 if (indflag)
824 if (adr->offset.offi == framep)
825 bumplc();
826 else
828 int off;
829 if (switchnow != NULL && adr->flags == TEMP)
830 outswoffset(off = adr->offset.offi);
831 else
832 outoffset(off = adr->offset.offi - framep);
833 #ifndef NO_DEL_PUSH
834 if (optimise && !callersaves && off < 0)
836 outstr("+");
837 outstr(funcname);
838 outstr(".off");
840 #endif
842 outindleft();
844 else if (adr->offset.offi != framep)
845 badaddress();
846 outregname(LOCAL);
847 # else
848 if (indflag)
850 bumplc();
851 if (adr->offset.offi != sp)
852 outoffset(adr->offset.offi - sp);
853 outindleft();
855 else if (adr->offset.offi != sp)
856 badaddress();
857 outregname(LOCAL);
858 # endif /* FRAMEPOINTER */
859 # ifdef XENIX_AS
860 if (indflag)
861 outindright();
862 # endif
863 #endif /* I8088 */
864 #ifdef MC6809
865 if (adr->flags == TEMP && adr->offset.offi == sp &&
866 adr->indcount == 1)
868 outcregname(LOCAL);
869 outplus();
870 ++sp;
871 if (adr->type->typesize != 1)
873 outplus();
874 ++sp;
876 break;
878 outoffset(adr->offset.offi - sp);
879 if (indflag && adr->offset.offi != sp &&
880 is5bitoffset(adr->offset.offi - sp))
881 bumplc();
882 outcregname(LOCAL);
883 #endif /* MC6809 */
884 break;
885 case GLOBAL:
886 #ifdef I8088
887 bumplc();
888 #ifdef I80386
889 if (i386_32)
890 bumplc2();
891 #endif
892 if (!indflag)
893 outimmed();
894 else
896 # ifndef XENIX_AS
897 outindleft();
898 # endif
899 bumplc();
901 #endif
902 #ifdef MC6809
903 if (!posindependent)
905 if (adr->indcount == 0)
907 outimmed();
908 bumplc();
910 else if (indflag)
912 outextended();
913 bumplc2();
915 else if (adr->flags & DIRECTPAGE)
916 outdirectpage();
917 else
919 outextended();
920 bumplc();
923 #endif
924 if (adr->flags & LABELLED)
925 outlabel(adr->name.label);
926 else if (*adr->name.namep == 0) /* constant address */
928 outhex((uoffset_T) adr->offset.offi);
929 break;
931 else
932 outccname(adr->name.namep);
933 if (adr->offset.offi != 0)
935 if (adr->offset.offi > 0)
936 outplus();
937 outshex(adr->offset.offi);
939 #ifdef MC6809
940 if (posindependent)
942 outcregname(GLOBAL);
943 bumplc2();
945 #endif
946 break;
947 default:
948 outnl();
949 badaddress();
950 break;
952 #ifdef I8088
953 if (indflag)
955 --adr->indcount;
956 # ifndef XENIX_AS
957 outindright();
958 # endif
960 #endif
961 #ifdef MC6809
962 if (indflag)
964 outindright();
965 adr->indcount -= MAXINDIRECT;
967 else if (adr->indcount != 0)
968 --adr->indcount;
969 #endif
972 /* print register name, then newline */
974 PUBLIC void outnregname(reg)
975 store_pt reg;
977 outregname(reg);
978 outnl();
981 /* print register name */
983 PUBLIC void outregname(reg)
984 store_pt reg;
986 switch ((store_t) reg)
988 case BREG:
989 outstr(acclostr);
990 break;
991 case DREG:
992 outstr(accumstr);
993 break;
994 #ifdef MC6809
995 case GLOBAL:
996 outstr("PC");
997 break;
998 #endif
999 case INDREG0:
1000 outstr(ireg0str);
1001 regfuse |= INDREG0;
1002 break;
1003 case INDREG1:
1004 outstr(ireg1str);
1005 regfuse |= INDREG1;
1006 break;
1007 case INDREG2:
1008 outstr(ireg2str);
1009 regfuse |= INDREG2;
1010 break;
1011 case LOCAL:
1012 outstr(localregstr);
1013 regfuse |= LOCAL;
1014 break;
1015 #ifdef STACKREG
1016 case STACKREG:
1017 outstr(stackregstr);
1018 break;
1019 #endif
1020 #ifdef DATREG1
1021 case DATREG1:
1022 outstr(dreg1str);
1023 break;
1024 #endif
1025 #ifdef DATREG1B
1026 case DATREG1B:
1027 outstr(dreg1bstr);
1028 break;
1029 #endif
1030 #ifdef DATREG2
1031 case DATREG2:
1032 outstr(dreg2str);
1033 break;
1034 #endif
1035 default:
1036 { int i;
1037 if (reg)
1038 for(i=1; i; i<<=1)
1040 if( reg&i )
1042 outregname(i);
1043 outstr(" ");
1046 else
1047 outstr(badregstr);
1049 break;
1053 #if defined(I8088) && defined(I80386)
1054 /* print register name for short type */
1056 PUBLIC void outshortregname(reg)
1057 store_pt reg;
1059 switch ((store_t) reg)
1061 case DREG:
1062 outstr(accumstr + 1);
1063 break;
1064 case INDREG0:
1065 outstr(ireg0str + 1);
1066 break;
1067 case INDREG1:
1068 outstr(ireg1str + 1);
1069 break;
1070 case INDREG2:
1071 outstr(ireg2str + 1);
1072 break;
1073 case DATREG1:
1074 outstr(dreg1str + 1);
1075 break;
1076 case DATREG2:
1077 outstr(dreg2str + 1);
1078 break;
1079 default:
1080 outstr(badregstr);
1081 break;
1085 #endif
1087 /*-----------------------------------------------------------------------------
1088 pointat(target leaf)
1089 point OPREG at target
1090 target must be singly indirect or float or double
1091 -----------------------------------------------------------------------------*/
1093 PUBLIC void pointat(target)
1094 struct symstruct *target;
1096 if (target->type->scalar & RSCALAR)
1097 (void) f_indirect(target);
1098 address(target);
1099 load(target, OPREG);
1100 target->type = target->type->nexttype;
1103 PUBLIC void poplist(reglist)
1104 store_pt reglist;
1106 if (reglist)
1107 sp += pushpull(reglist, FALSE);
1110 PUBLIC void push(source)
1111 struct symstruct *source;
1113 store_t reg;
1114 #ifdef I8088
1115 uoffset_T size;
1116 #endif
1117 scalar_t sscalar;
1119 if (source->type->constructor & STRUCTU)
1121 if (source->flags != TEMP) /* TEMP must be from last function */
1122 blockpush(source);
1124 else if ((sscalar = source->type->scalar) & RSCALAR)
1126 if (!f_indirect(source))
1128 saveopreg();
1129 fpush(source);
1130 restoreopreg();
1133 #ifdef I8088
1134 else if ((source->indcount == 1 &&
1135 (sscalar & (SHORT | INT | LONG | FLOAT) ||
1136 source->type->constructor & POINTER))
1137 #ifdef I80386
1138 || (source->storage == CONSTANT && i386_32)
1139 #endif
1142 size = source->type->typesize;
1143 if (size == 1)
1144 size = 2;
1145 if (sscalar & DLONG)
1147 source->offset.offi += itypesize;
1148 outpshs();
1149 bumplc();
1150 outtab();
1151 outadr(source);
1152 source->indcount = 1;
1153 source->offset.offi -= itypesize;
1155 outpshs();
1156 bumplc();
1157 outtab();
1158 #ifdef I80386
1159 if (i386_32)
1161 if (source->storage == CONSTANT)
1163 unbumplc();
1164 adjlc((offset_T) source->offset.offv, INDREG0);
1166 if (size == 2)
1168 outword();
1169 bumplc();
1171 else
1172 outdword();
1174 #endif
1175 outadr(source);
1176 sp -= size;
1178 #endif
1179 else
1181 reg = source->storage;
1182 loadany(source);
1183 if (sscalar & DLONG)
1184 pushlist(DREG | source->storage);
1185 else if (sscalar & CHAR)
1186 pushchar();
1187 else
1188 pushreg(source->storage);
1189 if (source->flags != REGVAR)
1190 reguse &= ~(reg | source->storage);
1192 onstack(source);
1195 PUBLIC void pushlist(reglist)
1196 store_pt reglist;
1198 if ((store_t) reglist)
1199 sp -= pushpull(reglist, TRUE);
1202 PRIVATE fastin_pt pushpull(reglist, pushflag)
1203 store_pt reglist;
1204 bool_pt pushflag;
1206 store_pt lastregbit;
1207 void (*ppfunc) P((void));
1208 char *regptr;
1210 #ifdef MC6809
1211 int separator; /* promoted char for output */
1213 #endif
1214 fastin_t bytespushed;
1215 store_pt regbit;
1217 if ((bool_t) pushflag)
1219 ppfunc = outpshs;
1220 #ifdef I8088
1221 regbit = 1 << 10;
1222 #else
1223 regbit = 1 << 7;
1224 #endif
1225 regptr = regpushlist;
1226 lastregbit = 1;
1228 else
1230 ppfunc = outpuls;
1231 regbit = 1;
1232 regptr = regpulllist;
1233 #ifdef I8088
1234 lastregbit = 1 << 10;
1235 #else
1236 lastregbit = 1 << 7;
1237 #endif
1239 #ifdef MC6809 /* temp use pull strings to keep old order */
1240 regbit = 1;
1241 regptr = regpulllist;
1242 lastregbit = 1 << 7;
1243 #endif
1244 #ifdef MC6809
1245 separator = OPSEPARATOR;
1246 (*ppfunc) ();
1247 #endif
1248 bytespushed = 0;
1249 while (TRUE)
1251 if (regbit & reglist)
1253 #ifdef I8088
1254 (*ppfunc)();
1255 if (*regptr != FLAGSREGCHAR)
1256 outtab();
1257 #endif
1258 #ifdef MC6809
1259 outbyte(separator);
1260 #endif
1262 outbyte(*regptr++);
1263 while (*regptr >= MINREGCHAR);
1264 bytespushed += *regptr++ - '0';
1265 #ifdef I8088
1266 outnl();
1267 #endif
1268 #ifdef MC6809
1269 separator = OPERANDSEPARATOR;
1270 #endif
1272 else
1275 while (*regptr++ >= MINREGCHAR);
1276 if (regbit == lastregbit)
1277 break;
1278 #ifdef MC6809 /* temp use pull strings to keep old order */
1279 regbit <<= 1;
1280 #else /* this should normally be unconditional */
1281 if ((bool_t) pushflag)
1282 regbit >>= 1;
1283 else
1284 regbit <<= 1;
1285 #endif
1287 #ifdef MC6809
1288 outnl();
1289 #endif
1290 return bytespushed;
1293 PUBLIC void pushreg(reg)
1294 store_pt reg;
1296 outpshs();
1297 outtab();
1298 outnregname(reg);
1299 sp -= pshregsize;
1302 PUBLIC void storereg(sourcereg, target)
1303 store_pt sourcereg;
1304 struct symstruct *target;
1306 store_pt targreg;
1308 if (target->indcount == 0)
1310 if (target->offset.offi != 0 || target->level == OFFKLUDGELEVEL ||
1311 !(target->storage & allregs) || target->storage & CHARREGS)
1312 bugerror("bad register store");
1313 else if ((store_t) (targreg = target->storage) != (store_t) sourcereg)
1315 target->storage = sourcereg;
1316 loadadr(target, targreg); /* do LEA or TFR */
1319 else
1321 #ifdef I8088
1322 /* Added acess to CPU registers. Just declare _AX etc. as
1323 * extern int, and you can use them to get/set
1324 * the register values. (vak) */
1325 if (target->storage == GLOBAL && !(target->flags & LABELLED) &&
1326 *target->name.namep != 0 &&
1327 strncmp(target->name.namep, "__", 2) == 0)
1329 if (strcmp (target->name.namep, "__AX") == 0) { return; }
1330 if (strcmp (target->name.namep, "__BX") == 0) { outstr ("mov\tbx,"); outregname(sourcereg); outnl(); return; }
1331 if (strcmp (target->name.namep, "__CX") == 0) { outstr ("mov\tcx,"); outregname(sourcereg); outnl(); return; }
1332 if (strcmp (target->name.namep, "__DX") == 0) { outstr ("mov\tdx,"); outregname(sourcereg); outnl(); return; }
1333 if (strcmp (target->name.namep, "__SP") == 0) { outstr ("mov\tsp,"); outregname(sourcereg); outnl(); return; }
1334 if (strcmp (target->name.namep, "__BP") == 0) { outstr ("mov\tbp,"); outregname(sourcereg); outnl(); return; }
1335 if (strcmp (target->name.namep, "__SI") == 0) { outstr ("mov\tsi,"); outregname(sourcereg); outnl(); return; }
1336 if (strcmp (target->name.namep, "__DI") == 0) { outstr ("mov\tdi,"); outregname(sourcereg); outnl(); return; }
1337 if (strcmp (target->name.namep, "__CS") == 0) { outstr ("mov\tcs,"); outregname(sourcereg); outnl(); return; }
1338 if (strcmp (target->name.namep, "__DS") == 0) { outstr ("mov\tds,"); outregname(sourcereg); outnl(); return; }
1339 if (strcmp (target->name.namep, "__ES") == 0) { outstr ("mov\tes,"); outregname(sourcereg); outnl(); return; }
1340 if (strcmp (target->name.namep, "__SS") == 0) { outstr ("mov\tss,"); outregname(sourcereg); outnl(); return; }
1341 if (strcmp (target->name.namep, "__FLAGS") == 0) { outstr ("push\tax"); outregname(sourcereg); outstr ("\npopf\n"); return; }
1343 #endif
1344 outstore();
1345 #ifdef I8088
1346 if (target->storage == GLOBAL && (store_t) sourcereg & (AXREG | ALREG))
1347 unbumplc();
1348 outnnadr(target);
1349 outcomma();
1350 #ifdef I80386
1351 if (i386_32 && target->type->scalar & SHORT)
1353 outshortregname(sourcereg);
1354 bumplc();
1355 outnl();
1357 else
1358 #endif
1359 outnregname(sourcereg);
1360 #endif
1361 #ifdef MC6809
1362 if ((store_t) sourcereg == YREG)
1363 bumplc();
1364 outregname(sourcereg);
1365 outadr(target);
1366 #endif
1370 /*-----------------------------------------------------------------------------
1371 struc(element leaf, structure leaf)
1372 evaluates the expression
1373 structure.element
1374 -----------------------------------------------------------------------------*/
1376 PUBLIC void struc(source, target)
1377 struct symstruct *source;
1378 struct symstruct *target;
1380 address(target);
1381 if (source->offset.offi != 0 || source->level == OFFKLUDGELEVEL)
1383 if (target->indcount != 0 || target->level == OFFKLUDGELEVEL)
1384 load(target, getindexreg());
1385 target->offset.offi += source->offset.offi;
1387 if (source->indcount == 0)
1388 target->type = source->type;
1389 else
1391 target->type = pointype(source->type); /* lost by = */
1392 indirec(target);
1396 PUBLIC void transfer(source, targreg)
1397 struct symstruct *source;
1398 store_pt targreg;
1400 regtransfer(source->storage, targreg);
1401 source->storage = targreg;