1 /*-------------------------------------------------------------------------
2 gen.c - Z80 specific code generator.
4 Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
6 Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
7 Improved WORD push 22784 144 19AE
8 With label1 on 22694 144 197E
9 With label2 on 22743 144 198A
10 With label3 on 22776 144 1999
11 With label4 on 22776 144 1999
12 With all 'label' on 22661 144 196F
13 With loopInvariant on 20919 156 19AB
14 With loopInduction on Breaks 198B
15 With all working on 20796 158 196C
16 Slightly better genCmp(signed) 20597 159 195B
17 Better reg packing, first peephole 20038 163 1873
18 With assign packing 19281 165 1849
21 Michael Hope <michaelh@earthling.net> 2000
22 Based on the mcs51 generator -
23 Sandeep Dutta . sandeep.dutta@usa.net (1998)
24 and - Jean-Louis VERN.jlvern@writeme.com (1999)
26 This program is free software; you can redistribute it and/or modify it
27 under the terms of the GNU General Public License as published by the
28 Free Software Foundation; either version 2, or (at your option) any
31 This program is distributed in the hope that it will be useful,
32 but WITHOUT ANY WARRANTY; without even the implied warranty of
33 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 GNU General Public License for more details.
37 You should have received a copy of the GNU General Public License
38 along with this program; if not, write to the Free Software
39 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
41 In other words, you are welcome to use, share and improve this program.
42 You are forbidden to forbid anyone else to use, share and improve
43 what you give them. Help stamp out software-hoarding!
45 -------------------------------------------------------------------------*/
52 #ifdef HAVE_SYS_ISA_DEFS_H
53 #include <sys/isa_defs.h>
57 #include "SDCCpeeph.h"
61 /* this is the down and dirty file with all kinds of kludgy & hacky
62 stuff. This is what it is all about CODE GENERATION for a specific MCU.
63 Some of the routines may be reusable, will have to see */
66 static char *_z80_return[] = {"l", "h", "e", "d" };
67 static char *_gbz80_return[] = { "e", "d", "l", "h" };
68 static char **_fReturn;
74 static char *accUse[] = {"a" };
75 static char *hlUse[] = { "l", "h" };
81 extern int ptrRegReq ;
83 extern FILE *codeOutFile;
100 } _pairs[NUM_PAIRS] = {
105 { "iy", "iy.l?", "iy.h?" },
106 { "ix", "ix.l?", "ix.h?" }
109 #define RESULTONSTACK(x) \
110 (IC_RESULT(x) && IC_RESULT(x)->aop && \
111 IC_RESULT(x)->aop->type == AOP_STK )
113 #define MOVA(x) if (strcmp(x,"a")) emitcode("ld","a,%s",x);
114 #define CLRC emitcode("xor","a,a");
116 lineNode *lineHead = NULL;
117 lineNode *lineCurr = NULL;
119 static const unsigned char SLMask[] =
120 {0xFF ,0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00};
121 static const unsigned char SRMask[] =
122 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00};
153 static char *aopGet(asmop *aop, int offset, bool bit16);
155 static void _tidyUp(char *buf)
157 /* Clean up the line so that it is 'prettier' */
158 if (strchr(buf, ':')) {
159 /* Is a label - cant do anything */
162 /* Change the first (and probably only) ' ' to a tab so
174 static void emit2(const char *szFormat, ...)
179 va_start(ap, szFormat);
181 tvsprintf(buffer, szFormat, ap);
184 lineCurr = (lineCurr ?
185 connectLine(lineCurr,newLineNode(buffer)) :
186 (lineHead = newLineNode(buffer)));
188 lineCurr->isInline = inLine;
189 lineCurr->isDebug = debugLine;
192 /*-----------------------------------------------------------------*/
193 /* emitcode - writes the code into a file : for now it is simple */
194 /*-----------------------------------------------------------------*/
195 void emitcode (const char *inst, const char *fmt, ...)
198 char lb[MAX_INLINEASM];
204 sprintf(lb,"%s\t",inst);
205 vsprintf(lb+(strlen(lb)),fmt,ap);
209 while (isspace(*lbp)) lbp++;
212 lineCurr = (lineCurr ?
213 connectLine(lineCurr,newLineNode(lb)) :
214 (lineHead = newLineNode(lb)));
215 lineCurr->isInline = inLine;
216 lineCurr->isDebug = debugLine;
233 emitcode("ld", "sp,ix");
234 emitcode("pop", "ix");
235 emitcode("pop", "de");
240 const char *getPairName(asmop *aop)
242 if (aop->type == AOP_REG) {
243 switch (aop->aopu.aop_reg[0]->rIdx) {
255 else if (aop->type == AOP_STR) {
256 switch (*aop->aopu.aop_str[0]) {
272 static PAIR_ID getPairId(asmop *aop)
274 if (aop->size == 2) {
275 if (aop->type == AOP_REG) {
276 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX)&&(aop->aopu.aop_reg[1]->rIdx == B_IDX)) {
279 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX)&&(aop->aopu.aop_reg[1]->rIdx == D_IDX)) {
282 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX)&&(aop->aopu.aop_reg[1]->rIdx == H_IDX)) {
286 if (aop->type == AOP_STR) {
287 if (!strcmp(aop->aopu.aop_str[0], "c")&&!strcmp(aop->aopu.aop_str[1], "b")) {
290 if (!strcmp(aop->aopu.aop_str[0], "e")&&!strcmp(aop->aopu.aop_str[1], "d")) {
293 if (!strcmp(aop->aopu.aop_str[0], "l")&&!strcmp(aop->aopu.aop_str[1], "h")) {
301 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
302 bool isPair(asmop *aop)
304 return (getPairId(aop) != PAIR_INVALID);
307 bool isPtrPair(asmop *aop)
309 PAIR_ID pairId = getPairId(aop);
319 /** Push a register pair onto the stack */
320 void genPairPush(asmop *aop)
322 emitcode("push", "%s", getPairName(aop));
326 /*-----------------------------------------------------------------*/
327 /* newAsmop - creates a new asmOp */
328 /*-----------------------------------------------------------------*/
329 static asmop *newAsmop (short type)
333 ALLOC(aop,sizeof(asmop));
338 /*-----------------------------------------------------------------*/
339 /* aopForSym - for a true symbol */
340 /*-----------------------------------------------------------------*/
341 static asmop *aopForSym (iCode *ic,symbol *sym,bool result, bool requires_a)
350 space = SPEC_OCLS(sym->etype);
352 /* if already has one */
356 /* Assign depending on the storage class */
357 if (sym->onStack || sym->iaccess) {
358 emitcode("", "; AOP_STK for %s", sym->rname);
359 sym->aop = aop = newAsmop(AOP_STK);
360 aop->size = getSize(sym->type);
361 aop->aopu.aop_stk = sym->stack;
365 /* special case for a function */
366 if (IS_FUNC(sym->type)) {
367 sym->aop = aop = newAsmop(AOP_IMMD);
368 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(sym->rname)+1);
369 strcpy(aop->aopu.aop_immd,sym->rname);
375 /* if it is in direct space */
376 if (IN_REGSP(space) && !requires_a) {
377 sym->aop = aop = newAsmop (AOP_SFR);
378 aop->aopu.aop_dir = sym->rname ;
379 aop->size = getSize(sym->type);
380 emitcode("", "; AOP_SFR for %s", sym->rname);
385 /* only remaining is far space */
386 /* in which case DPTR gets the address */
388 emitcode("", "; AOP_HL for %s", sym->rname);
389 sym->aop = aop = newAsmop(AOP_HL);
392 sym->aop = aop = newAsmop(AOP_IY);
394 aop->size = getSize(sym->type);
395 aop->aopu.aop_dir = sym->rname;
397 /* if it is in code space */
398 if (IN_CODESPACE(space))
404 /*-----------------------------------------------------------------*/
405 /* aopForRemat - rematerialzes an object */
406 /*-----------------------------------------------------------------*/
407 static asmop *aopForRemat (symbol *sym)
410 iCode *ic = sym->rematiCode;
411 asmop *aop = newAsmop(AOP_IMMD);
414 /* if plus or minus print the right hand side */
415 if (ic->op == '+' || ic->op == '-') {
416 /* PENDING: for re-target */
417 sprintf(s,"0x%04x %c ",(int) operandLitValue(IC_RIGHT(ic)),
420 ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode;
423 /* we reached the end */
424 sprintf(s,"%s",OP_SYMBOL(IC_LEFT(ic))->rname);
428 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(buffer)+1);
429 strcpy(aop->aopu.aop_immd,buffer);
433 /*-----------------------------------------------------------------*/
434 /* regsInCommon - two operands have some registers in common */
435 /*-----------------------------------------------------------------*/
436 bool regsInCommon (operand *op1, operand *op2)
441 /* if they have registers in common */
442 if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
445 sym1 = OP_SYMBOL(op1);
446 sym2 = OP_SYMBOL(op2);
448 if (sym1->nRegs == 0 || sym2->nRegs == 0)
451 for (i = 0 ; i < sym1->nRegs ; i++) {
456 for (j = 0 ; j < sym2->nRegs ;j++ ) {
460 if (sym2->regs[j] == sym1->regs[i])
468 /*-----------------------------------------------------------------*/
469 /* operandsEqu - equivalent */
470 /*-----------------------------------------------------------------*/
471 bool operandsEqu ( operand *op1, operand *op2)
475 /* if they not symbols */
476 if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
479 sym1 = OP_SYMBOL(op1);
480 sym2 = OP_SYMBOL(op2);
482 /* if both are itemps & one is spilt
483 and the other is not then false */
484 if (IS_ITEMP(op1) && IS_ITEMP(op2) &&
485 sym1->isspilt != sym2->isspilt )
488 /* if they are the same */
492 if (strcmp(sym1->rname,sym2->rname) == 0)
496 /* if left is a tmp & right is not */
500 (sym1->usl.spillLoc == sym2))
507 (sym2->usl.spillLoc == sym1))
513 /*-----------------------------------------------------------------*/
514 /* sameRegs - two asmops have the same registers */
515 /*-----------------------------------------------------------------*/
516 bool sameRegs (asmop *aop1, asmop *aop2 )
520 if (aop1->type == AOP_SFR ||
521 aop2->type == AOP_SFR)
527 if (aop1->type != AOP_REG ||
528 aop2->type != AOP_REG )
531 if (aop1->size != aop2->size)
534 for (i = 0 ; i < aop1->size ; i++ )
535 if (aop1->aopu.aop_reg[i] !=
536 aop2->aopu.aop_reg[i] )
542 /*-----------------------------------------------------------------*/
543 /* aopOp - allocates an asmop for an operand : */
544 /*-----------------------------------------------------------------*/
545 static void aopOp (operand *op, iCode *ic, bool result, bool requires_a)
554 /* if this a literal */
555 if (IS_OP_LITERAL(op)) {
556 op->aop = aop = newAsmop(AOP_LIT);
557 aop->aopu.aop_lit = op->operand.valOperand;
558 aop->size = getSize(operandType(op));
562 /* if already has a asmop then continue */
566 /* if the underlying symbol has a aop */
567 if (IS_SYMOP(op) && OP_SYMBOL(op)->aop) {
568 op->aop = OP_SYMBOL(op)->aop;
572 /* if this is a true symbol */
573 if (IS_TRUE_SYMOP(op)) {
574 op->aop = aopForSym(ic, OP_SYMBOL(op), result, requires_a);
578 /* this is a temporary : this has
584 e) can be a return use only */
588 /* if the type is a conditional */
589 if (sym->regType == REG_CND) {
590 aop = op->aop = sym->aop = newAsmop(AOP_CRY);
595 /* if it is spilt then two situations
597 b) has a spill location */
598 if (sym->isspilt || sym->nRegs == 0) {
599 /* rematerialize it NOW */
601 sym->aop = op->aop = aop =
603 aop->size = getSize(sym->type);
609 if (sym->accuse == ACCUSE_A) {
610 aop = op->aop = sym->aop = newAsmop(AOP_ACC);
611 aop->size = getSize(sym->type);
612 for ( i = 0 ; i < 2 ; i++ )
613 aop->aopu.aop_str[i] = accUse[i];
615 else if (sym->accuse == ACCUSE_HL) {
617 aop = op->aop = sym->aop = newAsmop(AOP_HLREG);
618 aop->size = getSize(sym->type);
619 for ( i = 0 ; i < 2 ; i++ )
620 aop->aopu.aop_str[i] = hlUse[i];
629 aop = op->aop = sym->aop = newAsmop(AOP_STR);
630 aop->size = getSize(sym->type);
631 for ( i = 0 ; i < 4 ; i++ )
632 aop->aopu.aop_str[i] = _fReturn[i];
636 /* else spill location */
637 sym->aop = op->aop = aop =
638 aopForSym(ic,sym->usl.spillLoc,result, requires_a);
639 aop->size = getSize(sym->type);
643 /* must be in a register */
644 sym->aop = op->aop = aop = newAsmop(AOP_REG);
645 aop->size = sym->nRegs;
646 for ( i = 0 ; i < sym->nRegs ;i++)
647 aop->aopu.aop_reg[i] = sym->regs[i];
650 /*-----------------------------------------------------------------*/
651 /* freeAsmop - free up the asmop given to an operand */
652 /*----------------------------------------------------------------*/
653 static void freeAsmop (operand *op, asmop *aaop, iCode *ic)
671 /* all other cases just dealloc */
675 OP_SYMBOL(op)->aop = NULL;
676 /* if the symbol has a spill */
678 SPIL_LOC(op)->aop = NULL;
683 bool isLitWord(asmop *aop)
685 /* if (aop->size != 2)
696 char *aopGetLitWordLong(asmop *aop, int offset, bool with_hash)
702 if (aop->size != 2 && aop->type != AOP_HL)
705 /* depending on type */
710 /* PENDING: for re-target */
712 tsprintf(s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
714 tsprintf(s, "%s + %d", aop->aopu.aop_immd, offset);
715 ALLOC_ATOMIC(rs,strlen(s)+1);
719 value * val = aop->aopu.aop_lit;
720 /* if it is a float then it gets tricky */
721 /* otherwise it is fairly simple */
722 if (!IS_FLOAT(val->type)) {
723 unsigned long v = floatFromVal(val);
727 tsprintf(buffer, "!immedword", v);
729 tsprintf(buffer, "!constword", v);
730 ALLOC_ATOMIC(rs,strlen(buffer)+1);
731 return strcpy (rs,buffer);
736 convertFloat(&f, floatFromVal(val));
738 tsprintf(buffer, "!immedword", f.w[offset/2]);
740 tsprintf(buffer, "!constword", f.w[offset/2]);
741 ALLOC_ATOMIC(rs,strlen(buffer)+1);
742 return strcpy (rs,buffer);
750 char *aopGetWord(asmop *aop, int offset)
752 return aopGetLitWordLong(aop, offset, TRUE);
755 bool isPtr(const char *s)
757 if (!strcmp(s, "hl"))
759 if (!strcmp(s, "ix"))
761 if (!strcmp(s, "iy"))
766 static void adjustPair(const char *pair, int *pold, int new)
770 while (*pold < new) {
771 emitcode("inc", "%s", pair);
774 while (*pold > new) {
775 emitcode("dec", "%s", pair);
780 static void spillPair(PAIR_ID pairId)
782 _G.pairs[pairId].last_type = AOP_INVALID;
783 _G.pairs[pairId].lit = NULL;
786 static void spillCached(void)
792 static bool requiresHL(asmop *aop)
803 static void fetchLitPair(PAIR_ID pairId, asmop *left, int offset)
806 const char *pair = _pairs[pairId].name;
807 l = aopGetLitWordLong(left, offset, FALSE);
811 if (pairId == PAIR_HL || pairId == PAIR_IY) {
812 if (_G.pairs[pairId].last_type == left->type) {
813 if (_G.pairs[pairId].lit && !strcmp(_G.pairs[pairId].lit, l)) {
814 if (pairId == PAIR_HL && abs(_G.pairs[pairId].offset - offset) < 3) {
815 adjustPair(pair, &_G.pairs[pairId].offset, offset);
818 if (pairId == PAIR_IY && abs(offset)<127) {
824 _G.pairs[pairId].last_type = left->type;
825 _G.pairs[pairId].lit = gc_strdup(l);
826 _G.pairs[pairId].offset = offset;
828 /* Both a lit on the right and a true symbol on the left */
829 /* PENDING: for re-target */
832 emit2("ld %s,!hashedstr + %d", pair, l, offset);
835 emit2("ld %s,!hashedstr", pair, l);
838 static void fetchPairLong(PAIR_ID pairId, asmop *aop, int offset)
840 /* if this is remateriazable */
841 if (isLitWord(aop)) {
842 fetchLitPair(pairId, aop, offset);
844 else { /* we need to get it byte by byte */
845 if (pairId == PAIR_HL && IS_GB && requiresHL(aop)) {
846 aopGet(aop, offset, FALSE);
850 emit2("ld h,!immedbyte", 0);
858 emit2("; WARNING: mlh woosed out. This code is invalid.");
861 else if (IS_Z80 && aop->type == AOP_IY) {
862 /* Instead of fetching relative to IY, just grab directly
863 from the address IY refers to */
864 char *l = aopGetLitWordLong(aop, offset, FALSE);
866 emit2("ld %s,(%s)", _pairs[pairId].name, l);
869 emitcode("ld", "%s,%s", _pairs[pairId].l, aopGet(aop, offset, FALSE));
870 emitcode("ld", "%s,%s", _pairs[pairId].h, aopGet(aop, offset+1, FALSE));
872 /* PENDING: check? */
873 if (pairId == PAIR_HL)
878 static void fetchPair(PAIR_ID pairId, asmop *aop)
880 fetchPairLong(pairId, aop, 0);
883 static void fetchHL(asmop *aop)
885 fetchPair(PAIR_HL, aop);
888 static void setupPair(PAIR_ID pairId, asmop *aop, int offset)
890 assert(pairId == PAIR_HL || pairId == PAIR_IY);
894 fetchLitPair(pairId, aop, 0);
897 fetchLitPair(pairId, aop, offset);
898 _G.pairs[pairId].offset = offset;
901 /* Doesnt include _G.stack.pushed */
902 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
903 if (aop->aopu.aop_stk > 0) {
904 abso += _G.stack.param_offset;
906 assert(pairId == PAIR_HL);
907 /* In some cases we can still inc or dec hl */
908 if (_G.pairs[pairId].last_type == AOP_STK && abs(_G.pairs[pairId].offset - abso) < 3) {
909 adjustPair(_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
912 emit2("!ldahlsp", abso +_G.stack.pushed);
914 _G.pairs[pairId].offset = abso;
920 _G.pairs[pairId].last_type = aop->type;
923 static void emitLabel(int key)
925 emit2("!tlabeldef", key);
929 /*-----------------------------------------------------------------*/
930 /* aopGet - for fetching value of the aop */
931 /*-----------------------------------------------------------------*/
932 static char *aopGet(asmop *aop, int offset, bool bit16)
937 /* offset is greater than size then zero */
938 /* PENDING: this seems a bit screwed in some pointer cases. */
939 if (offset > (aop->size - 1) &&
940 aop->type != AOP_LIT)
943 /* depending on type */
946 /* PENDING: re-target */
948 tsprintf (s,"!immedwords", aop->aopu.aop_immd);
952 tsprintf(s, "!bankimmeds", aop->aopu.aop_immd);
955 tsprintf(s, "!msbimmeds", aop->aopu.aop_immd);
958 tsprintf(s, "!lsbimmeds", aop->aopu.aop_immd);
963 ALLOC_ATOMIC(rs,strlen(s)+1);
969 emitcode("ld", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
971 ALLOC_ATOMIC(rs,strlen(s)+1);
977 emitcode("ldh", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
979 ALLOC_ATOMIC(rs,strlen(s)+1);
984 return aop->aopu.aop_reg[offset]->name;
988 setupPair(PAIR_HL, aop, offset);
994 setupPair(PAIR_IY, aop, offset);
995 tsprintf(s,"!*iyx", offset);
996 ALLOC_ATOMIC(rs,strlen(s)+1);
1002 setupPair(PAIR_HL, aop, offset);
1003 tsprintf(s, "!*hl");
1006 tsprintf(s,"!*ixx", aop->aopu.aop_stk+offset);
1008 ALLOC_ATOMIC(rs,strlen(s)+1);
1022 wassert(offset < 2);
1023 return aop->aopu.aop_str[offset];
1026 return aopLiteral (aop->aopu.aop_lit,offset);
1030 return aop->aopu.aop_str[offset];
1034 wassertl(0, "aopget got unsupported aop->type");
1038 bool isRegString(const char *s)
1040 if (!strcmp(s, "b") ||
1051 bool isConstant(const char *s)
1053 /* This is a bit of a hack... */
1054 return (*s == '#' || *s == '$');
1057 bool canAssignToPtr(const char *s)
1066 /*-----------------------------------------------------------------*/
1067 /* aopPut - puts a string for a aop */
1068 /*-----------------------------------------------------------------*/
1069 static void aopPut (asmop *aop, const char *s, int offset)
1071 if (aop->size && offset > ( aop->size - 1)) {
1072 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1073 "aopPut got offset > aop->size");
1077 /* will assign value to value */
1078 /* depending on where it is ofcourse */
1079 switch (aop->type) {
1084 emitcode("ld", "a,%s", s);
1085 emitcode("ld", "(%s+%d),a", aop->aopu.aop_dir, offset);
1091 emitcode("ld", "a,%s", s);
1092 emitcode("ldh", "(%s+%d),a", aop->aopu.aop_dir, offset);
1096 if (!strcmp(s, "!*hl"))
1097 emit2("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1100 aop->aopu.aop_reg[offset]->name, s);
1105 setupPair(PAIR_IY, aop, offset);
1106 if (!canAssignToPtr(s)) {
1107 emit2("ld a,%s", s);
1108 emit2("ld !*iyx,a", offset);
1111 emit2("ld !*iyx,%s", offset, s);
1116 /* PENDING: for re-target */
1117 if (!strcmp(s, "!*hl") || !strcmp(s, "(hl)") || !strcmp(s, "[hl]")) {
1121 setupPair(PAIR_HL, aop, offset);
1123 emit2("ld !*hl,%s", s);
1128 /* PENDING: re-target */
1129 if (!strcmp(s, "!*hl") || !strcmp(s, "(hl)") || !strcmp(s, "[hl]")) {
1133 setupPair(PAIR_HL, aop, offset);
1134 if (!canAssignToPtr(s)) {
1135 emit2("ld a,%s", s);
1139 emit2("ld !*hl,%s", s);
1142 if (!canAssignToPtr(s)) {
1143 emit2("ld a,%s", s);
1144 emit2("ld !*ixx,a", aop->aopu.aop_stk+offset);
1147 emit2("ld !*ixx,%s", aop->aopu.aop_stk+offset, s);
1152 /* if bit variable */
1153 if (!aop->aopu.aop_dir) {
1157 /* In bit space but not in C - cant happen */
1164 if (strcmp(aop->aopu.aop_str[offset],s)) {
1165 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1171 if (!offset && (strcmp(s,"acc") == 0))
1175 emitcode("", "; Error aopPut AOP_ACC");
1178 if (strcmp(aop->aopu.aop_str[offset],s))
1179 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1184 wassert(offset < 2);
1185 emit2("ld %s,%s", aop->aopu.aop_str[offset], s);
1189 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1190 "aopPut got unsupported aop->type");
1195 #define AOP(op) op->aop
1196 #define AOP_TYPE(op) AOP(op)->type
1197 #define AOP_SIZE(op) AOP(op)->size
1198 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1200 static void commitPair(asmop *aop, PAIR_ID id)
1202 if (id == PAIR_HL && requiresHL(aop)) {
1205 aopPut(aop, "a", 0);
1206 aopPut(aop, "d", 1);
1209 aopPut(aop, _pairs[id].l, 0);
1210 aopPut(aop, _pairs[id].h, 1);
1214 /*-----------------------------------------------------------------*/
1215 /* getDataSize - get the operand data size */
1216 /*-----------------------------------------------------------------*/
1217 int getDataSize(operand *op)
1220 size = AOP_SIZE(op);
1228 /*-----------------------------------------------------------------*/
1229 /* movLeft2Result - move byte from left to result */
1230 /*-----------------------------------------------------------------*/
1231 static void movLeft2Result (operand *left, int offl,
1232 operand *result, int offr, int sign)
1235 if(!sameRegs(AOP(left),AOP(result)) || (offl != offr)){
1236 l = aopGet(AOP(left),offl,FALSE);
1239 aopPut(AOP(result),l,offr);
1248 /** Put Acc into a register set
1250 void outAcc(operand *result)
1253 size = getDataSize(result);
1255 aopPut(AOP(result),"a",0);
1258 /* unsigned or positive */
1260 aopPut(AOP(result), zero, offset++);
1265 /** Take the value in carry and put it into a register
1267 void outBitC(operand *result)
1269 /* if the result is bit */
1270 if (AOP_TYPE(result) == AOP_CRY) {
1271 emitcode("", "; Note: outBitC form 1");
1272 aopPut(AOP(result),"blah",0);
1275 emit2("ld a,!zero");
1281 /*-----------------------------------------------------------------*/
1282 /* toBoolean - emit code for orl a,operator(sizeop) */
1283 /*-----------------------------------------------------------------*/
1284 void toBoolean(operand *oper)
1286 int size = AOP_SIZE(oper);
1289 emitcode("ld", "a,%s", aopGet(AOP(oper), offset++, FALSE));
1292 emitcode("or","a,%s",aopGet(AOP(oper),offset++,FALSE));
1295 if (AOP(oper)->type != AOP_ACC) {
1297 emitcode("or","a,%s",aopGet(AOP(oper),0,FALSE));
1302 /*-----------------------------------------------------------------*/
1303 /* genNot - generate code for ! operation */
1304 /*-----------------------------------------------------------------*/
1305 static void genNot (iCode *ic)
1307 link *optype = operandType(IC_LEFT(ic));
1309 /* assign asmOps to operand & result */
1310 aopOp (IC_LEFT(ic),ic,FALSE, TRUE);
1311 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1313 /* if in bit space then a special case */
1314 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) {
1318 /* if type float then do float */
1319 if (IS_FLOAT(optype)) {
1323 toBoolean(IC_LEFT(ic));
1328 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1329 emit2("sub a,!one");
1330 outBitC(IC_RESULT(ic));
1332 /* release the aops */
1333 freeAsmop(IC_LEFT(ic),NULL,ic);
1334 freeAsmop(IC_RESULT(ic),NULL,ic);
1337 /*-----------------------------------------------------------------*/
1338 /* genCpl - generate code for complement */
1339 /*-----------------------------------------------------------------*/
1340 static void genCpl (iCode *ic)
1346 /* assign asmOps to operand & result */
1347 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
1348 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1350 /* if both are in bit space then
1352 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1353 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1357 size = AOP_SIZE(IC_RESULT(ic));
1359 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1362 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1365 /* release the aops */
1366 freeAsmop(IC_LEFT(ic),NULL,ic);
1367 freeAsmop(IC_RESULT(ic),NULL,ic);
1370 /*-----------------------------------------------------------------*/
1371 /* genUminus - unary minus code generation */
1372 /*-----------------------------------------------------------------*/
1373 static void genUminus (iCode *ic)
1376 link *optype, *rtype;
1379 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1380 aopOp(IC_RESULT(ic),ic,TRUE, FALSE);
1382 /* if both in bit space then special
1384 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1385 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1390 optype = operandType(IC_LEFT(ic));
1391 rtype = operandType(IC_RESULT(ic));
1393 /* if float then do float stuff */
1394 if (IS_FLOAT(optype)) {
1399 /* otherwise subtract from zero */
1400 size = AOP_SIZE(IC_LEFT(ic));
1404 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1405 emit2("ld a,!zero");
1406 emit2("sbc a,%s",l);
1407 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1410 /* if any remaining bytes in the result */
1411 /* we just need to propagate the sign */
1412 if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic))))) {
1416 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1420 /* release the aops */
1421 freeAsmop(IC_LEFT(ic),NULL,ic);
1422 freeAsmop(IC_RESULT(ic),NULL,ic);
1425 static void _push(PAIR_ID pairId)
1427 emit2("push %s", _pairs[pairId].name);
1428 _G.stack.pushed += 2;
1431 static void _pop(PAIR_ID pairId)
1433 emit2("pop %s", _pairs[pairId].name);
1434 _G.stack.pushed -= 2;
1438 /*-----------------------------------------------------------------*/
1439 /* assignResultValue - */
1440 /*-----------------------------------------------------------------*/
1441 void assignResultValue(operand * oper)
1443 int size = AOP_SIZE(oper);
1447 topInA = requiresHL(AOP(oper));
1453 if (IS_GB && size == 4 && requiresHL(AOP(oper))) {
1454 /* We do it the hard way here. */
1456 aopPut(AOP(oper), _fReturn[0], 0);
1457 aopPut(AOP(oper), _fReturn[1], 1);
1458 emitcode("pop", "de");
1459 _G.stack.pushed -= 2;
1460 aopPut(AOP(oper), _fReturn[0], 2);
1461 aopPut(AOP(oper), _fReturn[1], 3);
1465 aopPut(AOP(oper), _fReturn[size], size);
1470 /*-----------------------------------------------------------------*/
1471 /* genIpush - genrate code for pushing this gets a little complex */
1472 /*-----------------------------------------------------------------*/
1473 static void genIpush (iCode *ic)
1475 int size, offset = 0 ;
1478 /* if this is not a parm push : ie. it is spill push
1479 and spill push is always done on the local stack */
1480 if (!ic->parmPush) {
1481 /* and the item is spilt then do nothing */
1482 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1485 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1486 size = AOP_SIZE(IC_LEFT(ic));
1487 /* push it on the stack */
1488 if (isPair(AOP(IC_LEFT(ic)))) {
1489 emitcode("push", getPairName(AOP(IC_LEFT(ic))));
1490 _G.stack.pushed += 2;
1495 /* Simple for now - load into A and PUSH AF */
1496 if (AOP(IC_LEFT(ic))->type == AOP_IY) {
1497 char *l = aopGetLitWordLong(AOP(IC_LEFT(ic)), --offset, FALSE);
1499 emit2("ld a,(%s)", l);
1502 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1503 emit2("ld a,%s", l);
1513 /* Hmmm... what about saving the currently used registers
1516 /* then do the push */
1517 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1519 size = AOP_SIZE(IC_LEFT(ic));
1521 if (isPair(AOP(IC_LEFT(ic)))) {
1523 emitcode("push", "%s", getPairName(AOP(IC_LEFT(ic))));
1527 fetchHL(AOP(IC_LEFT(ic)));
1528 emitcode("push", "hl");
1530 _G.stack.pushed += 2;
1534 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
1535 emitcode("push", "hl");
1537 _G.stack.pushed += 2;
1538 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 0);
1539 emitcode("push", "hl");
1541 _G.stack.pushed += 2;
1546 if (AOP(IC_LEFT(ic))->type == AOP_IY) {
1547 char *l = aopGetLitWordLong(AOP(IC_LEFT(ic)), --offset, FALSE);
1549 emit2("ld a,(%s)", l);
1552 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1553 emit2("ld a,%s", l);
1555 emitcode("push", "af");
1556 emitcode("inc", "sp");
1561 freeAsmop(IC_LEFT(ic),NULL,ic);
1564 /*-----------------------------------------------------------------*/
1565 /* genIpop - recover the registers: can happen only for spilling */
1566 /*-----------------------------------------------------------------*/
1567 static void genIpop (iCode *ic)
1572 /* if the temp was not pushed then */
1573 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1576 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1577 size = AOP_SIZE(IC_LEFT(ic));
1579 if (isPair(AOP(IC_LEFT(ic)))) {
1580 emitcode("pop", getPairName(AOP(IC_LEFT(ic))));
1584 emitcode("dec", "sp");
1585 emitcode("pop", "hl");
1587 aopPut(AOP(IC_LEFT(ic)), "l", offset--);
1591 freeAsmop(IC_LEFT(ic),NULL,ic);
1594 static int _isPairUsed(iCode *ic, PAIR_ID pairId)
1599 if (bitVectBitValue(ic->rUsed, D_IDX))
1601 if (bitVectBitValue(ic->rUsed, E_IDX))
1610 static int _opUsesPair(operand *op, iCode *ic, PAIR_ID pairId)
1614 symbol *sym = OP_SYMBOL(op);
1616 if (sym->isspilt || sym->nRegs == 0)
1619 aopOp(op, ic, FALSE, FALSE);
1622 if (aop->type == AOP_REG) {
1624 for (i=0; i < aop->size; i++) {
1625 if (pairId == PAIR_DE) {
1626 emit2("; name %s", aop->aopu.aop_reg[i]->name);
1627 if (!strcmp(aop->aopu.aop_reg[i]->name, "e"))
1629 if (!strcmp(aop->aopu.aop_reg[i]->name, "d"))
1638 freeAsmop(IC_LEFT(ic),NULL,ic);
1642 /* This is quite unfortunate */
1643 static void setArea(int inHome)
1645 static int lastArea = 0;
1647 if (lastArea != inHome) {
1649 const char *sz = port->mem.code_name;
1650 port->mem.code_name = "HOME";
1651 emit2("!area", CODE_NAME);
1652 port->mem.code_name = sz;
1655 emit2("!area", CODE_NAME);
1660 /** Emit the code for a call statement
1662 static void emitCall(iCode *ic, bool ispcall)
1665 link *detype = getSpec(operandType(IC_LEFT(ic)));
1667 if (IS_BANKED(detype))
1668 emit2("; call to a banked function");
1670 /* if caller saves & we have not saved then */
1671 if (!ic->regsSaved) {
1675 /* if send set is not empty then assign */
1679 int n = elementsInSet(sendSet);
1680 if (IS_Z80 && n == 2 && _isPairUsed(ic, PAIR_DE)) {
1681 /* Only push de if it is used and if it's not used
1682 in the return value */
1683 /* Panic if partly used */
1684 if (_opUsesPair(IC_RESULT(ic), ic, PAIR_DE) == 1) {
1685 emit2("; Warning: de crossover");
1687 else if (!_opUsesPair(IC_RESULT(ic), ic, PAIR_DE)) {
1694 if (IS_Z80 && n == 2 ) {
1695 /* Want to load HL first, then DE as HL may = DE */
1696 sic = setFirstItem(sendSet);
1697 sic = setNextItem(sendSet);
1698 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1699 fetchPair(PAIR_HL, AOP(IC_LEFT(sic)));
1701 freeAsmop (IC_LEFT(sic),NULL,sic);
1702 sic = setFirstItem(sendSet);
1703 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1704 fetchPair(PAIR_DE, AOP(IC_LEFT(sic)));
1706 freeAsmop (IC_LEFT(sic),NULL,sic);
1709 for (sic = setFirstItem(sendSet) ; sic ;
1710 sic = setNextItem(sendSet)) {
1712 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1713 size = AOP_SIZE(IC_LEFT(sic));
1715 /* Always send in pairs */
1718 if (IS_Z80 && n == 1)
1719 fetchPair(PAIR_HL, AOP(IC_LEFT(sic)));
1721 fetchPair(PAIR_DE, AOP(IC_LEFT(sic)));
1724 fetchPair(PAIR_HL, AOP(IC_LEFT(sic)));
1727 /* Send set too big */
1731 freeAsmop (IC_LEFT(sic),NULL,sic);
1740 if (IS_BANKED(detype)) {
1741 werror(W_INDIR_BANKED);
1743 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1745 if (isLitWord(AOP(IC_LEFT(ic)))) {
1746 emitcode("", "; Special case where the pCall is to a constant");
1747 emitcode("call", aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE));
1750 symbol *rlbl = newiTempLabel(NULL);
1752 emit2("ld hl,!immed!tlabel", (rlbl->key+100));
1753 emitcode("push", "hl");
1754 _G.stack.pushed += 2;
1756 fetchHL(AOP(IC_LEFT(ic)));
1758 emit2("!tlabeldef", (rlbl->key+100));
1759 _G.stack.pushed -= 2;
1761 freeAsmop(IC_LEFT(ic),NULL,ic);
1764 char *name = OP_SYMBOL(IC_LEFT(ic))->rname[0] ?
1765 OP_SYMBOL(IC_LEFT(ic))->rname :
1766 OP_SYMBOL(IC_LEFT(ic))->name;
1767 if (IS_BANKED(detype)) {
1768 emit2("call banked_call");
1769 emit2("!dws", name);
1770 emit2("!dw !bankimmeds", name);
1774 emit2("call %s", name);
1779 /* if we need assign a result value */
1780 if ((IS_ITEMP(IC_RESULT(ic)) &&
1781 (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
1782 OP_SYMBOL(IC_RESULT(ic))->spildir )) ||
1783 IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
1786 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
1789 assignResultValue(IC_RESULT(ic));
1791 freeAsmop(IC_RESULT(ic),NULL, ic);
1794 /* adjust the stack for parameters if required */
1795 if (IC_LEFT(ic)->parmBytes) {
1796 int i = IC_LEFT(ic)->parmBytes;
1797 _G.stack.pushed -= i;
1799 emit2("!ldaspsp", i);
1804 emitcode("ld", "hl,#%d", i);
1805 emitcode("add", "hl,sp");
1806 emitcode("ld", "sp,hl");
1810 emitcode("pop", "hl");
1814 emitcode("inc", "sp");
1823 /*-----------------------------------------------------------------*/
1824 /* genCall - generates a call statement */
1825 /*-----------------------------------------------------------------*/
1826 static void genCall (iCode *ic)
1828 link *detype = getSpec(operandType(IC_LEFT(ic)));
1829 emitCall(ic, FALSE);
1832 /*-----------------------------------------------------------------*/
1833 /* genPcall - generates a call by pointer statement */
1834 /*-----------------------------------------------------------------*/
1835 static void genPcall (iCode *ic)
1840 /*-----------------------------------------------------------------*/
1841 /* resultRemat - result is rematerializable */
1842 /*-----------------------------------------------------------------*/
1843 static int resultRemat (iCode *ic)
1845 if (SKIP_IC(ic) || ic->op == IFX)
1848 if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
1849 symbol *sym = OP_SYMBOL(IC_RESULT(ic));
1850 if (sym->remat && !POINTER_SET(ic))
1857 /*-----------------------------------------------------------------*/
1858 /* genFunction - generated code for function entry */
1859 /*-----------------------------------------------------------------*/
1860 static void genFunction (iCode *ic)
1862 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1866 setArea(IS_NONBANKED(sym->etype));
1868 /* create the function header */
1869 emit2("!functionheader", sym->name);
1870 /* PENDING: portability. */
1871 emit2("__%s_start:", sym->rname);
1872 emit2("!functionlabeldef", sym->rname);
1874 fetype = getSpec(operandType(IC_LEFT(ic)));
1876 /* if critical function then turn interrupts off */
1877 if (SPEC_CRTCL(fetype))
1880 /* if this is an interrupt service routine then
1881 save acc, b, dpl, dph */
1882 if (IS_ISR(sym->etype)) {
1885 /* PENDING: callee-save etc */
1887 /* If BC or DE are used, then push */
1888 _G.stack.pushed_bc = 0;
1889 _G.stack.pushed_de = 0;
1890 _G.stack.param_offset = 0;
1891 if (sym->regsUsed) {
1893 for ( i = 0 ; i < sym->regsUsed->size ; i++) {
1894 if (bitVectBitValue(sym->regsUsed, i)) {
1898 _G.stack.pushed_bc = 1;
1903 _G.stack.pushed_de = 1;
1908 if (_G.stack.pushed_bc) {
1910 _G.stack.param_offset += 2;
1912 if (_G.stack.pushed_de) {
1914 _G.stack.param_offset += 2;
1918 /* adjust the stack for the function */
1919 _G.stack.last = sym->stack;
1922 emit2("!enterx", sym->stack);
1925 _G.stack.offset = sym->stack;
1928 /*-----------------------------------------------------------------*/
1929 /* genEndFunction - generates epilogue for functions */
1930 /*-----------------------------------------------------------------*/
1931 static void genEndFunction (iCode *ic)
1933 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1935 if (IS_ISR(sym->etype)) {
1939 if (SPEC_CRTCL(sym->etype))
1942 /* PENDING: calleeSave */
1944 /* if debug then send end of function */
1945 if (options.debug && currFunc) {
1947 emitcode("","C$%s$%d$%d$%d ==.",
1948 ic->filename,currFunc->lastLine,
1949 ic->level,ic->block);
1950 if (IS_STATIC(currFunc->etype))
1951 emitcode("","XF%s$%s$0$0 ==.",moduleName,currFunc->name);
1953 emitcode("","XG$%s$0$0 ==.",currFunc->name);
1956 if (_G.stack.offset)
1957 emit2("!leavex", _G.stack.offset);
1961 if (_G.stack.pushed_de)
1963 if (_G.stack.pushed_bc)
1965 /* Both baned and non-banked just ret */
1968 /* PENDING: portability. */
1969 emit2("__%s_end:", sym->rname);
1971 _G.stack.pushed = 0;
1972 _G.stack.offset = 0;
1975 /*-----------------------------------------------------------------*/
1976 /* genRet - generate code for return statement */
1977 /*-----------------------------------------------------------------*/
1978 static void genRet (iCode *ic)
1981 /* Errk. This is a hack until I can figure out how
1982 to cause dehl to spill on a call */
1983 int size,offset = 0;
1985 /* if we have no return value then
1986 just generate the "ret" */
1990 /* we have something to return then
1991 move the return value into place */
1992 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1993 size = AOP_SIZE(IC_LEFT(ic));
1995 if ((size == 2) && ((l = aopGetWord(AOP(IC_LEFT(ic)), 0)))) {
1997 emitcode("ld", "de,%s", l);
2000 emitcode("ld", "hl,%s", l);
2004 if (IS_GB && size == 4 && requiresHL(AOP(IC_LEFT(ic)))) {
2005 fetchPair(PAIR_DE, AOP(IC_LEFT(ic)));
2006 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
2010 l = aopGet(AOP(IC_LEFT(ic)),offset,
2012 if (strcmp(_fReturn[offset],l))
2013 emitcode("ld","%s,%s", _fReturn[offset++],l);
2017 freeAsmop (IC_LEFT(ic),NULL,ic);
2020 /* generate a jump to the return label
2021 if the next is not the return statement */
2022 if (!(ic->next && ic->next->op == LABEL &&
2023 IC_LABEL(ic->next) == returnLabel))
2025 emit2("jp !tlabel", returnLabel->key+100);
2028 /*-----------------------------------------------------------------*/
2029 /* genLabel - generates a label */
2030 /*-----------------------------------------------------------------*/
2031 static void genLabel (iCode *ic)
2033 /* special case never generate */
2034 if (IC_LABEL(ic) == entryLabel)
2037 emitLabel(IC_LABEL(ic)->key+100);
2040 /*-----------------------------------------------------------------*/
2041 /* genGoto - generates a ljmp */
2042 /*-----------------------------------------------------------------*/
2043 static void genGoto (iCode *ic)
2045 emit2("jp !tlabel", IC_LABEL(ic)->key+100);
2048 /*-----------------------------------------------------------------*/
2049 /* genPlusIncr :- does addition with increment if possible */
2050 /*-----------------------------------------------------------------*/
2051 static bool genPlusIncr (iCode *ic)
2053 unsigned int icount ;
2054 unsigned int size = getDataSize(IC_RESULT(ic));
2055 PAIR_ID resultId = getPairId(AOP(IC_RESULT(ic)));
2057 /* will try to generate an increment */
2058 /* if the right side is not a literal
2060 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
2063 emitcode("", "; genPlusIncr");
2065 icount = floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
2067 /* If result is a pair */
2068 if (resultId != PAIR_INVALID) {
2069 if (isLitWord(AOP(IC_LEFT(ic)))) {
2070 fetchLitPair(getPairId(AOP(IC_RESULT(ic))), AOP(IC_LEFT(ic)), icount);
2073 if (isPair(AOP(IC_LEFT(ic))) && resultId == PAIR_HL && icount > 2) {
2074 fetchPair(resultId, AOP(IC_RIGHT(ic)));
2075 emitcode("add", "hl,%s", getPairName(AOP(IC_LEFT(ic))));
2081 if (!sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
2084 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
2085 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
2088 emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
2093 /* if the literal value of the right hand side
2094 is greater than 4 then it is not worth it */
2098 /* if increment 16 bits in register */
2099 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2104 symbol *tlbl = NULL;
2105 tlbl = newiTempLabel(NULL);
2107 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)), offset++, FALSE));
2109 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2112 emitLabel(tlbl->key+100);
2116 /* if the sizes are greater than 1 then we cannot */
2117 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2118 AOP_SIZE(IC_LEFT(ic)) > 1 )
2121 /* we can if the aops of the left & result match or
2122 if they are in registers and the registers are the
2124 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
2126 emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0, FALSE));
2133 /*-----------------------------------------------------------------*/
2134 /* outBitAcc - output a bit in acc */
2135 /*-----------------------------------------------------------------*/
2136 void outBitAcc(operand *result)
2138 symbol *tlbl = newiTempLabel(NULL);
2139 /* if the result is a bit */
2140 if (AOP_TYPE(result) == AOP_CRY){
2144 emit2("!shortjp z,!tlabel", tlbl->key+100);
2146 emitLabel(tlbl->key+100);
2151 /*-----------------------------------------------------------------*/
2152 /* genPlus - generates code for addition */
2153 /*-----------------------------------------------------------------*/
2154 static void genPlus (iCode *ic)
2156 int size, offset = 0;
2158 /* special cases :- */
2160 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
2161 aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
2162 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
2164 /* Swap the left and right operands if:
2166 if literal, literal on the right or
2167 if left requires ACC or right is already
2170 if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
2171 (AOP_NEEDSACC(IC_LEFT(ic))) ||
2172 AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
2173 operand *t = IC_RIGHT(ic);
2174 IC_RIGHT(ic) = IC_LEFT(ic);
2178 /* if both left & right are in bit
2180 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2181 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2186 /* if left in bit space & right literal */
2187 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2188 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
2189 /* Can happen I guess */
2193 /* if I can do an increment instead
2194 of add then GOOD for ME */
2195 if (genPlusIncr (ic) == TRUE)
2198 emit2("; genPlusIncr failed");
2200 size = getDataSize(IC_RESULT(ic));
2202 /* Special case when left and right are constant */
2203 if (isPair(AOP(IC_RESULT(ic)))) {
2206 left = aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE);
2207 right = aopGetLitWordLong(AOP(IC_RIGHT(ic)), 0, FALSE);
2208 if (left && right) {
2212 sprintf(buffer, "#(%s + %s)", left, right);
2213 emitcode("ld", "%s,%s", getPairName(AOP(IC_RESULT(ic))), buffer);
2218 if (isPair(AOP(IC_RIGHT(ic))) && getPairId(AOP(IC_RESULT(ic))) == PAIR_HL) {
2219 /* Fetch into HL then do the add */
2221 fetchPair(PAIR_HL, AOP(IC_LEFT(ic)));
2222 emitcode("add", "hl,%s", getPairName(AOP(IC_RIGHT(ic))));
2227 ld hl,sp+n trashes C so we cant afford to do it during an
2228 add with stack based varibles. Worst case is:
2241 So you cant afford to load up hl if either left, right, or result
2242 is on the stack (*sigh*) The alt is:
2250 Combinations in here are:
2251 * If left or right are in bc then the loss is small - trap later
2252 * If the result is in bc then the loss is also small
2255 if (AOP_TYPE(IC_LEFT(ic)) == AOP_STK ||
2256 AOP_TYPE(IC_RIGHT(ic)) == AOP_STK ||
2257 AOP_TYPE(IC_RESULT(ic)) == AOP_STK) {
2258 if ((AOP_SIZE(IC_LEFT(ic)) == 2 ||
2259 AOP_SIZE(IC_RIGHT(ic)) == 2) &&
2260 (AOP_SIZE(IC_LEFT(ic)) <= 2 &&
2261 AOP_SIZE(IC_RIGHT(ic)) <= 2)) {
2262 if (getPairId(AOP(IC_RIGHT(ic))) == PAIR_BC) {
2263 /* Swap left and right */
2264 operand *t = IC_RIGHT(ic);
2265 IC_RIGHT(ic) = IC_LEFT(ic);
2268 if (getPairId(AOP(IC_LEFT(ic))) == PAIR_BC) {
2269 fetchPair(PAIR_HL, AOP(IC_RIGHT(ic)));
2273 fetchPair(PAIR_DE, AOP(IC_LEFT(ic)));
2274 fetchPair(PAIR_HL, AOP(IC_RIGHT(ic)));
2277 commitPair(AOP(IC_RESULT(ic)), PAIR_HL);
2280 else if (size == 4) {
2281 emit2("; WARNING: This add is probably broken.\n");
2287 if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
2288 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2291 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2294 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2296 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2299 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2302 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2304 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2308 freeAsmop(IC_LEFT(ic),NULL,ic);
2309 freeAsmop(IC_RIGHT(ic),NULL,ic);
2310 freeAsmop(IC_RESULT(ic),NULL,ic);
2314 /*-----------------------------------------------------------------*/
2315 /* genMinusDec :- does subtraction with deccrement if possible */
2316 /*-----------------------------------------------------------------*/
2317 static bool genMinusDec (iCode *ic)
2319 unsigned int icount ;
2320 unsigned int size = getDataSize(IC_RESULT(ic));
2322 /* will try to generate an increment */
2323 /* if the right side is not a literal we cannot */
2324 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
2327 /* if the literal value of the right hand side
2328 is greater than 4 then it is not worth it */
2329 if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
2332 size = getDataSize(IC_RESULT(ic));
2335 /* if increment 16 bits in register */
2336 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2339 symbol *tlbl = newiTempLabel(NULL);
2340 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
2341 emitcode("jp", "np," LABEL_STR ,tlbl->key+100);
2343 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
2347 emitLabel(tlbl->key+100);
2352 /* if decrement 16 bits in register */
2353 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2354 (size > 1) && isPair(AOP(IC_RESULT(ic)))) {
2356 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2360 /* If result is a pair */
2361 if (isPair(AOP(IC_RESULT(ic)))) {
2362 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
2363 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
2365 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2369 /* if the sizes are greater than 1 then we cannot */
2370 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2371 AOP_SIZE(IC_LEFT(ic)) > 1 )
2374 /* we can if the aops of the left & result match or if they are in
2375 registers and the registers are the same */
2376 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
2378 emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE));
2385 /*-----------------------------------------------------------------*/
2386 /* genMinus - generates code for subtraction */
2387 /*-----------------------------------------------------------------*/
2388 static void genMinus (iCode *ic)
2390 int size, offset = 0;
2391 unsigned long lit = 0L;
2393 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
2394 aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
2395 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
2397 /* special cases :- */
2398 /* if both left & right are in bit space */
2399 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2400 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2405 /* if I can do an decrement instead of subtract then GOOD for ME */
2406 if (genMinusDec (ic) == TRUE)
2409 size = getDataSize(IC_RESULT(ic));
2411 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
2414 lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
2418 /* Same logic as genPlus */
2420 if (AOP_TYPE(IC_LEFT(ic)) == AOP_STK ||
2421 AOP_TYPE(IC_RIGHT(ic)) == AOP_STK ||
2422 AOP_TYPE(IC_RESULT(ic)) == AOP_STK) {
2423 if ((AOP_SIZE(IC_LEFT(ic)) == 2 ||
2424 AOP_SIZE(IC_RIGHT(ic)) == 2) &&
2425 (AOP_SIZE(IC_LEFT(ic)) <= 2 &&
2426 AOP_SIZE(IC_RIGHT(ic)) <= 2)) {
2427 PAIR_ID left = getPairId(AOP(IC_LEFT(ic)));
2428 PAIR_ID right = getPairId(AOP(IC_RIGHT(ic)));
2430 if (left == PAIR_INVALID && right == PAIR_INVALID) {
2434 else if (right == PAIR_INVALID)
2436 else if (left == PAIR_INVALID)
2439 fetchPair(left, AOP(IC_LEFT(ic)));
2440 /* Order is important. Right may be HL */
2441 fetchPair(right, AOP(IC_RIGHT(ic)));
2443 emit2("ld a,%s", _pairs[left].l);
2444 emit2("sub a,%s", _pairs[right].l);
2446 emit2("ld a,%s", _pairs[left].h);
2447 emit2("sbc a,%s", _pairs[right].h);
2449 aopPut(AOP(IC_RESULT(ic)), "a", 1);
2450 aopPut(AOP(IC_RESULT(ic)), "e", 0);
2453 else if (size == 4) {
2454 emit2("; WARNING: This sub is probably broken.\n");
2459 /* if literal, add a,#-lit, else normal subb */
2461 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2462 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) {
2464 emitcode("sub","a,%s",
2465 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2467 emitcode("sbc","a,%s",
2468 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2471 /* first add without previous c */
2473 emit2("add a,!immedbyte", (unsigned int)(lit & 0x0FFL));
2475 emit2("adc a,!immedbyte", (unsigned int)((lit >> (offset*8)) & 0x0FFL));
2477 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2480 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2481 AOP_SIZE(IC_LEFT(ic)) == 3 &&
2482 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2486 freeAsmop(IC_LEFT(ic),NULL,ic);
2487 freeAsmop(IC_RIGHT(ic),NULL,ic);
2488 freeAsmop(IC_RESULT(ic),NULL,ic);
2491 /*-----------------------------------------------------------------*/
2492 /* genMult - generates code for multiplication */
2493 /*-----------------------------------------------------------------*/
2494 static void genMult (iCode *ic)
2496 /* Shouldn't occur - all done through function calls */
2500 /*-----------------------------------------------------------------*/
2501 /* genDiv - generates code for division */
2502 /*-----------------------------------------------------------------*/
2503 static void genDiv (iCode *ic)
2505 /* Shouldn't occur - all done through function calls */
2509 /*-----------------------------------------------------------------*/
2510 /* genMod - generates code for division */
2511 /*-----------------------------------------------------------------*/
2512 static void genMod (iCode *ic)
2514 /* Shouldn't occur - all done through function calls */
2518 /*-----------------------------------------------------------------*/
2519 /* genIfxJump :- will create a jump depending on the ifx */
2520 /*-----------------------------------------------------------------*/
2521 static void genIfxJump (iCode *ic, char *jval)
2526 /* if true label then we jump if condition
2528 if ( IC_TRUE(ic) ) {
2530 if (!strcmp(jval, "a")) {
2533 else if (!strcmp(jval, "c")) {
2537 /* The buffer contains the bit on A that we should test */
2542 /* false label is present */
2543 jlbl = IC_FALSE(ic) ;
2544 if (!strcmp(jval, "a")) {
2547 else if (!strcmp(jval, "c")) {
2551 /* The buffer contains the bit on A that we should test */
2555 /* Z80 can do a conditional long jump */
2556 if (!strcmp(jval, "a")) {
2557 emitcode("or", "a,a");
2559 else if (!strcmp(jval, "c")) {
2562 emitcode("bit", "%s,a", jval);
2564 emit2("jp %s,!tlabel", inst, jlbl->key+100);
2566 /* mark the icode as generated */
2570 /** Generic compare for > or <
2572 static void genCmp (operand *left,operand *right,
2573 operand *result, iCode *ifx, int sign)
2575 int size, offset = 0 ;
2576 unsigned long lit = 0L;
2578 /* if left & right are bit variables */
2579 if (AOP_TYPE(left) == AOP_CRY &&
2580 AOP_TYPE(right) == AOP_CRY ) {
2581 /* Cant happen on the Z80 */
2584 /* subtract right from left if at the
2585 end the carry flag is set then we know that
2586 left is greater than right */
2587 size = max(AOP_SIZE(left),AOP_SIZE(right));
2589 /* if unsigned char cmp with lit, just compare */
2591 (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
2592 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2594 emit2("xor a,!immedbyte", 0x80);
2595 emit2("cp %s^!constbyte", aopGet(AOP(right), offset, FALSE), 0x80);
2598 emitcode("cp", "%s", aopGet(AOP(right), offset, FALSE));
2601 if(AOP_TYPE(right) == AOP_LIT) {
2602 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2603 /* optimize if(x < 0) or if(x >= 0) */
2606 /* No sign so it's always false */
2610 /* Just load in the top most bit */
2611 MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE));
2612 if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx) {
2613 genIfxJump (ifx,"7");
2617 emitcode("rlc","a");
2623 /* First setup h and l contaning the top most bytes XORed */
2624 bool fDidXor = FALSE;
2625 if (AOP_TYPE(left) == AOP_LIT){
2626 unsigned long lit = (unsigned long)
2627 floatFromVal(AOP(left)->aopu.aop_lit);
2628 emit2("ld %s,!immedbyte", _fTmp[0],
2629 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2632 emitcode("ld", "a,%s", aopGet(AOP(left), size-1, FALSE));
2633 emit2("xor a,!immedbyte", 0x80);
2634 emitcode("ld", "%s,a", _fTmp[0]);
2637 if (AOP_TYPE(right) == AOP_LIT) {
2638 unsigned long lit = (unsigned long)
2639 floatFromVal(AOP(right)->aopu.aop_lit);
2640 emit2("ld %s,!immedbyte", _fTmp[1],
2641 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2644 emitcode("ld", "a,%s", aopGet(AOP(right), size-1, FALSE));
2645 emit2("xor a,!immedbyte", 0x80);
2646 emitcode("ld", "%s,a", _fTmp[1]);
2656 /* Do a long subtract */
2657 if (!sign || size ) {
2658 MOVA(aopGet(AOP(left),offset,FALSE));
2660 if (sign && size == 0) {
2661 emitcode("ld", "a,%s", _fTmp[0]);
2662 emitcode("sbc", "a,%s", _fTmp[1]);
2665 /* Subtract through, propagating the carry */
2666 emitcode("sbc","a,%s ; 2",aopGet(AOP(right),offset++,FALSE));
2673 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2676 /* if the result is used in the next
2677 ifx conditional branch then generate
2678 code a little differently */
2680 genIfxJump (ifx,"c");
2683 /* leave the result in acc */
2687 /*-----------------------------------------------------------------*/
2688 /* genCmpGt :- greater than comparison */
2689 /*-----------------------------------------------------------------*/
2690 static void genCmpGt (iCode *ic, iCode *ifx)
2692 operand *left, *right, *result;
2693 link *letype , *retype;
2697 right= IC_RIGHT(ic);
2698 result = IC_RESULT(ic);
2700 letype = getSpec(operandType(left));
2701 retype =getSpec(operandType(right));
2702 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2703 /* assign the amsops */
2704 aopOp (left,ic,FALSE, FALSE);
2705 aopOp (right,ic,FALSE, FALSE);
2706 aopOp (result,ic,TRUE, FALSE);
2708 genCmp(right, left, result, ifx, sign);
2710 freeAsmop(left,NULL,ic);
2711 freeAsmop(right,NULL,ic);
2712 freeAsmop(result,NULL,ic);
2715 /*-----------------------------------------------------------------*/
2716 /* genCmpLt - less than comparisons */
2717 /*-----------------------------------------------------------------*/
2718 static void genCmpLt (iCode *ic, iCode *ifx)
2720 operand *left, *right, *result;
2721 link *letype , *retype;
2725 right= IC_RIGHT(ic);
2726 result = IC_RESULT(ic);
2728 letype = getSpec(operandType(left));
2729 retype =getSpec(operandType(right));
2730 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2732 /* assign the amsops */
2733 aopOp (left,ic,FALSE, FALSE);
2734 aopOp (right,ic,FALSE, FALSE);
2735 aopOp (result,ic,TRUE, FALSE);
2737 genCmp(left, right, result, ifx, sign);
2739 freeAsmop(left,NULL,ic);
2740 freeAsmop(right,NULL,ic);
2741 freeAsmop(result,NULL,ic);
2744 /*-----------------------------------------------------------------*/
2745 /* gencjneshort - compare and jump if not equal */
2746 /*-----------------------------------------------------------------*/
2747 static void gencjneshort(operand *left, operand *right, symbol *lbl)
2749 int size = max(AOP_SIZE(left),AOP_SIZE(right));
2751 unsigned long lit = 0L;
2753 /* Swap the left and right if it makes the computation easier */
2754 if (AOP_TYPE(left) == AOP_LIT) {
2760 if(AOP_TYPE(right) == AOP_LIT)
2761 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2763 /* if the right side is a literal then anything goes */
2764 if (AOP_TYPE(right) == AOP_LIT &&
2765 AOP_TYPE(left) != AOP_DIR ) {
2767 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2772 emitcode("or", "a,%s", aopGet(AOP(left), offset, FALSE));
2776 emitcode("or", "a,a");
2778 emit2("jp nz,!tlabel", lbl->key+100);
2782 emitcode("ld", "a,%s ; 2", aopGet(AOP(left),offset,FALSE));
2783 if ((AOP_TYPE(right) == AOP_LIT) && lit == 0)
2784 emitcode("or", "a,a");
2786 emitcode("cp", "a,%s", aopGet(AOP(right),offset,FALSE));
2787 emit2("jp nz,!tlabel", lbl->key+100);
2792 /* if the right side is in a register or in direct space or
2793 if the left is a pointer register & right is not */
2794 else if (AOP_TYPE(right) == AOP_REG ||
2795 AOP_TYPE(right) == AOP_DIR ||
2796 (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT)) {
2798 MOVA(aopGet(AOP(left),offset,FALSE));
2799 if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
2800 ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
2802 emit2("jp nz,!tlabel", lbl->key+100);
2804 emitcode("cp", "%s ; 4", aopGet(AOP(right),offset,FALSE));
2805 emit2("jp nz,!tlabel", lbl->key+100);
2810 /* right is a pointer reg need both a & b */
2811 /* PENDING: is this required? */
2813 MOVA(aopGet(AOP(right),offset,FALSE));
2814 emitcode("cp", "%s ; 5", aopGet(AOP(left), offset, FALSE));
2815 emit2("!shortjp nz,!tlabel", lbl->key+100);
2821 /*-----------------------------------------------------------------*/
2822 /* gencjne - compare and jump if not equal */
2823 /*-----------------------------------------------------------------*/
2824 static void gencjne(operand *left, operand *right, symbol *lbl)
2826 symbol *tlbl = newiTempLabel(NULL);
2828 gencjneshort(left, right, lbl);
2832 emit2("!shortjp !tlabel", tlbl->key+100);
2833 emitLabel(lbl->key+100);
2834 emitcode("xor","a,a");
2835 emitLabel(tlbl->key+100);
2838 /*-----------------------------------------------------------------*/
2839 /* genCmpEq - generates code for equal to */
2840 /*-----------------------------------------------------------------*/
2841 static void genCmpEq (iCode *ic, iCode *ifx)
2843 operand *left, *right, *result;
2845 aopOp((left=IC_LEFT(ic)),ic,FALSE, FALSE);
2846 aopOp((right=IC_RIGHT(ic)),ic,FALSE, FALSE);
2847 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2849 /* Swap operands if it makes the operation easier. ie if:
2850 1. Left is a literal.
2852 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
2853 operand *t = IC_RIGHT(ic);
2854 IC_RIGHT(ic) = IC_LEFT(ic);
2858 if (ifx && !AOP_SIZE(result)){
2860 /* if they are both bit variables */
2861 if (AOP_TYPE(left) == AOP_CRY &&
2862 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2865 tlbl = newiTempLabel(NULL);
2866 gencjneshort(left, right, tlbl);
2867 if ( IC_TRUE(ifx) ) {
2868 emit2("jp !tlabel", IC_TRUE(ifx)->key+100);
2869 emitLabel(tlbl->key+100);
2871 /* PENDING: do this better */
2872 symbol *lbl = newiTempLabel(NULL);
2873 emit2("!shortjp !tlabel", lbl->key+100);
2874 emitLabel(tlbl->key+100);
2875 emit2("jp !tlabel", IC_FALSE(ifx)->key+100);
2876 emitLabel(lbl->key+100);
2879 /* mark the icode as generated */
2884 /* if they are both bit variables */
2885 if (AOP_TYPE(left) == AOP_CRY &&
2886 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2889 gencjne(left,right,newiTempLabel(NULL));
2890 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2894 genIfxJump(ifx,"a");
2897 /* if the result is used in an arithmetic operation
2898 then put the result in place */
2899 if (AOP_TYPE(result) != AOP_CRY) {
2902 /* leave the result in acc */
2906 freeAsmop(left,NULL,ic);
2907 freeAsmop(right,NULL,ic);
2908 freeAsmop(result,NULL,ic);
2911 /*-----------------------------------------------------------------*/
2912 /* ifxForOp - returns the icode containing the ifx for operand */
2913 /*-----------------------------------------------------------------*/
2914 static iCode *ifxForOp ( operand *op, iCode *ic )
2916 /* if true symbol then needs to be assigned */
2917 if (IS_TRUE_SYMOP(op))
2920 /* if this has register type condition and
2921 the next instruction is ifx with the same operand
2922 and live to of the operand is upto the ifx only then */
2924 ic->next->op == IFX &&
2925 IC_COND(ic->next)->key == op->key &&
2926 OP_SYMBOL(op)->liveTo <= ic->next->seq )
2932 /*-----------------------------------------------------------------*/
2933 /* genAndOp - for && operation */
2934 /*-----------------------------------------------------------------*/
2935 static void genAndOp (iCode *ic)
2937 operand *left,*right, *result;
2940 /* note here that && operations that are in an if statement are
2941 taken away by backPatchLabels only those used in arthmetic
2942 operations remain */
2943 aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2944 aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2945 aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2947 /* if both are bit variables */
2948 if (AOP_TYPE(left) == AOP_CRY &&
2949 AOP_TYPE(right) == AOP_CRY ) {
2952 tlbl = newiTempLabel(NULL);
2954 emit2("!shortjp z,!tlabel", tlbl->key+100);
2956 emitLabel(tlbl->key+100);
2960 freeAsmop(left,NULL,ic);
2961 freeAsmop(right,NULL,ic);
2962 freeAsmop(result,NULL,ic);
2965 /*-----------------------------------------------------------------*/
2966 /* genOrOp - for || operation */
2967 /*-----------------------------------------------------------------*/
2968 static void genOrOp (iCode *ic)
2970 operand *left,*right, *result;
2973 /* note here that || operations that are in an
2974 if statement are taken away by backPatchLabels
2975 only those used in arthmetic operations remain */
2976 aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2977 aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2978 aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2980 /* if both are bit variables */
2981 if (AOP_TYPE(left) == AOP_CRY &&
2982 AOP_TYPE(right) == AOP_CRY ) {
2985 tlbl = newiTempLabel(NULL);
2987 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2989 emitLabel(tlbl->key+100);
2993 freeAsmop(left,NULL,ic);
2994 freeAsmop(right,NULL,ic);
2995 freeAsmop(result,NULL,ic);
2998 /*-----------------------------------------------------------------*/
2999 /* isLiteralBit - test if lit == 2^n */
3000 /*-----------------------------------------------------------------*/
3001 int isLiteralBit(unsigned long lit)
3003 unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
3004 0x100L,0x200L,0x400L,0x800L,
3005 0x1000L,0x2000L,0x4000L,0x8000L,
3006 0x10000L,0x20000L,0x40000L,0x80000L,
3007 0x100000L,0x200000L,0x400000L,0x800000L,
3008 0x1000000L,0x2000000L,0x4000000L,0x8000000L,
3009 0x10000000L,0x20000000L,0x40000000L,0x80000000L};
3012 for(idx = 0; idx < 32; idx++)
3018 /*-----------------------------------------------------------------*/
3019 /* jmpTrueOrFalse - */
3020 /*-----------------------------------------------------------------*/
3021 static void jmpTrueOrFalse (iCode *ic, symbol *tlbl)
3023 // ugly but optimized by peephole
3025 symbol *nlbl = newiTempLabel(NULL);
3026 emit2("jp !tlabel", nlbl->key+100);
3027 emitLabel(tlbl->key+100);
3028 emit2("jp !tlabel", IC_TRUE(ic)->key+100);
3029 emitLabel(nlbl->key+100);
3032 emit2("jp !tlabel", IC_FALSE(ic)->key+100);
3033 emitLabel(tlbl->key+100);
3038 /*-----------------------------------------------------------------*/
3039 /* genAnd - code for and */
3040 /*-----------------------------------------------------------------*/
3041 static void genAnd (iCode *ic, iCode *ifx)
3043 operand *left, *right, *result;
3045 unsigned long lit = 0L;
3048 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3049 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3050 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3053 emitcode("","; Type res[%d] = l[%d]&r[%d]",
3055 AOP_TYPE(left), AOP_TYPE(right));
3056 emitcode("","; Size res[%d] = l[%d]&r[%d]",
3058 AOP_SIZE(left), AOP_SIZE(right));
3061 /* if left is a literal & right is not then exchange them */
3062 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3063 AOP_NEEDSACC(left)) {
3064 operand *tmp = right ;
3069 /* if result = right then exchange them */
3070 if(sameRegs(AOP(result),AOP(right))){
3071 operand *tmp = right ;
3076 /* if right is bit then exchange them */
3077 if (AOP_TYPE(right) == AOP_CRY &&
3078 AOP_TYPE(left) != AOP_CRY){
3079 operand *tmp = right ;
3083 if(AOP_TYPE(right) == AOP_LIT)
3084 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3086 size = AOP_SIZE(result);
3088 if (AOP_TYPE(left) == AOP_CRY){
3093 // if(val & 0xZZ) - size = 0, ifx != FALSE -
3094 // bit = val & 0xZZ - size = 1, ifx = FALSE -
3095 if((AOP_TYPE(right) == AOP_LIT) &&
3096 (AOP_TYPE(result) == AOP_CRY) &&
3097 (AOP_TYPE(left) != AOP_CRY)) {
3098 int posbit = isLiteralBit(lit);
3102 MOVA(aopGet(AOP(left),posbit>>3,FALSE));
3106 emitcode("mov","c,acc.%d",posbit&0x07);
3111 sprintf(buffer, "%d", posbit&0x07);
3112 genIfxJump(ifx, buffer);
3120 symbol *tlbl = newiTempLabel(NULL);
3121 int sizel = AOP_SIZE(left);
3124 emitcode("setb","c");
3127 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
3128 MOVA( aopGet(AOP(left),offset,FALSE));
3130 if((posbit = isLiteralBit(bytelit)) != 0) {
3132 emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
3135 if(bytelit != 0x0FFL)
3136 emitcode("and","a,%s",
3137 aopGet(AOP(right),offset,FALSE));
3141 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3146 // bit = left & literal
3148 emitcode("clr","c");
3149 emit2("!tlabeldef", tlbl->key+100);
3151 // if(left & literal)
3154 jmpTrueOrFalse(ifx, tlbl);
3162 /* if left is same as result */
3163 if(sameRegs(AOP(result),AOP(left))){
3164 for(;size--; offset++) {
3165 if(AOP_TYPE(right) == AOP_LIT){
3166 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
3170 aopPut(AOP(result),zero,offset);
3172 MOVA(aopGet(AOP(left),offset,FALSE));
3173 emitcode("and","a,%s",
3174 aopGet(AOP(right),offset,FALSE));
3175 aopPut(AOP(left), "a", offset);
3180 if (AOP_TYPE(left) == AOP_ACC) {
3184 MOVA(aopGet(AOP(left),offset,FALSE));
3185 emitcode("and","a,%s",
3186 aopGet(AOP(right),offset,FALSE));
3187 aopPut(AOP(left), "a", offset);
3192 // left & result in different registers
3193 if(AOP_TYPE(result) == AOP_CRY){
3196 for(;(size--);offset++) {
3198 // result = left & right
3199 if(AOP_TYPE(right) == AOP_LIT){
3200 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
3202 aopGet(AOP(left),offset,FALSE),
3205 } else if(bytelit == 0){
3206 aopPut(AOP(result),zero,offset);
3210 // faster than result <- left, anl result,right
3211 // and better if result is SFR
3212 if (AOP_TYPE(left) == AOP_ACC)
3213 emitcode("and","a,%s",aopGet(AOP(right),offset,FALSE));
3215 MOVA(aopGet(AOP(left),offset,FALSE));
3216 emitcode("and","a,%s",
3217 aopGet(AOP(right),offset,FALSE));
3219 aopPut(AOP(result),"a",offset);
3226 freeAsmop(left,NULL,ic);
3227 freeAsmop(right,NULL,ic);
3228 freeAsmop(result,NULL,ic);
3231 /*-----------------------------------------------------------------*/
3232 /* genOr - code for or */
3233 /*-----------------------------------------------------------------*/
3234 static void genOr (iCode *ic, iCode *ifx)
3236 operand *left, *right, *result;
3238 unsigned long lit = 0L;
3240 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3241 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3242 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3245 emitcode("","; Type res[%d] = l[%d]&r[%d]",
3247 AOP_TYPE(left), AOP_TYPE(right));
3248 emitcode("","; Size res[%d] = l[%d]&r[%d]",
3250 AOP_SIZE(left), AOP_SIZE(right));
3253 /* if left is a literal & right is not then exchange them */
3254 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3255 AOP_NEEDSACC(left)) {
3256 operand *tmp = right ;
3261 /* if result = right then exchange them */
3262 if(sameRegs(AOP(result),AOP(right))){
3263 operand *tmp = right ;
3268 /* if right is bit then exchange them */
3269 if (AOP_TYPE(right) == AOP_CRY &&
3270 AOP_TYPE(left) != AOP_CRY){
3271 operand *tmp = right ;
3275 if(AOP_TYPE(right) == AOP_LIT)
3276 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3278 size = AOP_SIZE(result);
3280 if (AOP_TYPE(left) == AOP_CRY){
3285 if((AOP_TYPE(right) == AOP_LIT) &&
3286 (AOP_TYPE(result) == AOP_CRY) &&
3287 (AOP_TYPE(left) != AOP_CRY)){
3292 /* if left is same as result */
3293 if(sameRegs(AOP(result),AOP(left))){
3294 for(;size--; offset++) {
3295 if(AOP_TYPE(right) == AOP_LIT){
3296 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3299 MOVA(aopGet(AOP(left),offset,FALSE));
3300 emitcode("or","a,%s",
3301 aopGet(AOP(right),offset,FALSE));
3302 aopPut(AOP(result),"a", offset);
3305 if (AOP_TYPE(left) == AOP_ACC)
3306 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
3308 MOVA(aopGet(AOP(left),offset,FALSE));
3309 emitcode("or","a,%s",
3310 aopGet(AOP(right),offset,FALSE));
3311 aopPut(AOP(result),"a", offset);
3316 // left & result in different registers
3317 if(AOP_TYPE(result) == AOP_CRY){
3319 } else for(;(size--);offset++){
3321 // result = left & right
3322 if(AOP_TYPE(right) == AOP_LIT){
3323 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3325 aopGet(AOP(left),offset,FALSE),
3330 // faster than result <- left, anl result,right
3331 // and better if result is SFR
3332 if (AOP_TYPE(left) == AOP_ACC)
3333 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
3335 MOVA(aopGet(AOP(left),offset,FALSE));
3336 emitcode("or","a,%s",
3337 aopGet(AOP(right),offset,FALSE));
3339 aopPut(AOP(result),"a",offset);
3340 /* PENDING: something weird is going on here. Add exception. */
3341 if (AOP_TYPE(result) == AOP_ACC)
3347 freeAsmop(left,NULL,ic);
3348 freeAsmop(right,NULL,ic);
3349 freeAsmop(result,NULL,ic);
3352 /*-----------------------------------------------------------------*/
3353 /* genXor - code for xclusive or */
3354 /*-----------------------------------------------------------------*/
3355 static void genXor (iCode *ic, iCode *ifx)
3357 operand *left, *right, *result;
3359 unsigned long lit = 0L;
3361 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3362 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3363 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3365 /* if left is a literal & right is not then exchange them */
3366 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3367 AOP_NEEDSACC(left)) {
3368 operand *tmp = right ;
3373 /* if result = right then exchange them */
3374 if(sameRegs(AOP(result),AOP(right))){
3375 operand *tmp = right ;
3380 /* if right is bit then exchange them */
3381 if (AOP_TYPE(right) == AOP_CRY &&
3382 AOP_TYPE(left) != AOP_CRY){
3383 operand *tmp = right ;
3387 if(AOP_TYPE(right) == AOP_LIT)
3388 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3390 size = AOP_SIZE(result);
3392 if (AOP_TYPE(left) == AOP_CRY){
3397 if((AOP_TYPE(right) == AOP_LIT) &&
3398 (AOP_TYPE(result) == AOP_CRY) &&
3399 (AOP_TYPE(left) != AOP_CRY)){
3404 /* if left is same as result */
3405 if(sameRegs(AOP(result),AOP(left))){
3406 for(;size--; offset++) {
3407 if(AOP_TYPE(right) == AOP_LIT){
3408 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3411 MOVA(aopGet(AOP(right),offset,FALSE));
3412 emitcode("xor","a,%s",
3413 aopGet(AOP(left),offset,FALSE));
3414 aopPut(AOP(result),"a",0);
3417 if (AOP_TYPE(left) == AOP_ACC)
3418 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3420 MOVA(aopGet(AOP(right),offset,FALSE));
3421 emitcode("xor","a,%s",
3422 aopGet(AOP(left),offset,FALSE));
3423 aopPut(AOP(result),"a",0);
3428 // left & result in different registers
3429 if(AOP_TYPE(result) == AOP_CRY){
3431 } else for(;(size--);offset++){
3433 // result = left & right
3434 if(AOP_TYPE(right) == AOP_LIT){
3435 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3437 aopGet(AOP(left),offset,FALSE),
3442 // faster than result <- left, anl result,right
3443 // and better if result is SFR
3444 if (AOP_TYPE(left) == AOP_ACC)
3445 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3447 MOVA(aopGet(AOP(right),offset,FALSE));
3448 emitcode("xor","a,%s",
3449 aopGet(AOP(left),offset,FALSE));
3450 aopPut(AOP(result),"a",0);
3452 aopPut(AOP(result),"a",offset);
3457 freeAsmop(left,NULL,ic);
3458 freeAsmop(right,NULL,ic);
3459 freeAsmop(result,NULL,ic);
3462 /*-----------------------------------------------------------------*/
3463 /* genInline - write the inline code out */
3464 /*-----------------------------------------------------------------*/
3465 static void genInline (iCode *ic)
3467 char buffer[MAX_INLINEASM];
3471 inLine += (!options.asmpeep);
3472 strcpy(buffer,IC_INLINE(ic));
3474 /* emit each line as a code */
3493 /* emitcode("",buffer); */
3494 inLine -= (!options.asmpeep);
3497 /*-----------------------------------------------------------------*/
3498 /* genRRC - rotate right with carry */
3499 /*-----------------------------------------------------------------*/
3500 static void genRRC (iCode *ic)
3505 /*-----------------------------------------------------------------*/
3506 /* genRLC - generate code for rotate left with carry */
3507 /*-----------------------------------------------------------------*/
3508 static void genRLC (iCode *ic)
3513 /*-----------------------------------------------------------------*/
3514 /* shiftR2Left2Result - shift right two bytes from left to result */
3515 /*-----------------------------------------------------------------*/
3516 static void shiftR2Left2Result (operand *left, int offl,
3517 operand *result, int offr,
3518 int shCount, int sign)
3520 movLeft2Result(left, offl, result, offr, 0);
3521 movLeft2Result(left, offl+1, result, offr+1, 0);
3527 /* if (AOP(result)->type == AOP_REG) {*/
3530 symbol *tlbl , *tlbl1;
3533 tlbl = newiTempLabel(NULL);
3534 tlbl1 = newiTempLabel(NULL);
3536 /* Left is already in result - so now do the shift */
3538 emit2("ld a,!immedbyte+1", shCount);
3539 emit2("!shortjp !tlabel", tlbl1->key+100);
3540 emitLabel(tlbl->key+100);
3543 emitcode("or", "a,a");
3546 l = aopGet(AOP(result), --offset, FALSE);
3547 emitcode("rr","%s", l);
3550 emitLabel(tlbl1->key+100);
3551 emitcode("dec", "a");
3552 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3557 /*-----------------------------------------------------------------*/
3558 /* shiftL2Left2Result - shift left two bytes from left to result */
3559 /*-----------------------------------------------------------------*/
3560 static void shiftL2Left2Result (operand *left, int offl,
3561 operand *result, int offr, int shCount)
3563 if(sameRegs(AOP(result), AOP(left)) &&
3564 ((offl + MSB16) == offr)){
3567 /* Copy left into result */
3568 movLeft2Result(left, offl, result, offr, 0);
3569 movLeft2Result(left, offl+1, result, offr+1, 0);
3571 /* PENDING: for now just see if it'll work. */
3572 /*if (AOP(result)->type == AOP_REG) { */
3576 symbol *tlbl , *tlbl1;
3579 tlbl = newiTempLabel(NULL);
3580 tlbl1 = newiTempLabel(NULL);
3582 /* Left is already in result - so now do the shift */
3584 emit2("ld a,!immedbyte+1", shCount);
3585 emit2("!shortjp !tlabel", tlbl1->key+100);
3586 emitLabel(tlbl->key+100);
3589 emitcode("or", "a,a");
3591 l = aopGet(AOP(result),offset++,FALSE);
3592 emitcode("rl","%s", l);
3595 emitLabel(tlbl1->key+100);
3596 emitcode("dec", "a");
3597 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3602 /*-----------------------------------------------------------------*/
3603 /* AccRol - rotate left accumulator by known count */
3604 /*-----------------------------------------------------------------*/
3605 static void AccRol (int shCount)
3607 shCount &= 0x0007; // shCount : 0..7
3644 /*-----------------------------------------------------------------*/
3645 /* AccLsh - left shift accumulator by known count */
3646 /*-----------------------------------------------------------------*/
3647 static void AccLsh (int shCount)
3651 emitcode("add","a,a");
3653 else if(shCount == 2) {
3654 emitcode("add","a,a");
3655 emitcode("add","a,a");
3657 /* rotate left accumulator */
3659 /* and kill the lower order bits */
3660 emit2("and a,!immedbyte", SLMask[shCount]);
3665 /*-----------------------------------------------------------------*/
3666 /* shiftL1Left2Result - shift left one byte from left to result */
3667 /*-----------------------------------------------------------------*/
3668 static void shiftL1Left2Result (operand *left, int offl,
3669 operand *result, int offr, int shCount)
3672 l = aopGet(AOP(left),offl,FALSE);
3674 /* shift left accumulator */
3676 aopPut(AOP(result),"a",offr);
3680 /*-----------------------------------------------------------------*/
3681 /* genlshTwo - left shift two bytes by known amount != 0 */
3682 /*-----------------------------------------------------------------*/
3683 static void genlshTwo (operand *result,operand *left, int shCount)
3685 int size = AOP_SIZE(result);
3689 /* if shCount >= 8 */
3694 movLeft2Result(left, LSB, result, MSB16, 0);
3695 aopPut(AOP(result),zero, 0);
3696 shiftL1Left2Result(left, MSB16, result, MSB16, shCount);
3699 movLeft2Result(left, LSB, result, MSB16, 0);
3700 aopPut(AOP(result),zero, 0);
3704 aopPut(AOP(result),zero,LSB);
3707 /* 1 <= shCount <= 7 */
3713 shiftL2Left2Result(left, LSB, result, LSB, shCount);
3718 /*-----------------------------------------------------------------*/
3719 /* genlshOne - left shift a one byte quantity by known count */
3720 /*-----------------------------------------------------------------*/
3721 static void genlshOne (operand *result, operand *left, int shCount)
3723 shiftL1Left2Result(left, LSB, result, LSB, shCount);
3726 /*-----------------------------------------------------------------*/
3727 /* genLeftShiftLiteral - left shifting by known count */
3728 /*-----------------------------------------------------------------*/
3729 static void genLeftShiftLiteral (operand *left,
3734 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3737 freeAsmop(right,NULL,ic);
3739 aopOp(left,ic,FALSE, FALSE);
3740 aopOp(result,ic,FALSE, FALSE);
3742 size = getSize(operandType(result));
3745 emitcode("; shift left ","result %d, left %d",size,
3749 /* I suppose that the left size >= result size */
3754 else if(shCount >= (size * 8))
3756 aopPut(AOP(result),zero,size);
3760 genlshOne (result,left,shCount);
3763 genlshTwo (result,left,shCount);
3772 freeAsmop(left,NULL,ic);
3773 freeAsmop(result,NULL,ic);
3776 /*-----------------------------------------------------------------*/
3777 /* genLeftShift - generates code for left shifting */
3778 /*-----------------------------------------------------------------*/
3779 static void genLeftShift (iCode *ic)
3783 symbol *tlbl , *tlbl1;
3784 operand *left,*right, *result;
3786 right = IC_RIGHT(ic);
3788 result = IC_RESULT(ic);
3790 aopOp(right,ic,FALSE, FALSE);
3792 /* if the shift count is known then do it
3793 as efficiently as possible */
3794 if (AOP_TYPE(right) == AOP_LIT) {
3795 genLeftShiftLiteral (left,right,result,ic);
3799 /* shift count is unknown then we have to form a loop get the loop
3800 count in B : Note: we take only the lower order byte since
3801 shifting more that 32 bits make no sense anyway, ( the largest
3802 size of an object can be only 32 bits ) */
3803 emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE));
3804 emitcode("inc","a");
3805 freeAsmop (right,NULL,ic);
3806 aopOp(left,ic,FALSE, FALSE);
3807 aopOp(result,ic,FALSE, FALSE);
3809 /* now move the left to the result if they are not the
3812 if (!sameRegs(AOP(left),AOP(result))) {
3814 size = AOP_SIZE(result);
3817 l = aopGet(AOP(left),offset,FALSE);
3818 aopPut(AOP(result),l,offset);
3823 size = AOP_SIZE(result);
3826 l = aopGet(AOP(left),offset,FALSE);
3827 aopPut(AOP(result),l,offset);
3833 tlbl = newiTempLabel(NULL);
3834 size = AOP_SIZE(result);
3836 tlbl1 = newiTempLabel(NULL);
3838 emit2("!shortjp !tlabel", tlbl1->key+100);
3839 emitLabel(tlbl->key+100);
3840 l = aopGet(AOP(result),offset,FALSE);
3841 emitcode("or", "a,a");
3843 l = aopGet(AOP(result),offset++,FALSE);
3844 emitcode("rl","%s", l);
3846 emitLabel(tlbl1->key+100);
3847 emitcode("dec", "a");
3848 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3850 freeAsmop(left,NULL,ic);
3851 freeAsmop(result,NULL,ic);
3854 /*-----------------------------------------------------------------*/
3855 /* genrshOne - left shift two bytes by known amount != 0 */
3856 /*-----------------------------------------------------------------*/
3857 static void genrshOne (operand *result,operand *left, int shCount)
3860 int size = AOP_SIZE(result);
3866 l = aopGet(AOP(left),0,FALSE);
3867 if (AOP(result)->type == AOP_REG) {
3868 aopPut(AOP(result), l, 0);
3869 l = aopGet(AOP(result), 0, FALSE);
3871 emitcode("srl", "%s", l);
3876 emitcode("srl", "a");
3878 aopPut(AOP(result),"a",0);
3882 /*-----------------------------------------------------------------*/
3883 /* AccRsh - right shift accumulator by known count */
3884 /*-----------------------------------------------------------------*/
3885 static void AccRsh (int shCount)
3888 /* rotate right accumulator */
3889 AccRol(8 - shCount);
3890 /* and kill the higher order bits */
3891 emit2("and a,!immedbyte", SRMask[shCount]);
3895 /*-----------------------------------------------------------------*/
3896 /* shiftR1Left2Result - shift right one byte from left to result */
3897 /*-----------------------------------------------------------------*/
3898 static void shiftR1Left2Result (operand *left, int offl,
3899 operand *result, int offr,
3900 int shCount, int sign)
3902 MOVA(aopGet(AOP(left),offl,FALSE));
3909 aopPut(AOP(result),"a",offr);
3912 /*-----------------------------------------------------------------*/
3913 /* genrshTwo - right shift two bytes by known amount != 0 */
3914 /*-----------------------------------------------------------------*/
3915 static void genrshTwo (operand *result,operand *left,
3916 int shCount, int sign)
3918 /* if shCount >= 8 */
3922 shiftR1Left2Result(left, MSB16, result, LSB,
3926 movLeft2Result(left, MSB16, result, LSB, sign);
3928 aopPut(AOP(result),zero,1);
3930 /* 1 <= shCount <= 7 */
3932 shiftR2Left2Result(left, LSB, result, LSB, shCount, sign);
3936 /*-----------------------------------------------------------------*/
3937 /* genRightShiftLiteral - left shifting by known count */
3938 /*-----------------------------------------------------------------*/
3939 static void genRightShiftLiteral (operand *left,
3944 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3947 freeAsmop(right,NULL,ic);
3949 aopOp(left,ic,FALSE, FALSE);
3950 aopOp(result,ic,FALSE, FALSE);
3952 size = getSize(operandType(result));
3954 emitcode("; shift right ","result %d, left %d",size,
3957 /* I suppose that the left size >= result size */
3962 else if(shCount >= (size * 8))
3964 aopPut(AOP(result),zero,size);
3968 genrshOne(result, left, shCount);
3971 /* PENDING: sign support */
3972 genrshTwo(result, left, shCount, FALSE);
3981 freeAsmop(left,NULL,ic);
3982 freeAsmop(result,NULL,ic);
3985 /*-----------------------------------------------------------------*/
3986 /* genRightShift - generate code for right shifting */
3987 /*-----------------------------------------------------------------*/
3988 static void genRightShift (iCode *ic)
3990 operand *right, *left, *result;
3992 int size, offset, first = 1;
3996 symbol *tlbl, *tlbl1 ;
3998 /* if signed then we do it the hard way preserve the
3999 sign bit moving it inwards */
4000 retype = getSpec(operandType(IC_RESULT(ic)));
4002 is_signed = !SPEC_USIGN(retype);
4004 /* signed & unsigned types are treated the same : i.e. the
4005 signed is NOT propagated inwards : quoting from the
4006 ANSI - standard : "for E1 >> E2, is equivalent to division
4007 by 2**E2 if unsigned or if it has a non-negative value,
4008 otherwise the result is implementation defined ", MY definition
4009 is that the sign does not get propagated */
4011 right = IC_RIGHT(ic);
4013 result = IC_RESULT(ic);
4015 aopOp(right,ic,FALSE, FALSE);
4017 /* if the shift count is known then do it
4018 as efficiently as possible */
4019 if (AOP_TYPE(right) == AOP_LIT) {
4020 genRightShiftLiteral(left,right,result,ic);
4024 aopOp(left,ic,FALSE, FALSE);
4025 aopOp(result,ic,FALSE, FALSE);
4027 /* now move the left to the result if they are not the
4029 if (!sameRegs(AOP(left),AOP(result)) &&
4030 AOP_SIZE(result) > 1) {
4032 size = AOP_SIZE(result);
4035 l = aopGet(AOP(left),offset,FALSE);
4036 aopPut(AOP(result),l,offset);
4041 emitcode("ld", "a,%s",aopGet(AOP(right),0,FALSE));
4042 emitcode("inc","a");
4043 freeAsmop (right, NULL, ic);
4045 tlbl = newiTempLabel(NULL);
4046 tlbl1= newiTempLabel(NULL);
4047 size = AOP_SIZE(result);
4050 emit2("!shortjp !tlabel", tlbl1->key+100);
4051 emitLabel(tlbl->key+100);
4053 l = aopGet(AOP(result),offset--,FALSE);
4056 emitcode("sra", "%s", l);
4058 emitcode("srl", "%s", l);
4062 emitcode("rr", "%s", l);
4064 emitLabel(tlbl1->key+100);
4065 emitcode("dec", "a");
4066 emit2("!shortjp nz,!tlabel", tlbl->key+100);
4068 freeAsmop(left,NULL,ic);
4069 freeAsmop(result,NULL,ic);
4072 /*-----------------------------------------------------------------*/
4073 /* genGenPointerGet - get value from generic pointer space */
4074 /*-----------------------------------------------------------------*/
4075 static void genGenPointerGet (operand *left,
4076 operand *result, iCode *ic)
4079 link *retype = getSpec(operandType(result));
4085 aopOp(left,ic,FALSE, FALSE);
4086 aopOp(result,ic,FALSE, FALSE);
4088 if (isPair(AOP(left)) && AOP_SIZE(result)==1) {
4090 if (isPtrPair(AOP(left)))
4092 tsprintf(buffer, "!*pair", getPairName(AOP(left)));
4093 aopPut(AOP(result), buffer, 0);
4096 emit2("ld a,!*pair", getPairName(AOP(left)));
4097 aopPut(AOP(result),"a", 0);
4099 freeAsmop(left,NULL,ic);
4103 /* For now we always load into IY */
4104 /* if this is remateriazable */
4105 fetchPair(pair, AOP(left));
4107 /* so iy now contains the address */
4108 freeAsmop(left,NULL,ic);
4110 /* if bit then unpack */
4111 if (IS_BITVAR(retype)) {
4115 size = AOP_SIZE(result);
4119 /* PENDING: make this better */
4120 if (!IS_GB && AOP(result)->type == AOP_REG) {
4121 aopPut(AOP(result), "!*hl", offset++);
4124 emit2("ld a,!*pair", _pairs[pair].name);
4125 aopPut(AOP(result),"a",offset++);
4128 emit2("inc %s", _pairs[pair].name);
4134 freeAsmop(result,NULL,ic);
4137 /*-----------------------------------------------------------------*/
4138 /* genPointerGet - generate code for pointer get */
4139 /*-----------------------------------------------------------------*/
4140 static void genPointerGet (iCode *ic)
4142 operand *left, *result ;
4146 result = IC_RESULT(ic) ;
4148 /* depending on the type of pointer we need to
4149 move it to the correct pointer register */
4150 type = operandType(left);
4151 etype = getSpec(type);
4153 genGenPointerGet (left,result,ic);
4156 bool isRegOrLit(asmop *aop)
4158 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
4163 /*-----------------------------------------------------------------*/
4164 /* genGenPointerSet - stores the value into a pointer location */
4165 /*-----------------------------------------------------------------*/
4166 static void genGenPointerSet (operand *right,
4167 operand *result, iCode *ic)
4170 link *retype = getSpec(operandType(right));
4171 PAIR_ID pairId = PAIR_HL;
4173 aopOp(result,ic,FALSE, FALSE);
4174 aopOp(right,ic,FALSE, FALSE);
4179 /* Handle the exceptions first */
4180 if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
4182 char *l = aopGet(AOP(right), 0, FALSE);
4183 const char *pair = getPairName(AOP(result));
4184 if (canAssignToPtr(l) && isPtr(pair)) {
4185 emit2("ld !*pair,%s", pair, l);
4189 emit2("ld !*pair,a", pair);
4194 /* if the operand is already in dptr
4195 then we do nothing else we move the value to dptr */
4196 if (AOP_TYPE(result) != AOP_STR) {
4197 fetchPair(pairId, AOP(result));
4199 /* so hl know contains the address */
4200 freeAsmop(result,NULL,ic);
4202 /* if bit then unpack */
4203 if (IS_BITVAR(retype)) {
4207 size = AOP_SIZE(right);
4211 char *l = aopGet(AOP(right),offset,FALSE);
4212 if (isRegOrLit(AOP(right)) && !IS_GB) {
4213 emit2("ld !*pair,%s", _pairs[pairId].name, l);
4217 emit2("ld !*pair,a", _pairs[pairId].name);
4220 emitcode("inc", _pairs[pairId].name);
4226 freeAsmop(right,NULL,ic);
4229 /*-----------------------------------------------------------------*/
4230 /* genPointerSet - stores the value into a pointer location */
4231 /*-----------------------------------------------------------------*/
4232 static void genPointerSet (iCode *ic)
4234 operand *right, *result ;
4237 right = IC_RIGHT(ic);
4238 result = IC_RESULT(ic) ;
4240 /* depending on the type of pointer we need to
4241 move it to the correct pointer register */
4242 type = operandType(result);
4243 etype = getSpec(type);
4245 genGenPointerSet (right,result,ic);
4248 /*-----------------------------------------------------------------*/
4249 /* genIfx - generate code for Ifx statement */
4250 /*-----------------------------------------------------------------*/
4251 static void genIfx (iCode *ic, iCode *popIc)
4253 operand *cond = IC_COND(ic);
4256 aopOp(cond,ic,FALSE, TRUE);
4258 /* get the value into acc */
4259 if (AOP_TYPE(cond) != AOP_CRY)
4263 /* the result is now in the accumulator */
4264 freeAsmop(cond,NULL,ic);
4266 /* if there was something to be popped then do it */
4270 /* if the condition is a bit variable */
4271 if (isbit && IS_ITEMP(cond) &&
4273 genIfxJump(ic,SPIL_LOC(cond)->rname);
4275 if (isbit && !IS_ITEMP(cond))
4276 genIfxJump(ic,OP_SYMBOL(cond)->rname);
4283 /*-----------------------------------------------------------------*/
4284 /* genAddrOf - generates code for address of */
4285 /*-----------------------------------------------------------------*/
4286 static void genAddrOf (iCode *ic)
4288 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
4290 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
4292 /* if the operand is on the stack then we
4293 need to get the stack offset of this
4298 if (sym->stack <= 0) {
4299 emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
4302 emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
4304 emitcode("ld", "d,h");
4305 emitcode("ld", "e,l");
4308 emit2("ld de,!hashedstr", sym->rname);
4310 aopPut(AOP(IC_RESULT(ic)), "e", 0);
4311 aopPut(AOP(IC_RESULT(ic)), "d", 1);
4316 /* if it has an offset then we need to compute it */
4317 emitcode("ld", "hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
4318 emitcode("add", "hl,sp");
4321 emitcode("ld", "hl,#%s", sym->rname);
4323 aopPut(AOP(IC_RESULT(ic)), "l", 0);
4324 aopPut(AOP(IC_RESULT(ic)), "h", 1);
4326 freeAsmop(IC_RESULT(ic),NULL,ic);
4329 /*-----------------------------------------------------------------*/
4330 /* genAssign - generate code for assignment */
4331 /*-----------------------------------------------------------------*/
4332 static void genAssign (iCode *ic)
4334 operand *result, *right;
4336 unsigned long lit = 0L;
4338 result = IC_RESULT(ic);
4339 right = IC_RIGHT(ic) ;
4342 /* Dont bother assigning if they are the same */
4343 if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) {
4344 emitcode("", "; (operands are equal %u)", operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)));
4349 aopOp(right,ic,FALSE, FALSE);
4350 aopOp(result,ic,TRUE, FALSE);
4352 /* if they are the same registers */
4353 if (sameRegs(AOP(right),AOP(result))) {
4354 emitcode("", "; (registers are the same)");
4358 /* if the result is a bit */
4359 if (AOP_TYPE(result) == AOP_CRY) {
4364 size = AOP_SIZE(result);
4367 if(AOP_TYPE(right) == AOP_LIT)
4368 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
4369 if (isPair(AOP(result))) {
4370 fetchPair(getPairId(AOP(result)), AOP(right));
4372 else if((size > 1) &&
4373 (AOP_TYPE(result) != AOP_REG) &&
4374 (AOP_TYPE(right) == AOP_LIT) &&
4375 !IS_FLOAT(operandType(right)) &&
4377 bool fXored = FALSE;
4379 /* Work from the top down.
4380 Done this way so that we can use the cached copy of 0
4381 in A for a fast clear */
4383 if((unsigned int)((lit >> (offset*8)) & 0x0FFL)== 0) {
4384 if (!fXored && size>1) {
4385 emitcode("xor", "a,a");
4389 aopPut(AOP(result),"a",offset);
4392 aopPut(AOP(result), zero, offset);
4397 aopGet(AOP(right),offset,FALSE),
4402 else if (size == 2 && requiresHL(AOP(right)) && requiresHL(AOP(result)) && IS_GB) {
4403 /* Special case. Load into a and d, then load out. */
4404 MOVA(aopGet(AOP(right), 0, FALSE));
4405 emitcode("ld", "e,%s", aopGet(AOP(right), 1, FALSE));
4406 aopPut(AOP(result), "a", 0);
4407 aopPut(AOP(result), "e", 1);
4410 /* PENDING: do this check better */
4411 if (requiresHL(AOP(right)) && requiresHL(AOP(result))) {
4412 MOVA(aopGet(AOP(right), offset, FALSE));
4413 aopPut(AOP(result), "a", offset);
4417 aopGet(AOP(right),offset,FALSE),
4424 freeAsmop(right,NULL,ic);
4425 freeAsmop(result,NULL,ic);
4428 /*-----------------------------------------------------------------*/
4429 /* genJumpTab - genrates code for jump table */
4430 /*-----------------------------------------------------------------*/
4431 static void genJumpTab (iCode *ic)
4436 aopOp(IC_JTCOND(ic),ic,FALSE, FALSE);
4437 /* get the condition into accumulator */
4438 l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE);
4440 emitcode("push", "de");
4441 emitcode("ld", "e,%s", l);
4442 emit2("ld d,!zero");
4443 jtab = newiTempLabel(NULL);
4445 emit2("ld hl,!immed!tlabel", jtab->key+100);
4446 emitcode("add", "hl,de");
4447 emitcode("add", "hl,de");
4448 emitcode("add", "hl,de");
4449 freeAsmop(IC_JTCOND(ic),NULL,ic);
4451 emitcode("pop", "de");
4453 emitLabel(jtab->key+100);
4454 /* now generate the jump labels */
4455 for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
4456 jtab = setNextItem(IC_JTLABELS(ic)))
4457 emit2("jp !tlabel", jtab->key+100);
4460 /*-----------------------------------------------------------------*/
4461 /* genCast - gen code for casting */
4462 /*-----------------------------------------------------------------*/
4463 static void genCast (iCode *ic)
4465 operand *result = IC_RESULT(ic);
4466 link *ctype = operandType(IC_LEFT(ic));
4467 operand *right = IC_RIGHT(ic);
4470 /* if they are equivalent then do nothing */
4471 if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
4474 aopOp(right,ic,FALSE, FALSE);
4475 aopOp(result,ic,FALSE, FALSE);
4477 /* if the result is a bit */
4478 if (AOP_TYPE(result) == AOP_CRY) {
4482 /* if they are the same size : or less */
4483 if (AOP_SIZE(result) <= AOP_SIZE(right)) {
4485 /* if they are in the same place */
4486 if (sameRegs(AOP(right),AOP(result)))
4489 /* if they in different places then copy */
4490 size = AOP_SIZE(result);
4494 aopGet(AOP(right),offset,FALSE),
4501 /* PENDING: should be OK. */
4503 /* if the result is of type pointer */
4504 if (IS_PTR(ctype)) {
4509 /* so we now know that the size of destination is greater
4510 than the size of the source */
4511 /* we move to result for the size of source */
4512 size = AOP_SIZE(right);
4516 aopGet(AOP(right),offset,FALSE),
4521 /* now depending on the sign of the destination */
4522 size = AOP_SIZE(result) - AOP_SIZE(right);
4523 /* Unsigned or not an integral type - right fill with zeros */
4524 if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) {
4526 aopPut(AOP(result),zero,offset++);
4528 /* we need to extend the sign :{ */
4529 char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
4532 emitcode("", "; genCast: sign extend untested.");
4533 emitcode("rla", "");
4534 emitcode("sbc", "a,a");
4536 aopPut(AOP(result),"a",offset++);
4540 freeAsmop(right, NULL, ic);
4541 freeAsmop(result, NULL, ic);
4544 /*-----------------------------------------------------------------*/
4545 /* genReceive - generate code for a receive iCode */
4546 /*-----------------------------------------------------------------*/
4547 static void genReceive (iCode *ic)
4549 if (isOperandInFarSpace(IC_RESULT(ic)) &&
4550 ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
4551 IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
4555 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
4557 assignResultValue(IC_RESULT(ic));
4560 freeAsmop(IC_RESULT(ic),NULL,ic);
4563 /*-----------------------------------------------------------------*/
4564 /* genZ80Code - generate code for Z80 based controllers */
4565 /*-----------------------------------------------------------------*/
4566 void genZ80Code (iCode *lic)
4573 _fReturn = _gbz80_return;
4574 _fTmp = _gbz80_return;
4577 _fReturn = _z80_return;
4578 _fTmp = _z80_return;
4580 tsprintf(zero, "!zero");
4582 lineHead = lineCurr = NULL;
4584 /* if debug information required */
4585 if (options.debug && currFunc) {
4586 cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
4588 if (IS_STATIC(currFunc->etype))
4589 emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name);
4591 emitcode("","G$%s$0$0 ==.",currFunc->name);
4594 /* stack pointer name */
4598 for (ic = lic ; ic ; ic = ic->next ) {
4600 if ( cln != ic->lineno ) {
4601 if ( options.debug ) {
4603 emitcode("","C$%s$%d$%d$%d ==.",
4604 ic->filename,ic->lineno,
4605 ic->level,ic->block);
4608 emitcode(";","%s %d",ic->filename,ic->lineno);
4611 /* if the result is marked as
4612 spilt and rematerializable or code for
4613 this has already been generated then
4615 if (resultRemat(ic) || ic->generated )
4618 /* depending on the operation */
4621 emitcode("", "; genNot");
4626 emitcode("", "; genCpl");
4631 emitcode("", "; genUminus");
4636 emitcode("", "; genIpush");
4641 /* IPOP happens only when trying to restore a
4642 spilt live range, if there is an ifx statement
4643 following this pop then the if statement might
4644 be using some of the registers being popped which
4645 would destory the contents of the register so
4646 we need to check for this condition and handle it */
4648 ic->next->op == IFX &&
4649 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) {
4650 emitcode("", "; genIfx");
4651 genIfx (ic->next,ic);
4654 emitcode("", "; genIpop");
4660 emitcode("", "; genCall");
4665 emitcode("", "; genPcall");
4670 emitcode("", "; genFunction");
4675 emitcode("", "; genEndFunction");
4676 genEndFunction (ic);
4680 emitcode("", "; genRet");
4685 emitcode("", "; genLabel");
4690 emitcode("", "; genGoto");
4695 emitcode("", "; genPlus");
4700 emitcode("", "; genMinus");
4705 emitcode("", "; genMult");
4710 emitcode("", "; genDiv");
4715 emitcode("", "; genMod");
4720 emitcode("", "; genCmpGt");
4721 genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));
4725 emitcode("", "; genCmpLt");
4726 genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
4733 /* note these two are xlated by algebraic equivalence
4734 during parsing SDCC.y */
4735 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
4736 "got '>=' or '<=' shouldn't have come here");
4740 emitcode("", "; genCmpEq");
4741 genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
4745 emitcode("", "; genAndOp");
4750 emitcode("", "; genOrOp");
4755 emitcode("", "; genXor");
4756 genXor (ic,ifxForOp(IC_RESULT(ic),ic));
4760 emitcode("", "; genOr");
4761 genOr (ic,ifxForOp(IC_RESULT(ic),ic));
4765 emitcode("", "; genAnd");
4766 genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
4770 emitcode("", "; genInline");
4775 emitcode("", "; genRRC");
4780 emitcode("", "; genRLC");
4785 emitcode("", "; genHBIT");
4789 emitcode("", "; genLeftShift");
4794 emitcode("", "; genRightShift");
4798 case GET_VALUE_AT_ADDRESS:
4799 emitcode("", "; genPointerGet");
4805 if (POINTER_SET(ic)) {
4806 emitcode("", "; genAssign (pointer)");
4810 emitcode("", "; genAssign");
4816 emitcode("", "; genIfx");
4821 emitcode("", "; genAddrOf");
4826 emitcode("", "; genJumpTab");
4831 emitcode("", "; genCast");
4836 emitcode("", "; genReceive");
4841 emitcode("", "; addSet");
4842 addSet(&sendSet,ic);
4847 /* piCode(ic,stdout); */
4853 /* now we are ready to call the
4854 peep hole optimizer */
4855 if (!options.nopeep)
4856 peepHole (&lineHead);
4858 /* now do the actual printing */
4859 printLine (lineHead, codeOutFile);