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);
851 else if (IS_Z80 && aop->type == AOP_IY) {
852 /* Instead of fetching relative to IY, just grab directly
853 from the address IY refers to */
854 char *l = aopGetLitWordLong(aop, offset, FALSE);
856 emit2("ld %s,(%s)", _pairs[pairId].name, l);
859 emitcode("ld", "%s,%s", _pairs[pairId].l, aopGet(aop, offset, FALSE));
860 emitcode("ld", "%s,%s", _pairs[pairId].h, aopGet(aop, offset+1, FALSE));
862 /* PENDING: check? */
863 if (pairId == PAIR_HL)
868 static void fetchPair(PAIR_ID pairId, asmop *aop)
870 fetchPairLong(pairId, aop, 0);
873 static void fetchHL(asmop *aop)
875 fetchPair(PAIR_HL, aop);
878 static void setupPair(PAIR_ID pairId, asmop *aop, int offset)
880 assert(pairId == PAIR_HL || pairId == PAIR_IY);
884 fetchLitPair(pairId, aop, 0);
887 fetchLitPair(pairId, aop, offset);
888 _G.pairs[pairId].offset = offset;
891 /* Doesnt include _G.stack.pushed */
892 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
893 if (aop->aopu.aop_stk > 0) {
894 abso += _G.stack.param_offset;
896 assert(pairId == PAIR_HL);
897 /* In some cases we can still inc or dec hl */
898 if (_G.pairs[pairId].last_type == AOP_STK && abs(_G.pairs[pairId].offset - abso) < 3) {
899 adjustPair(_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
902 emit2("!ldahlsp", abso +_G.stack.pushed);
904 _G.pairs[pairId].offset = abso;
910 _G.pairs[pairId].last_type = aop->type;
913 static void emitLabel(int key)
915 emit2("!tlabeldef", key);
919 /*-----------------------------------------------------------------*/
920 /* aopGet - for fetching value of the aop */
921 /*-----------------------------------------------------------------*/
922 static char *aopGet(asmop *aop, int offset, bool bit16)
927 /* offset is greater than size then zero */
928 /* PENDING: this seems a bit screwed in some pointer cases. */
929 if (offset > (aop->size - 1) &&
930 aop->type != AOP_LIT)
933 /* depending on type */
936 /* PENDING: re-target */
938 tsprintf (s,"!immedwords", aop->aopu.aop_immd);
942 tsprintf(s, "!bankimmeds", aop->aopu.aop_immd);
945 tsprintf(s, "!msbimmeds", aop->aopu.aop_immd);
948 tsprintf(s, "!lsbimmeds", aop->aopu.aop_immd);
953 ALLOC_ATOMIC(rs,strlen(s)+1);
959 emitcode("ld", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
961 ALLOC_ATOMIC(rs,strlen(s)+1);
967 emitcode("ldh", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
969 ALLOC_ATOMIC(rs,strlen(s)+1);
974 return aop->aopu.aop_reg[offset]->name;
978 setupPair(PAIR_HL, aop, offset);
984 setupPair(PAIR_IY, aop, offset);
985 tsprintf(s,"!*iyx", offset);
986 ALLOC_ATOMIC(rs,strlen(s)+1);
992 setupPair(PAIR_HL, aop, offset);
996 tsprintf(s,"!*ixx", aop->aopu.aop_stk+offset);
998 ALLOC_ATOMIC(rs,strlen(s)+1);
1012 wassert(offset < 2);
1013 return aop->aopu.aop_str[offset];
1016 return aopLiteral (aop->aopu.aop_lit,offset);
1020 return aop->aopu.aop_str[offset];
1024 wassertl(0, "aopget got unsupported aop->type");
1028 bool isRegString(char *s)
1030 if (!strcmp(s, "b") ||
1041 bool isConstant(const char *s)
1043 /* This is a bit of a hack... */
1044 return (*s == '#' || *s == '$');
1047 bool canAssignToPtr(char *s)
1056 /*-----------------------------------------------------------------*/
1057 /* aopPut - puts a string for a aop */
1058 /*-----------------------------------------------------------------*/
1059 static void aopPut (asmop *aop, char *s, int offset)
1061 if (aop->size && offset > ( aop->size - 1)) {
1062 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1063 "aopPut got offset > aop->size");
1067 /* will assign value to value */
1068 /* depending on where it is ofcourse */
1069 switch (aop->type) {
1074 emitcode("ld", "a,%s", s);
1075 emitcode("ld", "(%s+%d),a", aop->aopu.aop_dir, offset);
1081 emitcode("ld", "a,%s", s);
1082 emitcode("ldh", "(%s+%d),a", aop->aopu.aop_dir, offset);
1086 if (!strcmp(s, "!*hl"))
1087 emit2("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1090 aop->aopu.aop_reg[offset]->name, s);
1095 setupPair(PAIR_IY, aop, offset);
1096 if (!canAssignToPtr(s)) {
1097 emit2("ld a,%s", s);
1098 emit2("ld !*iyx,a", offset);
1101 emit2("ld !*iyx,%s", offset, s);
1106 /* PENDING: for re-target */
1107 if (!strcmp(s, "!*hl") || !strcmp(s, "(hl)") || !strcmp(s, "[hl]")) {
1111 setupPair(PAIR_HL, aop, offset);
1113 emit2("ld !*hl,%s", s);
1118 /* PENDING: re-target */
1119 if (!strcmp(s, "!*hl") || !strcmp(s, "(hl)") || !strcmp(s, "[hl]")) {
1123 setupPair(PAIR_HL, aop, offset);
1124 if (!canAssignToPtr(s)) {
1125 emit2("ld a,%s", s);
1129 emit2("ld !*hl,%s ; 3", s);
1132 if (!canAssignToPtr(s)) {
1133 emit2("ld a,%s", s);
1134 emit2("ld !*ixx,a", aop->aopu.aop_stk+offset);
1137 emit2("ld !*ixx,%s", aop->aopu.aop_stk+offset, s);
1142 /* if bit variable */
1143 if (!aop->aopu.aop_dir) {
1147 /* In bit space but not in C - cant happen */
1154 if (strcmp(aop->aopu.aop_str[offset],s)) {
1155 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1161 if (!offset && (strcmp(s,"acc") == 0))
1165 emitcode("", "; Error aopPut AOP_ACC");
1168 if (strcmp(aop->aopu.aop_str[offset],s))
1169 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1174 wassert(offset < 2);
1175 emit2("ld %s,%s", aop->aopu.aop_str[offset], s);
1179 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1180 "aopPut got unsupported aop->type");
1185 #define AOP(op) op->aop
1186 #define AOP_TYPE(op) AOP(op)->type
1187 #define AOP_SIZE(op) AOP(op)->size
1188 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1190 /*-----------------------------------------------------------------*/
1191 /* getDataSize - get the operand data size */
1192 /*-----------------------------------------------------------------*/
1193 int getDataSize(operand *op)
1196 size = AOP_SIZE(op);
1204 /*-----------------------------------------------------------------*/
1205 /* movLeft2Result - move byte from left to result */
1206 /*-----------------------------------------------------------------*/
1207 static void movLeft2Result (operand *left, int offl,
1208 operand *result, int offr, int sign)
1211 if(!sameRegs(AOP(left),AOP(result)) || (offl != offr)){
1212 l = aopGet(AOP(left),offl,FALSE);
1215 aopPut(AOP(result),l,offr);
1224 /** Put Acc into a register set
1226 void outAcc(operand *result)
1229 size = getDataSize(result);
1231 aopPut(AOP(result),"a",0);
1234 /* unsigned or positive */
1236 aopPut(AOP(result), zero, offset++);
1241 /** Take the value in carry and put it into a register
1243 void outBitC(operand *result)
1245 /* if the result is bit */
1246 if (AOP_TYPE(result) == AOP_CRY) {
1247 emitcode("", "; Note: outBitC form 1");
1248 aopPut(AOP(result),"blah",0);
1251 emit2("ld a,!zero");
1257 /*-----------------------------------------------------------------*/
1258 /* toBoolean - emit code for orl a,operator(sizeop) */
1259 /*-----------------------------------------------------------------*/
1260 void toBoolean(operand *oper)
1262 int size = AOP_SIZE(oper);
1265 emitcode("ld", "a,%s", aopGet(AOP(oper), offset++, FALSE));
1268 emitcode("or","a,%s",aopGet(AOP(oper),offset++,FALSE));
1271 if (AOP(oper)->type != AOP_ACC) {
1273 emitcode("or","a,%s",aopGet(AOP(oper),0,FALSE));
1278 /*-----------------------------------------------------------------*/
1279 /* genNot - generate code for ! operation */
1280 /*-----------------------------------------------------------------*/
1281 static void genNot (iCode *ic)
1283 link *optype = operandType(IC_LEFT(ic));
1285 /* assign asmOps to operand & result */
1286 aopOp (IC_LEFT(ic),ic,FALSE, TRUE);
1287 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1289 /* if in bit space then a special case */
1290 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) {
1294 /* if type float then do float */
1295 if (IS_FLOAT(optype)) {
1299 toBoolean(IC_LEFT(ic));
1304 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1305 emit2("sub a,!one");
1306 outBitC(IC_RESULT(ic));
1308 /* release the aops */
1309 freeAsmop(IC_LEFT(ic),NULL,ic);
1310 freeAsmop(IC_RESULT(ic),NULL,ic);
1313 /*-----------------------------------------------------------------*/
1314 /* genCpl - generate code for complement */
1315 /*-----------------------------------------------------------------*/
1316 static void genCpl (iCode *ic)
1322 /* assign asmOps to operand & result */
1323 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
1324 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1326 /* if both are in bit space then
1328 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1329 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1333 size = AOP_SIZE(IC_RESULT(ic));
1335 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1338 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1341 /* release the aops */
1342 freeAsmop(IC_LEFT(ic),NULL,ic);
1343 freeAsmop(IC_RESULT(ic),NULL,ic);
1346 /*-----------------------------------------------------------------*/
1347 /* genUminus - unary minus code generation */
1348 /*-----------------------------------------------------------------*/
1349 static void genUminus (iCode *ic)
1352 link *optype, *rtype;
1355 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1356 aopOp(IC_RESULT(ic),ic,TRUE, FALSE);
1358 /* if both in bit space then special
1360 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1361 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1366 optype = operandType(IC_LEFT(ic));
1367 rtype = operandType(IC_RESULT(ic));
1369 /* if float then do float stuff */
1370 if (IS_FLOAT(optype)) {
1375 /* otherwise subtract from zero */
1376 size = AOP_SIZE(IC_LEFT(ic));
1380 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1381 emit2("ld a,!zero");
1382 emit2("sbc a,%s",l);
1383 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1386 /* if any remaining bytes in the result */
1387 /* we just need to propagate the sign */
1388 if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic))))) {
1392 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1396 /* release the aops */
1397 freeAsmop(IC_LEFT(ic),NULL,ic);
1398 freeAsmop(IC_RESULT(ic),NULL,ic);
1401 static void _push(PAIR_ID pairId)
1403 emit2("push %s", _pairs[pairId].name);
1404 _G.stack.pushed += 2;
1407 static void _pop(PAIR_ID pairId)
1409 emit2("pop %s", _pairs[pairId].name);
1410 _G.stack.pushed -= 2;
1414 /*-----------------------------------------------------------------*/
1415 /* assignResultValue - */
1416 /*-----------------------------------------------------------------*/
1417 void assignResultValue(operand * oper)
1419 int size = AOP_SIZE(oper);
1423 topInA = requiresHL(AOP(oper));
1429 if (IS_GB && size == 4 && requiresHL(AOP(oper))) {
1430 /* We do it the hard way here. */
1432 aopPut(AOP(oper), _fReturn[0], 0);
1433 aopPut(AOP(oper), _fReturn[1], 1);
1434 emitcode("pop", "de");
1435 _G.stack.pushed -= 2;
1436 aopPut(AOP(oper), _fReturn[0], 2);
1437 aopPut(AOP(oper), _fReturn[1], 3);
1441 aopPut(AOP(oper), _fReturn[size], size);
1446 /*-----------------------------------------------------------------*/
1447 /* genIpush - genrate code for pushing this gets a little complex */
1448 /*-----------------------------------------------------------------*/
1449 static void genIpush (iCode *ic)
1451 int size, offset = 0 ;
1454 /* if this is not a parm push : ie. it is spill push
1455 and spill push is always done on the local stack */
1456 if (!ic->parmPush) {
1457 /* and the item is spilt then do nothing */
1458 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1461 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1462 size = AOP_SIZE(IC_LEFT(ic));
1463 /* push it on the stack */
1464 if (isPair(AOP(IC_LEFT(ic)))) {
1465 emitcode("push", getPairName(AOP(IC_LEFT(ic))));
1466 _G.stack.pushed += 2;
1471 /* Simple for now - load into A and PUSH AF */
1472 if (AOP(IC_LEFT(ic))->type == AOP_IY) {
1473 char *l = aopGetLitWordLong(AOP(IC_LEFT(ic)), --offset, FALSE);
1475 emit2("ld a,(%s)", l);
1478 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1479 emit2("ld a,%s", l);
1489 /* Hmmm... what about saving the currently used registers
1492 /* then do the push */
1493 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1495 size = AOP_SIZE(IC_LEFT(ic));
1497 if (isPair(AOP(IC_LEFT(ic)))) {
1499 emitcode("push", "%s", getPairName(AOP(IC_LEFT(ic))));
1503 fetchHL(AOP(IC_LEFT(ic)));
1504 emitcode("push", "hl");
1506 _G.stack.pushed += 2;
1510 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
1511 emitcode("push", "hl");
1513 _G.stack.pushed += 2;
1514 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 0);
1515 emitcode("push", "hl");
1517 _G.stack.pushed += 2;
1522 if (AOP(IC_LEFT(ic))->type == AOP_IY) {
1523 char *l = aopGetLitWordLong(AOP(IC_LEFT(ic)), --offset, FALSE);
1525 emit2("ld a,(%s)", l);
1528 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1529 emit2("ld a,%s", l);
1531 emitcode("push", "af");
1532 emitcode("inc", "sp");
1537 freeAsmop(IC_LEFT(ic),NULL,ic);
1540 /*-----------------------------------------------------------------*/
1541 /* genIpop - recover the registers: can happen only for spilling */
1542 /*-----------------------------------------------------------------*/
1543 static void genIpop (iCode *ic)
1548 /* if the temp was not pushed then */
1549 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1552 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1553 size = AOP_SIZE(IC_LEFT(ic));
1555 if (isPair(AOP(IC_LEFT(ic)))) {
1556 emitcode("pop", getPairName(AOP(IC_LEFT(ic))));
1560 emitcode("dec", "sp");
1561 emitcode("pop", "hl");
1563 aopPut(AOP(IC_LEFT(ic)), "l", offset--);
1567 freeAsmop(IC_LEFT(ic),NULL,ic);
1570 static int _isPairUsed(iCode *ic, PAIR_ID pairId)
1575 if (bitVectBitValue(ic->rUsed, D_IDX))
1577 if (bitVectBitValue(ic->rUsed, E_IDX))
1586 static int _opUsesPair(operand *op, iCode *ic, PAIR_ID pairId)
1590 symbol *sym = OP_SYMBOL(op);
1592 if (sym->isspilt || sym->nRegs == 0)
1595 aopOp(op, ic, FALSE, FALSE);
1598 if (aop->type == AOP_REG) {
1600 for (i=0; i < aop->size; i++) {
1601 if (pairId == PAIR_DE) {
1602 emit2("; name %s", aop->aopu.aop_reg[i]->name);
1603 if (!strcmp(aop->aopu.aop_reg[i]->name, "e"))
1605 if (!strcmp(aop->aopu.aop_reg[i]->name, "d"))
1614 freeAsmop(IC_LEFT(ic),NULL,ic);
1618 /** Emit the code for a call statement
1620 static void emitCall(iCode *ic, bool ispcall)
1623 link *detype = getSpec(operandType(IC_LEFT(ic)));
1625 if (IS_BANKED(detype))
1626 emit2("; call to a banked function");
1628 /* if caller saves & we have not saved then */
1629 if (!ic->regsSaved) {
1633 /* if send set is not empty then assign */
1637 int n = elementsInSet(sendSet);
1638 if (IS_Z80 && n == 2 && _isPairUsed(ic, PAIR_DE)) {
1639 /* Only push de if it is used and if it's not used
1640 in the return value */
1641 /* Panic if partly used */
1642 if (_opUsesPair(IC_RESULT(ic), ic, PAIR_DE) == 1) {
1643 emit2("; Warning: de crossover");
1645 else if (!_opUsesPair(IC_RESULT(ic), ic, PAIR_DE)) {
1652 if (IS_Z80 && n == 2 ) {
1653 /* Want to load HL first, then DE as HL may = DE */
1654 sic = setFirstItem(sendSet);
1655 sic = setNextItem(sendSet);
1656 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1657 fetchPair(PAIR_HL, AOP(IC_LEFT(sic)));
1659 freeAsmop (IC_LEFT(sic),NULL,sic);
1660 sic = setFirstItem(sendSet);
1661 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1662 fetchPair(PAIR_DE, AOP(IC_LEFT(sic)));
1664 freeAsmop (IC_LEFT(sic),NULL,sic);
1667 for (sic = setFirstItem(sendSet) ; sic ;
1668 sic = setNextItem(sendSet)) {
1670 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1671 size = AOP_SIZE(IC_LEFT(sic));
1673 /* Always send in pairs */
1676 if (IS_Z80 && n == 1)
1677 fetchPair(PAIR_HL, AOP(IC_LEFT(sic)));
1679 fetchPair(PAIR_DE, AOP(IC_LEFT(sic)));
1682 fetchPair(PAIR_HL, AOP(IC_LEFT(sic)));
1685 /* Send set too big */
1689 freeAsmop (IC_LEFT(sic),NULL,sic);
1698 if (IS_BANKED(detype)) {
1699 werror(W_INDIR_BANKED);
1701 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1703 if (isLitWord(AOP(IC_LEFT(ic)))) {
1704 emitcode("", "; Special case where the pCall is to a constant");
1705 emitcode("call", aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE));
1708 symbol *rlbl = newiTempLabel(NULL);
1710 emit2("ld hl,!immed!tlabel", (rlbl->key+100));
1711 emitcode("push", "hl");
1712 _G.stack.pushed += 2;
1714 fetchHL(AOP(IC_LEFT(ic)));
1716 emit2("!tlabeldef", (rlbl->key+100));
1717 _G.stack.pushed -= 2;
1719 freeAsmop(IC_LEFT(ic),NULL,ic);
1722 char *name = OP_SYMBOL(IC_LEFT(ic))->rname[0] ?
1723 OP_SYMBOL(IC_LEFT(ic))->rname :
1724 OP_SYMBOL(IC_LEFT(ic))->name;
1725 if (IS_BANKED(detype)) {
1726 emit2("call banked_call");
1727 emit2("!dws", name);
1728 emit2("!dw !bankimmeds", name);
1732 emit2("call %s", name);
1737 /* if we need assign a result value */
1738 if ((IS_ITEMP(IC_RESULT(ic)) &&
1739 (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
1740 OP_SYMBOL(IC_RESULT(ic))->spildir )) ||
1741 IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
1744 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
1747 assignResultValue(IC_RESULT(ic));
1749 freeAsmop(IC_RESULT(ic),NULL, ic);
1752 /* adjust the stack for parameters if required */
1753 if (IC_LEFT(ic)->parmBytes) {
1754 int i = IC_LEFT(ic)->parmBytes;
1755 _G.stack.pushed -= i;
1757 emit2("!ldaspsp", i);
1762 emitcode("ld", "hl,#%d", i);
1763 emitcode("add", "hl,sp");
1764 emitcode("ld", "sp,hl");
1768 emitcode("pop", "hl");
1772 emitcode("inc", "sp");
1781 /*-----------------------------------------------------------------*/
1782 /* genCall - generates a call statement */
1783 /*-----------------------------------------------------------------*/
1784 static void genCall (iCode *ic)
1786 link *detype = getSpec(operandType(IC_LEFT(ic)));
1787 if (IS_BANKED(detype)) emit2("; call to a banked function");
1788 emitCall(ic, FALSE);
1791 /*-----------------------------------------------------------------*/
1792 /* genPcall - generates a call by pointer statement */
1793 /*-----------------------------------------------------------------*/
1794 static void genPcall (iCode *ic)
1799 /*-----------------------------------------------------------------*/
1800 /* resultRemat - result is rematerializable */
1801 /*-----------------------------------------------------------------*/
1802 static int resultRemat (iCode *ic)
1804 if (SKIP_IC(ic) || ic->op == IFX)
1807 if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
1808 symbol *sym = OP_SYMBOL(IC_RESULT(ic));
1809 if (sym->remat && !POINTER_SET(ic))
1816 /*-----------------------------------------------------------------*/
1817 /* genFunction - generated code for function entry */
1818 /*-----------------------------------------------------------------*/
1819 static void genFunction (iCode *ic)
1821 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1825 /* create the function header */
1826 emit2("!functionheader", sym->name);
1827 /* PENDING: portability. */
1828 emit2("__%s_start:", sym->rname);
1829 emit2("!functionlabeldef", sym->rname);
1831 fetype = getSpec(operandType(IC_LEFT(ic)));
1833 /* if critical function then turn interrupts off */
1834 if (SPEC_CRTCL(fetype))
1836 if (SPEC_BANKED(fetype)) emit2("; Iam banked");
1838 /* if this is an interrupt service routine then
1839 save acc, b, dpl, dph */
1840 if (IS_ISR(sym->etype)) {
1843 /* PENDING: callee-save etc */
1845 /* If BC or DE are used, then push */
1846 _G.stack.pushed_bc = 0;
1847 _G.stack.pushed_de = 0;
1848 _G.stack.param_offset = 0;
1849 if (sym->regsUsed) {
1851 for ( i = 0 ; i < sym->regsUsed->size ; i++) {
1852 if (bitVectBitValue(sym->regsUsed, i)) {
1856 _G.stack.pushed_bc = 1;
1861 _G.stack.pushed_de = 1;
1866 if (_G.stack.pushed_bc) {
1868 _G.stack.param_offset += 2;
1870 if (_G.stack.pushed_de) {
1872 _G.stack.param_offset += 2;
1876 /* adjust the stack for the function */
1877 _G.stack.last = sym->stack;
1880 emit2("!enterx", sym->stack);
1883 _G.stack.offset = sym->stack;
1886 /*-----------------------------------------------------------------*/
1887 /* genEndFunction - generates epilogue for functions */
1888 /*-----------------------------------------------------------------*/
1889 static void genEndFunction (iCode *ic)
1891 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1893 if (IS_ISR(sym->etype)) {
1897 if (SPEC_CRTCL(sym->etype))
1900 /* PENDING: calleeSave */
1902 /* if debug then send end of function */
1903 if (options.debug && currFunc) {
1905 emitcode("","C$%s$%d$%d$%d ==.",
1906 ic->filename,currFunc->lastLine,
1907 ic->level,ic->block);
1908 if (IS_STATIC(currFunc->etype))
1909 emitcode("","XF%s$%s$0$0 ==.",moduleName,currFunc->name);
1911 emitcode("","XG$%s$0$0 ==.",currFunc->name);
1914 if (_G.stack.offset)
1915 emit2("!leavex", _G.stack.offset);
1919 if (_G.stack.pushed_de)
1921 if (_G.stack.pushed_bc)
1923 /* Both baned and non-banked just ret */
1926 /* PENDING: portability. */
1927 emit2("__%s_end:", sym->rname);
1929 _G.stack.pushed = 0;
1930 _G.stack.offset = 0;
1933 /*-----------------------------------------------------------------*/
1934 /* genRet - generate code for return statement */
1935 /*-----------------------------------------------------------------*/
1936 static void genRet (iCode *ic)
1939 /* Errk. This is a hack until I can figure out how
1940 to cause dehl to spill on a call */
1941 int size,offset = 0;
1943 /* if we have no return value then
1944 just generate the "ret" */
1948 /* we have something to return then
1949 move the return value into place */
1950 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1951 size = AOP_SIZE(IC_LEFT(ic));
1953 if ((size == 2) && ((l = aopGetWord(AOP(IC_LEFT(ic)), 0)))) {
1955 emitcode("ld", "de,%s", l);
1958 emitcode("ld", "hl,%s", l);
1962 if (IS_GB && size == 4 && requiresHL(AOP(IC_LEFT(ic)))) {
1963 fetchPair(PAIR_DE, AOP(IC_LEFT(ic)));
1964 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
1968 l = aopGet(AOP(IC_LEFT(ic)),offset,
1970 if (strcmp(_fReturn[offset],l))
1971 emitcode("ld","%s,%s", _fReturn[offset++],l);
1975 freeAsmop (IC_LEFT(ic),NULL,ic);
1978 /* generate a jump to the return label
1979 if the next is not the return statement */
1980 if (!(ic->next && ic->next->op == LABEL &&
1981 IC_LABEL(ic->next) == returnLabel))
1983 emit2("jp !tlabel", returnLabel->key+100);
1986 /*-----------------------------------------------------------------*/
1987 /* genLabel - generates a label */
1988 /*-----------------------------------------------------------------*/
1989 static void genLabel (iCode *ic)
1991 /* special case never generate */
1992 if (IC_LABEL(ic) == entryLabel)
1995 emitLabel(IC_LABEL(ic)->key+100);
1998 /*-----------------------------------------------------------------*/
1999 /* genGoto - generates a ljmp */
2000 /*-----------------------------------------------------------------*/
2001 static void genGoto (iCode *ic)
2003 emit2("jp !tlabel", IC_LABEL(ic)->key+100);
2006 /*-----------------------------------------------------------------*/
2007 /* genPlusIncr :- does addition with increment if possible */
2008 /*-----------------------------------------------------------------*/
2009 static bool genPlusIncr (iCode *ic)
2011 unsigned int icount ;
2012 unsigned int size = getDataSize(IC_RESULT(ic));
2013 PAIR_ID resultId = getPairId(AOP(IC_RESULT(ic)));
2015 /* will try to generate an increment */
2016 /* if the right side is not a literal
2018 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
2021 emitcode("", "; genPlusIncr");
2023 icount = floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
2025 /* If result is a pair */
2026 if (resultId != PAIR_INVALID) {
2027 if (isLitWord(AOP(IC_LEFT(ic)))) {
2028 fetchLitPair(getPairId(AOP(IC_RESULT(ic))), AOP(IC_LEFT(ic)), icount);
2031 if (isPair(AOP(IC_LEFT(ic))) && resultId == PAIR_HL && icount > 2) {
2032 fetchPair(resultId, AOP(IC_RIGHT(ic)));
2033 emitcode("add", "hl,%s", getPairName(AOP(IC_LEFT(ic))));
2039 if (!sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
2042 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
2043 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
2046 emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
2051 /* if the literal value of the right hand side
2052 is greater than 4 then it is not worth it */
2056 /* if increment 16 bits in register */
2057 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2062 symbol *tlbl = NULL;
2063 tlbl = newiTempLabel(NULL);
2065 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)), offset++, FALSE));
2067 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2070 emitLabel(tlbl->key+100);
2074 /* if the sizes are greater than 1 then we cannot */
2075 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2076 AOP_SIZE(IC_LEFT(ic)) > 1 )
2079 /* we can if the aops of the left & result match or
2080 if they are in registers and the registers are the
2082 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
2084 emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0, FALSE));
2091 /*-----------------------------------------------------------------*/
2092 /* outBitAcc - output a bit in acc */
2093 /*-----------------------------------------------------------------*/
2094 void outBitAcc(operand *result)
2096 symbol *tlbl = newiTempLabel(NULL);
2097 /* if the result is a bit */
2098 if (AOP_TYPE(result) == AOP_CRY){
2102 emit2("!shortjp z,!tlabel", tlbl->key+100);
2104 emitLabel(tlbl->key+100);
2109 /*-----------------------------------------------------------------*/
2110 /* genPlus - generates code for addition */
2111 /*-----------------------------------------------------------------*/
2112 static void genPlus (iCode *ic)
2114 int size, offset = 0;
2116 /* special cases :- */
2118 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
2119 aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
2120 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
2122 /* Swap the left and right operands if:
2124 if literal, literal on the right or
2125 if left requires ACC or right is already
2128 if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
2129 (AOP_NEEDSACC(IC_LEFT(ic))) ||
2130 AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
2131 operand *t = IC_RIGHT(ic);
2132 IC_RIGHT(ic) = IC_LEFT(ic);
2136 /* if both left & right are in bit
2138 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2139 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2144 /* if left in bit space & right literal */
2145 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2146 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
2147 /* Can happen I guess */
2151 /* if I can do an increment instead
2152 of add then GOOD for ME */
2153 if (genPlusIncr (ic) == TRUE)
2156 size = getDataSize(IC_RESULT(ic));
2158 /* Special case when left and right are constant */
2159 if (isPair(AOP(IC_RESULT(ic)))) {
2162 left = aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE);
2163 right = aopGetLitWordLong(AOP(IC_RIGHT(ic)), 0, FALSE);
2164 if (left && right) {
2168 sprintf(buffer, "#(%s + %s)", left, right);
2169 emitcode("ld", "%s,%s", getPairName(AOP(IC_RESULT(ic))), buffer);
2174 if (isPair(AOP(IC_RIGHT(ic))) && getPairId(AOP(IC_RESULT(ic))) == PAIR_HL) {
2175 /* Fetch into HL then do the add */
2177 fetchPair(PAIR_HL, AOP(IC_LEFT(ic)));
2178 emitcode("add", "hl,%s", getPairName(AOP(IC_RIGHT(ic))));
2183 if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
2184 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2186 emitcode("add","a,%s",
2187 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2189 emitcode("adc","a,%s",
2190 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2192 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2194 emitcode("add","a,%s",
2195 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2197 emitcode("adc","a,%s",
2198 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2200 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2203 /* Some kind of pointer arith. */
2204 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2205 AOP_SIZE(IC_LEFT(ic)) == 3 &&
2206 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2209 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2210 AOP_SIZE(IC_RIGHT(ic)) == 3 &&
2211 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
2216 freeAsmop(IC_LEFT(ic),NULL,ic);
2217 freeAsmop(IC_RIGHT(ic),NULL,ic);
2218 freeAsmop(IC_RESULT(ic),NULL,ic);
2222 /*-----------------------------------------------------------------*/
2223 /* genMinusDec :- does subtraction with deccrement if possible */
2224 /*-----------------------------------------------------------------*/
2225 static bool genMinusDec (iCode *ic)
2227 unsigned int icount ;
2228 unsigned int size = getDataSize(IC_RESULT(ic));
2230 /* will try to generate an increment */
2231 /* if the right side is not a literal we cannot */
2232 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
2235 /* if the literal value of the right hand side
2236 is greater than 4 then it is not worth it */
2237 if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
2240 size = getDataSize(IC_RESULT(ic));
2243 /* if increment 16 bits in register */
2244 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2247 symbol *tlbl = newiTempLabel(NULL);
2248 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
2249 emitcode("jp", "np," LABEL_STR ,tlbl->key+100);
2251 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
2255 emitLabel(tlbl->key+100);
2260 /* if decrement 16 bits in register */
2261 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2262 (size > 1) && isPair(AOP(IC_RESULT(ic)))) {
2264 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2268 /* If result is a pair */
2269 if (isPair(AOP(IC_RESULT(ic)))) {
2270 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
2271 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
2273 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2277 /* if the sizes are greater than 1 then we cannot */
2278 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2279 AOP_SIZE(IC_LEFT(ic)) > 1 )
2282 /* we can if the aops of the left & result match or if they are in
2283 registers and the registers are the same */
2284 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
2286 emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE));
2293 /*-----------------------------------------------------------------*/
2294 /* genMinus - generates code for subtraction */
2295 /*-----------------------------------------------------------------*/
2296 static void genMinus (iCode *ic)
2298 int size, offset = 0;
2299 unsigned long lit = 0L;
2301 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
2302 aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
2303 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
2305 /* special cases :- */
2306 /* if both left & right are in bit space */
2307 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2308 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2313 /* if I can do an decrement instead of subtract then GOOD for ME */
2314 if (genMinusDec (ic) == TRUE)
2317 size = getDataSize(IC_RESULT(ic));
2319 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
2322 lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
2327 /* if literal, add a,#-lit, else normal subb */
2329 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2330 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) {
2332 emitcode("sub","a,%s",
2333 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2335 emitcode("sbc","a,%s",
2336 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2339 /* first add without previous c */
2341 emit2("add a,!immedbyte", (unsigned int)(lit & 0x0FFL));
2343 emit2("adc a,!immedbyte", (unsigned int)((lit >> (offset*8)) & 0x0FFL));
2345 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2348 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2349 AOP_SIZE(IC_LEFT(ic)) == 3 &&
2350 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2354 freeAsmop(IC_LEFT(ic),NULL,ic);
2355 freeAsmop(IC_RIGHT(ic),NULL,ic);
2356 freeAsmop(IC_RESULT(ic),NULL,ic);
2359 /*-----------------------------------------------------------------*/
2360 /* genMult - generates code for multiplication */
2361 /*-----------------------------------------------------------------*/
2362 static void genMult (iCode *ic)
2364 /* Shouldn't occur - all done through function calls */
2368 /*-----------------------------------------------------------------*/
2369 /* genDiv - generates code for division */
2370 /*-----------------------------------------------------------------*/
2371 static void genDiv (iCode *ic)
2373 /* Shouldn't occur - all done through function calls */
2377 /*-----------------------------------------------------------------*/
2378 /* genMod - generates code for division */
2379 /*-----------------------------------------------------------------*/
2380 static void genMod (iCode *ic)
2382 /* Shouldn't occur - all done through function calls */
2386 /*-----------------------------------------------------------------*/
2387 /* genIfxJump :- will create a jump depending on the ifx */
2388 /*-----------------------------------------------------------------*/
2389 static void genIfxJump (iCode *ic, char *jval)
2394 /* if true label then we jump if condition
2396 if ( IC_TRUE(ic) ) {
2398 if (!strcmp(jval, "a")) {
2401 else if (!strcmp(jval, "c")) {
2405 /* The buffer contains the bit on A that we should test */
2410 /* false label is present */
2411 jlbl = IC_FALSE(ic) ;
2412 if (!strcmp(jval, "a")) {
2415 else if (!strcmp(jval, "c")) {
2419 /* The buffer contains the bit on A that we should test */
2423 /* Z80 can do a conditional long jump */
2424 if (!strcmp(jval, "a")) {
2425 emitcode("or", "a,a");
2427 else if (!strcmp(jval, "c")) {
2430 emitcode("bit", "%s,a", jval);
2432 emit2("jp %s,!tlabel", inst, jlbl->key+100);
2434 /* mark the icode as generated */
2438 /** Generic compare for > or <
2440 static void genCmp (operand *left,operand *right,
2441 operand *result, iCode *ifx, int sign)
2443 int size, offset = 0 ;
2444 unsigned long lit = 0L;
2446 /* if left & right are bit variables */
2447 if (AOP_TYPE(left) == AOP_CRY &&
2448 AOP_TYPE(right) == AOP_CRY ) {
2449 /* Cant happen on the Z80 */
2452 /* subtract right from left if at the
2453 end the carry flag is set then we know that
2454 left is greater than right */
2455 size = max(AOP_SIZE(left),AOP_SIZE(right));
2457 /* if unsigned char cmp with lit, just compare */
2459 (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
2460 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2462 emit2("xor a,!immedbyte", 0x80);
2463 emit2("cp %s^!constbyte", aopGet(AOP(right), offset, FALSE), 0x80);
2466 emitcode("cp", "%s", aopGet(AOP(right), offset, FALSE));
2469 if(AOP_TYPE(right) == AOP_LIT) {
2470 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2471 /* optimize if(x < 0) or if(x >= 0) */
2474 /* No sign so it's always false */
2478 /* Just load in the top most bit */
2479 MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE));
2480 if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx) {
2481 genIfxJump (ifx,"7");
2485 emitcode("rlc","a");
2491 /* First setup h and l contaning the top most bytes XORed */
2492 bool fDidXor = FALSE;
2493 if (AOP_TYPE(left) == AOP_LIT){
2494 unsigned long lit = (unsigned long)
2495 floatFromVal(AOP(left)->aopu.aop_lit);
2496 emit2("ld %s,!immedbyte", _fTmp[0],
2497 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2500 emitcode("ld", "a,%s", aopGet(AOP(left), size-1, FALSE));
2501 emit2("xor a,!immedbyte", 0x80);
2502 emitcode("ld", "%s,a", _fTmp[0]);
2505 if (AOP_TYPE(right) == AOP_LIT) {
2506 unsigned long lit = (unsigned long)
2507 floatFromVal(AOP(right)->aopu.aop_lit);
2508 emit2("ld %s,!immedbyte", _fTmp[1],
2509 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2512 emitcode("ld", "a,%s", aopGet(AOP(right), size-1, FALSE));
2513 emit2("xor a,!immedbyte", 0x80);
2514 emitcode("ld", "%s,a", _fTmp[1]);
2524 /* Do a long subtract */
2525 if (!sign || size ) {
2526 MOVA(aopGet(AOP(left),offset,FALSE));
2528 if (sign && size == 0) {
2529 emitcode("ld", "a,%s", _fTmp[0]);
2530 emitcode("sbc", "a,%s", _fTmp[1]);
2533 /* Subtract through, propagating the carry */
2534 emitcode("sbc","a,%s ; 2",aopGet(AOP(right),offset++,FALSE));
2541 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2544 /* if the result is used in the next
2545 ifx conditional branch then generate
2546 code a little differently */
2548 genIfxJump (ifx,"c");
2551 /* leave the result in acc */
2555 /*-----------------------------------------------------------------*/
2556 /* genCmpGt :- greater than comparison */
2557 /*-----------------------------------------------------------------*/
2558 static void genCmpGt (iCode *ic, iCode *ifx)
2560 operand *left, *right, *result;
2561 link *letype , *retype;
2565 right= IC_RIGHT(ic);
2566 result = IC_RESULT(ic);
2568 letype = getSpec(operandType(left));
2569 retype =getSpec(operandType(right));
2570 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2571 /* assign the amsops */
2572 aopOp (left,ic,FALSE, FALSE);
2573 aopOp (right,ic,FALSE, FALSE);
2574 aopOp (result,ic,TRUE, FALSE);
2576 genCmp(right, left, result, ifx, sign);
2578 freeAsmop(left,NULL,ic);
2579 freeAsmop(right,NULL,ic);
2580 freeAsmop(result,NULL,ic);
2583 /*-----------------------------------------------------------------*/
2584 /* genCmpLt - less than comparisons */
2585 /*-----------------------------------------------------------------*/
2586 static void genCmpLt (iCode *ic, iCode *ifx)
2588 operand *left, *right, *result;
2589 link *letype , *retype;
2593 right= IC_RIGHT(ic);
2594 result = IC_RESULT(ic);
2596 letype = getSpec(operandType(left));
2597 retype =getSpec(operandType(right));
2598 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2600 /* assign the amsops */
2601 aopOp (left,ic,FALSE, FALSE);
2602 aopOp (right,ic,FALSE, FALSE);
2603 aopOp (result,ic,TRUE, FALSE);
2605 genCmp(left, right, result, ifx, sign);
2607 freeAsmop(left,NULL,ic);
2608 freeAsmop(right,NULL,ic);
2609 freeAsmop(result,NULL,ic);
2612 /*-----------------------------------------------------------------*/
2613 /* gencjneshort - compare and jump if not equal */
2614 /*-----------------------------------------------------------------*/
2615 static void gencjneshort(operand *left, operand *right, symbol *lbl)
2617 int size = max(AOP_SIZE(left),AOP_SIZE(right));
2619 unsigned long lit = 0L;
2621 /* Swap the left and right if it makes the computation easier */
2622 if (AOP_TYPE(left) == AOP_LIT) {
2628 if(AOP_TYPE(right) == AOP_LIT)
2629 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2631 /* if the right side is a literal then anything goes */
2632 if (AOP_TYPE(right) == AOP_LIT &&
2633 AOP_TYPE(left) != AOP_DIR ) {
2635 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2640 emitcode("or", "a,%s", aopGet(AOP(left), offset, FALSE));
2644 emitcode("or", "a,a");
2646 emit2("jp nz,!tlabel", lbl->key+100);
2650 emitcode("ld", "a,%s ; 2", aopGet(AOP(left),offset,FALSE));
2651 if ((AOP_TYPE(right) == AOP_LIT) && lit == 0)
2652 emitcode("or", "a,a");
2654 emitcode("cp", "a,%s", aopGet(AOP(right),offset,FALSE));
2655 emit2("jp nz,!tlabel", lbl->key+100);
2660 /* if the right side is in a register or in direct space or
2661 if the left is a pointer register & right is not */
2662 else if (AOP_TYPE(right) == AOP_REG ||
2663 AOP_TYPE(right) == AOP_DIR ||
2664 (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT)) {
2666 MOVA(aopGet(AOP(left),offset,FALSE));
2667 if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
2668 ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
2670 emit2("jp nz,!tlabel", lbl->key+100);
2672 emitcode("cp", "%s ; 4", aopGet(AOP(right),offset,FALSE));
2673 emit2("jp nz,!tlabel", lbl->key+100);
2678 /* right is a pointer reg need both a & b */
2679 /* PENDING: is this required? */
2681 MOVA(aopGet(AOP(right),offset,FALSE));
2682 emitcode("cp", "%s ; 5", aopGet(AOP(left), offset, FALSE));
2683 emit2("!shortjp nz,!tlabel", lbl->key+100);
2689 /*-----------------------------------------------------------------*/
2690 /* gencjne - compare and jump if not equal */
2691 /*-----------------------------------------------------------------*/
2692 static void gencjne(operand *left, operand *right, symbol *lbl)
2694 symbol *tlbl = newiTempLabel(NULL);
2696 gencjneshort(left, right, lbl);
2700 emit2("!shortjp !tlabel", tlbl->key+100);
2701 emitLabel(lbl->key+100);
2702 emitcode("xor","a,a");
2703 emitLabel(tlbl->key+100);
2706 /*-----------------------------------------------------------------*/
2707 /* genCmpEq - generates code for equal to */
2708 /*-----------------------------------------------------------------*/
2709 static void genCmpEq (iCode *ic, iCode *ifx)
2711 operand *left, *right, *result;
2713 aopOp((left=IC_LEFT(ic)),ic,FALSE, FALSE);
2714 aopOp((right=IC_RIGHT(ic)),ic,FALSE, FALSE);
2715 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2717 /* Swap operands if it makes the operation easier. ie if:
2718 1. Left is a literal.
2720 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
2721 operand *t = IC_RIGHT(ic);
2722 IC_RIGHT(ic) = IC_LEFT(ic);
2726 if (ifx && !AOP_SIZE(result)){
2728 /* if they are both bit variables */
2729 if (AOP_TYPE(left) == AOP_CRY &&
2730 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2733 tlbl = newiTempLabel(NULL);
2734 gencjneshort(left, right, tlbl);
2735 if ( IC_TRUE(ifx) ) {
2736 emit2("jp !tlabel", IC_TRUE(ifx)->key+100);
2737 emitLabel(tlbl->key+100);
2739 /* PENDING: do this better */
2740 symbol *lbl = newiTempLabel(NULL);
2741 emit2("!shortjp !tlabel", lbl->key+100);
2742 emitLabel(tlbl->key+100);
2743 emit2("jp !tlabel", IC_FALSE(ifx)->key+100);
2744 emitLabel(lbl->key+100);
2747 /* mark the icode as generated */
2752 /* if they are both bit variables */
2753 if (AOP_TYPE(left) == AOP_CRY &&
2754 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2757 gencjne(left,right,newiTempLabel(NULL));
2758 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2762 genIfxJump(ifx,"a");
2765 /* if the result is used in an arithmetic operation
2766 then put the result in place */
2767 if (AOP_TYPE(result) != AOP_CRY) {
2770 /* leave the result in acc */
2774 freeAsmop(left,NULL,ic);
2775 freeAsmop(right,NULL,ic);
2776 freeAsmop(result,NULL,ic);
2779 /*-----------------------------------------------------------------*/
2780 /* ifxForOp - returns the icode containing the ifx for operand */
2781 /*-----------------------------------------------------------------*/
2782 static iCode *ifxForOp ( operand *op, iCode *ic )
2784 /* if true symbol then needs to be assigned */
2785 if (IS_TRUE_SYMOP(op))
2788 /* if this has register type condition and
2789 the next instruction is ifx with the same operand
2790 and live to of the operand is upto the ifx only then */
2792 ic->next->op == IFX &&
2793 IC_COND(ic->next)->key == op->key &&
2794 OP_SYMBOL(op)->liveTo <= ic->next->seq )
2800 /*-----------------------------------------------------------------*/
2801 /* genAndOp - for && operation */
2802 /*-----------------------------------------------------------------*/
2803 static void genAndOp (iCode *ic)
2805 operand *left,*right, *result;
2808 /* note here that && operations that are in an if statement are
2809 taken away by backPatchLabels only those used in arthmetic
2810 operations remain */
2811 aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2812 aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2813 aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2815 /* if both are bit variables */
2816 if (AOP_TYPE(left) == AOP_CRY &&
2817 AOP_TYPE(right) == AOP_CRY ) {
2820 tlbl = newiTempLabel(NULL);
2822 emit2("!shortjp z,!tlabel", tlbl->key+100);
2824 emitLabel(tlbl->key+100);
2828 freeAsmop(left,NULL,ic);
2829 freeAsmop(right,NULL,ic);
2830 freeAsmop(result,NULL,ic);
2833 /*-----------------------------------------------------------------*/
2834 /* genOrOp - for || operation */
2835 /*-----------------------------------------------------------------*/
2836 static void genOrOp (iCode *ic)
2838 operand *left,*right, *result;
2841 /* note here that || operations that are in an
2842 if statement are taken away by backPatchLabels
2843 only those used in arthmetic operations remain */
2844 aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2845 aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2846 aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2848 /* if both are bit variables */
2849 if (AOP_TYPE(left) == AOP_CRY &&
2850 AOP_TYPE(right) == AOP_CRY ) {
2853 tlbl = newiTempLabel(NULL);
2855 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2857 emitLabel(tlbl->key+100);
2861 freeAsmop(left,NULL,ic);
2862 freeAsmop(right,NULL,ic);
2863 freeAsmop(result,NULL,ic);
2866 /*-----------------------------------------------------------------*/
2867 /* isLiteralBit - test if lit == 2^n */
2868 /*-----------------------------------------------------------------*/
2869 int isLiteralBit(unsigned long lit)
2871 unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
2872 0x100L,0x200L,0x400L,0x800L,
2873 0x1000L,0x2000L,0x4000L,0x8000L,
2874 0x10000L,0x20000L,0x40000L,0x80000L,
2875 0x100000L,0x200000L,0x400000L,0x800000L,
2876 0x1000000L,0x2000000L,0x4000000L,0x8000000L,
2877 0x10000000L,0x20000000L,0x40000000L,0x80000000L};
2880 for(idx = 0; idx < 32; idx++)
2886 /*-----------------------------------------------------------------*/
2887 /* jmpTrueOrFalse - */
2888 /*-----------------------------------------------------------------*/
2889 static void jmpTrueOrFalse (iCode *ic, symbol *tlbl)
2891 // ugly but optimized by peephole
2893 symbol *nlbl = newiTempLabel(NULL);
2894 emit2("jp !tlabel", nlbl->key+100);
2895 emitLabel(tlbl->key+100);
2896 emit2("jp !tlabel", IC_TRUE(ic)->key+100);
2897 emitLabel(nlbl->key+100);
2900 emit2("jp !tlabel", IC_FALSE(ic)->key+100);
2901 emitLabel(tlbl->key+100);
2906 /*-----------------------------------------------------------------*/
2907 /* genAnd - code for and */
2908 /*-----------------------------------------------------------------*/
2909 static void genAnd (iCode *ic, iCode *ifx)
2911 operand *left, *right, *result;
2913 unsigned long lit = 0L;
2916 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
2917 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
2918 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2921 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2923 AOP_TYPE(left), AOP_TYPE(right));
2924 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2926 AOP_SIZE(left), AOP_SIZE(right));
2929 /* if left is a literal & right is not then exchange them */
2930 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2931 AOP_NEEDSACC(left)) {
2932 operand *tmp = right ;
2937 /* if result = right then exchange them */
2938 if(sameRegs(AOP(result),AOP(right))){
2939 operand *tmp = right ;
2944 /* if right is bit then exchange them */
2945 if (AOP_TYPE(right) == AOP_CRY &&
2946 AOP_TYPE(left) != AOP_CRY){
2947 operand *tmp = right ;
2951 if(AOP_TYPE(right) == AOP_LIT)
2952 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2954 size = AOP_SIZE(result);
2956 if (AOP_TYPE(left) == AOP_CRY){
2961 // if(val & 0xZZ) - size = 0, ifx != FALSE -
2962 // bit = val & 0xZZ - size = 1, ifx = FALSE -
2963 if((AOP_TYPE(right) == AOP_LIT) &&
2964 (AOP_TYPE(result) == AOP_CRY) &&
2965 (AOP_TYPE(left) != AOP_CRY)) {
2966 int posbit = isLiteralBit(lit);
2970 MOVA(aopGet(AOP(left),posbit>>3,FALSE));
2974 emitcode("mov","c,acc.%d",posbit&0x07);
2979 sprintf(buffer, "%d", posbit&0x07);
2980 genIfxJump(ifx, buffer);
2988 symbol *tlbl = newiTempLabel(NULL);
2989 int sizel = AOP_SIZE(left);
2992 emitcode("setb","c");
2995 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
2996 MOVA( aopGet(AOP(left),offset,FALSE));
2998 if((posbit = isLiteralBit(bytelit)) != 0) {
3000 emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
3003 if(bytelit != 0x0FFL)
3004 emitcode("and","a,%s",
3005 aopGet(AOP(right),offset,FALSE));
3009 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3014 // bit = left & literal
3016 emitcode("clr","c");
3017 emit2("!tlabeldef", tlbl->key+100);
3019 // if(left & literal)
3022 jmpTrueOrFalse(ifx, tlbl);
3030 /* if left is same as result */
3031 if(sameRegs(AOP(result),AOP(left))){
3032 for(;size--; offset++) {
3033 if(AOP_TYPE(right) == AOP_LIT){
3034 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
3038 aopPut(AOP(result),zero,offset);
3040 MOVA(aopGet(AOP(left),offset,FALSE));
3041 emitcode("and","a,%s",
3042 aopGet(AOP(right),offset,FALSE));
3043 aopPut(AOP(left), "a", offset);
3048 if (AOP_TYPE(left) == AOP_ACC) {
3052 MOVA(aopGet(AOP(left),offset,FALSE));
3053 emitcode("and","a,%s",
3054 aopGet(AOP(right),offset,FALSE));
3055 aopPut(AOP(left), "a", offset);
3060 // left & result in different registers
3061 if(AOP_TYPE(result) == AOP_CRY){
3064 for(;(size--);offset++) {
3066 // result = left & right
3067 if(AOP_TYPE(right) == AOP_LIT){
3068 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
3070 aopGet(AOP(left),offset,FALSE),
3073 } else if(bytelit == 0){
3074 aopPut(AOP(result),zero,offset);
3078 // faster than result <- left, anl result,right
3079 // and better if result is SFR
3080 if (AOP_TYPE(left) == AOP_ACC)
3081 emitcode("and","a,%s",aopGet(AOP(right),offset,FALSE));
3083 MOVA(aopGet(AOP(left),offset,FALSE));
3084 emitcode("and","a,%s",
3085 aopGet(AOP(right),offset,FALSE));
3087 aopPut(AOP(result),"a",offset);
3094 freeAsmop(left,NULL,ic);
3095 freeAsmop(right,NULL,ic);
3096 freeAsmop(result,NULL,ic);
3099 /*-----------------------------------------------------------------*/
3100 /* genOr - code for or */
3101 /*-----------------------------------------------------------------*/
3102 static void genOr (iCode *ic, iCode *ifx)
3104 operand *left, *right, *result;
3106 unsigned long lit = 0L;
3108 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3109 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3110 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3113 emitcode("","; Type res[%d] = l[%d]&r[%d]",
3115 AOP_TYPE(left), AOP_TYPE(right));
3116 emitcode("","; Size res[%d] = l[%d]&r[%d]",
3118 AOP_SIZE(left), AOP_SIZE(right));
3121 /* if left is a literal & right is not then exchange them */
3122 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3123 AOP_NEEDSACC(left)) {
3124 operand *tmp = right ;
3129 /* if result = right then exchange them */
3130 if(sameRegs(AOP(result),AOP(right))){
3131 operand *tmp = right ;
3136 /* if right is bit then exchange them */
3137 if (AOP_TYPE(right) == AOP_CRY &&
3138 AOP_TYPE(left) != AOP_CRY){
3139 operand *tmp = right ;
3143 if(AOP_TYPE(right) == AOP_LIT)
3144 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3146 size = AOP_SIZE(result);
3148 if (AOP_TYPE(left) == AOP_CRY){
3153 if((AOP_TYPE(right) == AOP_LIT) &&
3154 (AOP_TYPE(result) == AOP_CRY) &&
3155 (AOP_TYPE(left) != AOP_CRY)){
3160 /* if left is same as result */
3161 if(sameRegs(AOP(result),AOP(left))){
3162 for(;size--; offset++) {
3163 if(AOP_TYPE(right) == AOP_LIT){
3164 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3167 MOVA(aopGet(AOP(left),offset,FALSE));
3168 emitcode("or","a,%s",
3169 aopGet(AOP(right),offset,FALSE));
3170 aopPut(AOP(result),"a", offset);
3173 if (AOP_TYPE(left) == AOP_ACC)
3174 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
3176 MOVA(aopGet(AOP(left),offset,FALSE));
3177 emitcode("or","a,%s",
3178 aopGet(AOP(right),offset,FALSE));
3179 aopPut(AOP(result),"a", offset);
3184 // left & result in different registers
3185 if(AOP_TYPE(result) == AOP_CRY){
3187 } else for(;(size--);offset++){
3189 // result = left & right
3190 if(AOP_TYPE(right) == AOP_LIT){
3191 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3193 aopGet(AOP(left),offset,FALSE),
3198 // faster than result <- left, anl result,right
3199 // and better if result is SFR
3200 if (AOP_TYPE(left) == AOP_ACC)
3201 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
3203 MOVA(aopGet(AOP(left),offset,FALSE));
3204 emitcode("or","a,%s",
3205 aopGet(AOP(right),offset,FALSE));
3207 aopPut(AOP(result),"a",offset);
3208 /* PENDING: something weird is going on here. Add exception. */
3209 if (AOP_TYPE(result) == AOP_ACC)
3215 freeAsmop(left,NULL,ic);
3216 freeAsmop(right,NULL,ic);
3217 freeAsmop(result,NULL,ic);
3220 /*-----------------------------------------------------------------*/
3221 /* genXor - code for xclusive or */
3222 /*-----------------------------------------------------------------*/
3223 static void genXor (iCode *ic, iCode *ifx)
3225 operand *left, *right, *result;
3227 unsigned long lit = 0L;
3229 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3230 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3231 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3233 /* if left is a literal & right is not then exchange them */
3234 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3235 AOP_NEEDSACC(left)) {
3236 operand *tmp = right ;
3241 /* if result = right then exchange them */
3242 if(sameRegs(AOP(result),AOP(right))){
3243 operand *tmp = right ;
3248 /* if right is bit then exchange them */
3249 if (AOP_TYPE(right) == AOP_CRY &&
3250 AOP_TYPE(left) != AOP_CRY){
3251 operand *tmp = right ;
3255 if(AOP_TYPE(right) == AOP_LIT)
3256 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3258 size = AOP_SIZE(result);
3260 if (AOP_TYPE(left) == AOP_CRY){
3265 if((AOP_TYPE(right) == AOP_LIT) &&
3266 (AOP_TYPE(result) == AOP_CRY) &&
3267 (AOP_TYPE(left) != AOP_CRY)){
3272 /* if left is same as result */
3273 if(sameRegs(AOP(result),AOP(left))){
3274 for(;size--; offset++) {
3275 if(AOP_TYPE(right) == AOP_LIT){
3276 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3279 MOVA(aopGet(AOP(right),offset,FALSE));
3280 emitcode("xor","a,%s",
3281 aopGet(AOP(left),offset,FALSE));
3282 aopPut(AOP(result),"a",0);
3285 if (AOP_TYPE(left) == AOP_ACC)
3286 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3288 MOVA(aopGet(AOP(right),offset,FALSE));
3289 emitcode("xor","a,%s",
3290 aopGet(AOP(left),offset,FALSE));
3291 aopPut(AOP(result),"a",0);
3296 // left & result in different registers
3297 if(AOP_TYPE(result) == AOP_CRY){
3299 } else for(;(size--);offset++){
3301 // result = left & right
3302 if(AOP_TYPE(right) == AOP_LIT){
3303 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3305 aopGet(AOP(left),offset,FALSE),
3310 // faster than result <- left, anl result,right
3311 // and better if result is SFR
3312 if (AOP_TYPE(left) == AOP_ACC)
3313 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3315 MOVA(aopGet(AOP(right),offset,FALSE));
3316 emitcode("xor","a,%s",
3317 aopGet(AOP(left),offset,FALSE));
3318 aopPut(AOP(result),"a",0);
3320 aopPut(AOP(result),"a",offset);
3325 freeAsmop(left,NULL,ic);
3326 freeAsmop(right,NULL,ic);
3327 freeAsmop(result,NULL,ic);
3330 /*-----------------------------------------------------------------*/
3331 /* genInline - write the inline code out */
3332 /*-----------------------------------------------------------------*/
3333 static void genInline (iCode *ic)
3335 char buffer[MAX_INLINEASM];
3339 inLine += (!options.asmpeep);
3340 strcpy(buffer,IC_INLINE(ic));
3342 /* emit each line as a code */
3361 /* emitcode("",buffer); */
3362 inLine -= (!options.asmpeep);
3365 /*-----------------------------------------------------------------*/
3366 /* genRRC - rotate right with carry */
3367 /*-----------------------------------------------------------------*/
3368 static void genRRC (iCode *ic)
3373 /*-----------------------------------------------------------------*/
3374 /* genRLC - generate code for rotate left with carry */
3375 /*-----------------------------------------------------------------*/
3376 static void genRLC (iCode *ic)
3381 /*-----------------------------------------------------------------*/
3382 /* shiftR2Left2Result - shift right two bytes from left to result */
3383 /*-----------------------------------------------------------------*/
3384 static void shiftR2Left2Result (operand *left, int offl,
3385 operand *result, int offr,
3386 int shCount, int sign)
3388 movLeft2Result(left, offl, result, offr, 0);
3389 movLeft2Result(left, offl+1, result, offr+1, 0);
3395 /* if (AOP(result)->type == AOP_REG) {*/
3398 symbol *tlbl , *tlbl1;
3401 tlbl = newiTempLabel(NULL);
3402 tlbl1 = newiTempLabel(NULL);
3404 /* Left is already in result - so now do the shift */
3406 emit2("ld a,!immedbyte+1", shCount);
3407 emit2("!shortjp !tlabel", tlbl1->key+100);
3408 emitLabel(tlbl->key+100);
3411 emitcode("or", "a,a");
3414 l = aopGet(AOP(result), --offset, FALSE);
3415 emitcode("rr","%s", l);
3418 emitLabel(tlbl1->key+100);
3419 emitcode("dec", "a");
3420 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3425 /*-----------------------------------------------------------------*/
3426 /* shiftL2Left2Result - shift left two bytes from left to result */
3427 /*-----------------------------------------------------------------*/
3428 static void shiftL2Left2Result (operand *left, int offl,
3429 operand *result, int offr, int shCount)
3431 if(sameRegs(AOP(result), AOP(left)) &&
3432 ((offl + MSB16) == offr)){
3435 /* Copy left into result */
3436 movLeft2Result(left, offl, result, offr, 0);
3437 movLeft2Result(left, offl+1, result, offr+1, 0);
3439 /* PENDING: for now just see if it'll work. */
3440 /*if (AOP(result)->type == AOP_REG) { */
3444 symbol *tlbl , *tlbl1;
3447 tlbl = newiTempLabel(NULL);
3448 tlbl1 = newiTempLabel(NULL);
3450 /* Left is already in result - so now do the shift */
3452 emit2("ld a,!immedbyte+1", shCount);
3453 emit2("!shortjp !tlabel", tlbl1->key+100);
3454 emitLabel(tlbl->key+100);
3457 emitcode("or", "a,a");
3459 l = aopGet(AOP(result),offset++,FALSE);
3460 emitcode("rl","%s", l);
3463 emitLabel(tlbl1->key+100);
3464 emitcode("dec", "a");
3465 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3470 /*-----------------------------------------------------------------*/
3471 /* AccRol - rotate left accumulator by known count */
3472 /*-----------------------------------------------------------------*/
3473 static void AccRol (int shCount)
3475 shCount &= 0x0007; // shCount : 0..7
3512 /*-----------------------------------------------------------------*/
3513 /* AccLsh - left shift accumulator by known count */
3514 /*-----------------------------------------------------------------*/
3515 static void AccLsh (int shCount)
3519 emitcode("add","a,a");
3521 else if(shCount == 2) {
3522 emitcode("add","a,a");
3523 emitcode("add","a,a");
3525 /* rotate left accumulator */
3527 /* and kill the lower order bits */
3528 emit2("and a,!immedbyte", SLMask[shCount]);
3533 /*-----------------------------------------------------------------*/
3534 /* shiftL1Left2Result - shift left one byte from left to result */
3535 /*-----------------------------------------------------------------*/
3536 static void shiftL1Left2Result (operand *left, int offl,
3537 operand *result, int offr, int shCount)
3540 l = aopGet(AOP(left),offl,FALSE);
3542 /* shift left accumulator */
3544 aopPut(AOP(result),"a",offr);
3548 /*-----------------------------------------------------------------*/
3549 /* genlshTwo - left shift two bytes by known amount != 0 */
3550 /*-----------------------------------------------------------------*/
3551 static void genlshTwo (operand *result,operand *left, int shCount)
3553 int size = AOP_SIZE(result);
3557 /* if shCount >= 8 */
3562 movLeft2Result(left, LSB, result, MSB16, 0);
3563 aopPut(AOP(result),zero, 0);
3564 shiftL1Left2Result(left, MSB16, result, MSB16, shCount);
3567 movLeft2Result(left, LSB, result, MSB16, 0);
3568 aopPut(AOP(result),zero, 0);
3572 aopPut(AOP(result),zero,LSB);
3575 /* 1 <= shCount <= 7 */
3581 shiftL2Left2Result(left, LSB, result, LSB, shCount);
3586 /*-----------------------------------------------------------------*/
3587 /* genlshOne - left shift a one byte quantity by known count */
3588 /*-----------------------------------------------------------------*/
3589 static void genlshOne (operand *result, operand *left, int shCount)
3591 shiftL1Left2Result(left, LSB, result, LSB, shCount);
3594 /*-----------------------------------------------------------------*/
3595 /* genLeftShiftLiteral - left shifting by known count */
3596 /*-----------------------------------------------------------------*/
3597 static void genLeftShiftLiteral (operand *left,
3602 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3605 freeAsmop(right,NULL,ic);
3607 aopOp(left,ic,FALSE, FALSE);
3608 aopOp(result,ic,FALSE, FALSE);
3610 size = getSize(operandType(result));
3613 emitcode("; shift left ","result %d, left %d",size,
3617 /* I suppose that the left size >= result size */
3622 else if(shCount >= (size * 8))
3624 aopPut(AOP(result),zero,size);
3628 genlshOne (result,left,shCount);
3631 genlshTwo (result,left,shCount);
3640 freeAsmop(left,NULL,ic);
3641 freeAsmop(result,NULL,ic);
3644 /*-----------------------------------------------------------------*/
3645 /* genLeftShift - generates code for left shifting */
3646 /*-----------------------------------------------------------------*/
3647 static void genLeftShift (iCode *ic)
3651 symbol *tlbl , *tlbl1;
3652 operand *left,*right, *result;
3654 right = IC_RIGHT(ic);
3656 result = IC_RESULT(ic);
3658 aopOp(right,ic,FALSE, FALSE);
3660 /* if the shift count is known then do it
3661 as efficiently as possible */
3662 if (AOP_TYPE(right) == AOP_LIT) {
3663 genLeftShiftLiteral (left,right,result,ic);
3667 /* shift count is unknown then we have to form a loop get the loop
3668 count in B : Note: we take only the lower order byte since
3669 shifting more that 32 bits make no sense anyway, ( the largest
3670 size of an object can be only 32 bits ) */
3671 emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE));
3672 emitcode("inc","a");
3673 freeAsmop (right,NULL,ic);
3674 aopOp(left,ic,FALSE, FALSE);
3675 aopOp(result,ic,FALSE, FALSE);
3677 /* now move the left to the result if they are not the
3680 if (!sameRegs(AOP(left),AOP(result))) {
3682 size = AOP_SIZE(result);
3685 l = aopGet(AOP(left),offset,FALSE);
3686 aopPut(AOP(result),l,offset);
3691 size = AOP_SIZE(result);
3694 l = aopGet(AOP(left),offset,FALSE);
3695 aopPut(AOP(result),l,offset);
3701 tlbl = newiTempLabel(NULL);
3702 size = AOP_SIZE(result);
3704 tlbl1 = newiTempLabel(NULL);
3706 emit2("!shortjp !tlabel", tlbl1->key+100);
3707 emitLabel(tlbl->key+100);
3708 l = aopGet(AOP(result),offset,FALSE);
3709 emitcode("or", "a,a");
3711 l = aopGet(AOP(result),offset++,FALSE);
3712 emitcode("rl","%s", l);
3714 emitLabel(tlbl1->key+100);
3715 emitcode("dec", "a");
3716 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3718 freeAsmop(left,NULL,ic);
3719 freeAsmop(result,NULL,ic);
3722 /*-----------------------------------------------------------------*/
3723 /* genrshOne - left shift two bytes by known amount != 0 */
3724 /*-----------------------------------------------------------------*/
3725 static void genrshOne (operand *result,operand *left, int shCount)
3728 int size = AOP_SIZE(result);
3734 l = aopGet(AOP(left),0,FALSE);
3735 if (AOP(result)->type == AOP_REG) {
3736 aopPut(AOP(result), l, 0);
3737 l = aopGet(AOP(result), 0, FALSE);
3739 emitcode("srl", "%s", l);
3744 emitcode("srl", "a");
3746 aopPut(AOP(result),"a",0);
3750 /*-----------------------------------------------------------------*/
3751 /* AccRsh - right shift accumulator by known count */
3752 /*-----------------------------------------------------------------*/
3753 static void AccRsh (int shCount)
3756 /* rotate right accumulator */
3757 AccRol(8 - shCount);
3758 /* and kill the higher order bits */
3759 emit2("and a,!immedbyte", SRMask[shCount]);
3763 /*-----------------------------------------------------------------*/
3764 /* shiftR1Left2Result - shift right one byte from left to result */
3765 /*-----------------------------------------------------------------*/
3766 static void shiftR1Left2Result (operand *left, int offl,
3767 operand *result, int offr,
3768 int shCount, int sign)
3770 MOVA(aopGet(AOP(left),offl,FALSE));
3777 aopPut(AOP(result),"a",offr);
3780 /*-----------------------------------------------------------------*/
3781 /* genrshTwo - right shift two bytes by known amount != 0 */
3782 /*-----------------------------------------------------------------*/
3783 static void genrshTwo (operand *result,operand *left,
3784 int shCount, int sign)
3786 /* if shCount >= 8 */
3790 shiftR1Left2Result(left, MSB16, result, LSB,
3794 movLeft2Result(left, MSB16, result, LSB, sign);
3796 aopPut(AOP(result),zero,1);
3798 /* 1 <= shCount <= 7 */
3800 shiftR2Left2Result(left, LSB, result, LSB, shCount, sign);
3804 /*-----------------------------------------------------------------*/
3805 /* genRightShiftLiteral - left shifting by known count */
3806 /*-----------------------------------------------------------------*/
3807 static void genRightShiftLiteral (operand *left,
3812 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3815 freeAsmop(right,NULL,ic);
3817 aopOp(left,ic,FALSE, FALSE);
3818 aopOp(result,ic,FALSE, FALSE);
3820 size = getSize(operandType(result));
3822 emitcode("; shift right ","result %d, left %d",size,
3825 /* I suppose that the left size >= result size */
3830 else if(shCount >= (size * 8))
3832 aopPut(AOP(result),zero,size);
3836 genrshOne(result, left, shCount);
3839 /* PENDING: sign support */
3840 genrshTwo(result, left, shCount, FALSE);
3849 freeAsmop(left,NULL,ic);
3850 freeAsmop(result,NULL,ic);
3853 /*-----------------------------------------------------------------*/
3854 /* genRightShift - generate code for right shifting */
3855 /*-----------------------------------------------------------------*/
3856 static void genRightShift (iCode *ic)
3858 operand *right, *left, *result;
3860 int size, offset, first = 1;
3864 symbol *tlbl, *tlbl1 ;
3866 /* if signed then we do it the hard way preserve the
3867 sign bit moving it inwards */
3868 retype = getSpec(operandType(IC_RESULT(ic)));
3870 is_signed = !SPEC_USIGN(retype);
3872 /* signed & unsigned types are treated the same : i.e. the
3873 signed is NOT propagated inwards : quoting from the
3874 ANSI - standard : "for E1 >> E2, is equivalent to division
3875 by 2**E2 if unsigned or if it has a non-negative value,
3876 otherwise the result is implementation defined ", MY definition
3877 is that the sign does not get propagated */
3879 right = IC_RIGHT(ic);
3881 result = IC_RESULT(ic);
3883 aopOp(right,ic,FALSE, FALSE);
3885 /* if the shift count is known then do it
3886 as efficiently as possible */
3887 if (AOP_TYPE(right) == AOP_LIT) {
3888 genRightShiftLiteral(left,right,result,ic);
3892 aopOp(left,ic,FALSE, FALSE);
3893 aopOp(result,ic,FALSE, FALSE);
3895 /* now move the left to the result if they are not the
3897 if (!sameRegs(AOP(left),AOP(result)) &&
3898 AOP_SIZE(result) > 1) {
3900 size = AOP_SIZE(result);
3903 l = aopGet(AOP(left),offset,FALSE);
3904 aopPut(AOP(result),l,offset);
3909 emitcode("ld", "a,%s",aopGet(AOP(right),0,FALSE));
3910 emitcode("inc","a");
3911 freeAsmop (right, NULL, ic);
3913 tlbl = newiTempLabel(NULL);
3914 tlbl1= newiTempLabel(NULL);
3915 size = AOP_SIZE(result);
3918 emit2("!shortjp !tlabel", tlbl1->key+100);
3919 emitLabel(tlbl->key+100);
3921 l = aopGet(AOP(result),offset--,FALSE);
3924 emitcode("sra", "%s", l);
3926 emitcode("srl", "%s", l);
3930 emitcode("rr", "%s", l);
3932 emitLabel(tlbl1->key+100);
3933 emitcode("dec", "a");
3934 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3936 freeAsmop(left,NULL,ic);
3937 freeAsmop(result,NULL,ic);
3940 /*-----------------------------------------------------------------*/
3941 /* genGenPointerGet - get value from generic pointer space */
3942 /*-----------------------------------------------------------------*/
3943 static void genGenPointerGet (operand *left,
3944 operand *result, iCode *ic)
3947 link *retype = getSpec(operandType(result));
3953 aopOp(left,ic,FALSE, FALSE);
3954 aopOp(result,ic,FALSE, FALSE);
3956 if (isPair(AOP(left)) && AOP_SIZE(result)==1) {
3958 if (isPtrPair(AOP(left)))
3960 tsprintf(buffer, "!*pair", getPairName(AOP(left)));
3961 aopPut(AOP(result), buffer, 0);
3964 emit2("ld a,!*pair", getPairName(AOP(left)));
3965 aopPut(AOP(result),"a", 0);
3967 freeAsmop(left,NULL,ic);
3971 /* For now we always load into IY */
3972 /* if this is remateriazable */
3973 fetchPair(pair, AOP(left));
3975 /* so iy now contains the address */
3976 freeAsmop(left,NULL,ic);
3978 /* if bit then unpack */
3979 if (IS_BITVAR(retype)) {
3983 size = AOP_SIZE(result);
3987 /* PENDING: make this better */
3988 if (!IS_GB && AOP(result)->type == AOP_REG) {
3989 aopPut(AOP(result), "!*hl", offset++);
3992 emit2("ld a,!*pair", _pairs[pair].name);
3993 aopPut(AOP(result),"a",offset++);
3996 emit2("inc %s", _pairs[pair].name);
4002 freeAsmop(result,NULL,ic);
4005 /*-----------------------------------------------------------------*/
4006 /* genPointerGet - generate code for pointer get */
4007 /*-----------------------------------------------------------------*/
4008 static void genPointerGet (iCode *ic)
4010 operand *left, *result ;
4014 result = IC_RESULT(ic) ;
4016 /* depending on the type of pointer we need to
4017 move it to the correct pointer register */
4018 type = operandType(left);
4019 etype = getSpec(type);
4021 genGenPointerGet (left,result,ic);
4024 bool isRegOrLit(asmop *aop)
4026 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
4031 /*-----------------------------------------------------------------*/
4032 /* genGenPointerSet - stores the value into a pointer location */
4033 /*-----------------------------------------------------------------*/
4034 static void genGenPointerSet (operand *right,
4035 operand *result, iCode *ic)
4038 link *retype = getSpec(operandType(right));
4039 PAIR_ID pairId = PAIR_HL;
4041 aopOp(result,ic,FALSE, FALSE);
4042 aopOp(right,ic,FALSE, FALSE);
4047 /* Handle the exceptions first */
4048 if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
4050 char *l = aopGet(AOP(right), 0, FALSE);
4051 const char *pair = getPairName(AOP(result));
4052 if (canAssignToPtr(l) && isPtr(pair)) {
4053 emit2("ld !*pair,%s", pair, l);
4057 emit2("ld !*pair,a", pair);
4062 /* if the operand is already in dptr
4063 then we do nothing else we move the value to dptr */
4064 if (AOP_TYPE(result) != AOP_STR) {
4065 fetchPair(pairId, AOP(result));
4067 /* so hl know contains the address */
4068 freeAsmop(result,NULL,ic);
4070 /* if bit then unpack */
4071 if (IS_BITVAR(retype)) {
4075 size = AOP_SIZE(right);
4079 char *l = aopGet(AOP(right),offset,FALSE);
4080 if (isRegOrLit(AOP(right)) && !IS_GB) {
4081 emit2("ld !*pair,%s", _pairs[pairId].name, l);
4085 emit2("ld !*pair,a", _pairs[pairId].name);
4088 emitcode("inc", _pairs[pairId].name);
4094 freeAsmop(right,NULL,ic);
4097 /*-----------------------------------------------------------------*/
4098 /* genPointerSet - stores the value into a pointer location */
4099 /*-----------------------------------------------------------------*/
4100 static void genPointerSet (iCode *ic)
4102 operand *right, *result ;
4105 right = IC_RIGHT(ic);
4106 result = IC_RESULT(ic) ;
4108 /* depending on the type of pointer we need to
4109 move it to the correct pointer register */
4110 type = operandType(result);
4111 etype = getSpec(type);
4113 genGenPointerSet (right,result,ic);
4116 /*-----------------------------------------------------------------*/
4117 /* genIfx - generate code for Ifx statement */
4118 /*-----------------------------------------------------------------*/
4119 static void genIfx (iCode *ic, iCode *popIc)
4121 operand *cond = IC_COND(ic);
4124 aopOp(cond,ic,FALSE, TRUE);
4126 /* get the value into acc */
4127 if (AOP_TYPE(cond) != AOP_CRY)
4131 /* the result is now in the accumulator */
4132 freeAsmop(cond,NULL,ic);
4134 /* if there was something to be popped then do it */
4138 /* if the condition is a bit variable */
4139 if (isbit && IS_ITEMP(cond) &&
4141 genIfxJump(ic,SPIL_LOC(cond)->rname);
4143 if (isbit && !IS_ITEMP(cond))
4144 genIfxJump(ic,OP_SYMBOL(cond)->rname);
4151 /*-----------------------------------------------------------------*/
4152 /* genAddrOf - generates code for address of */
4153 /*-----------------------------------------------------------------*/
4154 static void genAddrOf (iCode *ic)
4156 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
4158 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
4160 /* if the operand is on the stack then we
4161 need to get the stack offset of this
4166 if (sym->stack <= 0) {
4167 emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
4170 emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
4172 emitcode("ld", "d,h");
4173 emitcode("ld", "e,l");
4176 emit2("ld de,!hashedstr", sym->rname);
4178 aopPut(AOP(IC_RESULT(ic)), "e", 0);
4179 aopPut(AOP(IC_RESULT(ic)), "d", 1);
4184 /* if it has an offset then we need to compute it */
4185 emitcode("ld", "hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
4186 emitcode("add", "hl,sp");
4189 emitcode("ld", "hl,#%s", sym->rname);
4191 aopPut(AOP(IC_RESULT(ic)), "l", 0);
4192 aopPut(AOP(IC_RESULT(ic)), "h", 1);
4194 freeAsmop(IC_RESULT(ic),NULL,ic);
4197 /*-----------------------------------------------------------------*/
4198 /* genAssign - generate code for assignment */
4199 /*-----------------------------------------------------------------*/
4200 static void genAssign (iCode *ic)
4202 operand *result, *right;
4204 unsigned long lit = 0L;
4206 result = IC_RESULT(ic);
4207 right = IC_RIGHT(ic) ;
4210 /* Dont bother assigning if they are the same */
4211 if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) {
4212 emitcode("", "; (operands are equal %u)", operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)));
4217 aopOp(right,ic,FALSE, FALSE);
4218 aopOp(result,ic,TRUE, FALSE);
4220 /* if they are the same registers */
4221 if (sameRegs(AOP(right),AOP(result))) {
4222 emitcode("", "; (registers are the same)");
4226 /* if the result is a bit */
4227 if (AOP_TYPE(result) == AOP_CRY) {
4232 size = AOP_SIZE(result);
4235 if(AOP_TYPE(right) == AOP_LIT)
4236 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
4237 if (isPair(AOP(result))) {
4238 fetchPair(getPairId(AOP(result)), AOP(right));
4240 else if((size > 1) &&
4241 (AOP_TYPE(result) != AOP_REG) &&
4242 (AOP_TYPE(right) == AOP_LIT) &&
4243 !IS_FLOAT(operandType(right)) &&
4245 bool fXored = FALSE;
4247 /* Work from the top down.
4248 Done this way so that we can use the cached copy of 0
4249 in A for a fast clear */
4251 if((unsigned int)((lit >> (offset*8)) & 0x0FFL)== 0) {
4252 if (!fXored && size>1) {
4253 emitcode("xor", "a,a");
4257 aopPut(AOP(result),"a",offset);
4260 aopPut(AOP(result), zero, offset);
4265 aopGet(AOP(right),offset,FALSE),
4270 else if (size == 2 && requiresHL(AOP(right)) && requiresHL(AOP(result)) && IS_GB) {
4271 /* Special case. Load into a and d, then load out. */
4272 MOVA(aopGet(AOP(right), 0, FALSE));
4273 emitcode("ld", "e,%s", aopGet(AOP(right), 1, FALSE));
4274 aopPut(AOP(result), "a", 0);
4275 aopPut(AOP(result), "e", 1);
4278 /* PENDING: do this check better */
4279 if (requiresHL(AOP(right)) && requiresHL(AOP(result))) {
4280 MOVA(aopGet(AOP(right), offset, FALSE));
4281 aopPut(AOP(result), "a", offset);
4285 aopGet(AOP(right),offset,FALSE),
4292 freeAsmop(right,NULL,ic);
4293 freeAsmop(result,NULL,ic);
4296 /*-----------------------------------------------------------------*/
4297 /* genJumpTab - genrates code for jump table */
4298 /*-----------------------------------------------------------------*/
4299 static void genJumpTab (iCode *ic)
4304 aopOp(IC_JTCOND(ic),ic,FALSE, FALSE);
4305 /* get the condition into accumulator */
4306 l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE);
4308 emitcode("push", "de");
4309 emitcode("ld", "e,%s", l);
4310 emit2("ld d,!zero");
4311 jtab = newiTempLabel(NULL);
4313 emit2("ld hl,!immed!tlabel", jtab->key+100);
4314 emitcode("add", "hl,de");
4315 emitcode("add", "hl,de");
4316 emitcode("add", "hl,de");
4317 freeAsmop(IC_JTCOND(ic),NULL,ic);
4319 emitcode("pop", "de");
4321 emitLabel(jtab->key+100);
4322 /* now generate the jump labels */
4323 for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
4324 jtab = setNextItem(IC_JTLABELS(ic)))
4325 emit2("jp !tlabel", jtab->key+100);
4328 /*-----------------------------------------------------------------*/
4329 /* genCast - gen code for casting */
4330 /*-----------------------------------------------------------------*/
4331 static void genCast (iCode *ic)
4333 operand *result = IC_RESULT(ic);
4334 link *ctype = operandType(IC_LEFT(ic));
4335 operand *right = IC_RIGHT(ic);
4338 /* if they are equivalent then do nothing */
4339 if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
4342 aopOp(right,ic,FALSE, FALSE);
4343 aopOp(result,ic,FALSE, FALSE);
4345 /* if the result is a bit */
4346 if (AOP_TYPE(result) == AOP_CRY) {
4350 /* if they are the same size : or less */
4351 if (AOP_SIZE(result) <= AOP_SIZE(right)) {
4353 /* if they are in the same place */
4354 if (sameRegs(AOP(right),AOP(result)))
4357 /* if they in different places then copy */
4358 size = AOP_SIZE(result);
4362 aopGet(AOP(right),offset,FALSE),
4369 /* PENDING: should be OK. */
4371 /* if the result is of type pointer */
4372 if (IS_PTR(ctype)) {
4377 /* so we now know that the size of destination is greater
4378 than the size of the source */
4379 /* we move to result for the size of source */
4380 size = AOP_SIZE(right);
4384 aopGet(AOP(right),offset,FALSE),
4389 /* now depending on the sign of the destination */
4390 size = AOP_SIZE(result) - AOP_SIZE(right);
4391 /* Unsigned or not an integral type - right fill with zeros */
4392 if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) {
4394 aopPut(AOP(result),zero,offset++);
4396 /* we need to extend the sign :{ */
4397 char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
4400 emitcode("", "; genCast: sign extend untested.");
4401 emitcode("rla", "");
4402 emitcode("sbc", "a,a");
4404 aopPut(AOP(result),"a",offset++);
4408 freeAsmop(right, NULL, ic);
4409 freeAsmop(result, NULL, ic);
4412 /*-----------------------------------------------------------------*/
4413 /* genReceive - generate code for a receive iCode */
4414 /*-----------------------------------------------------------------*/
4415 static void genReceive (iCode *ic)
4417 if (isOperandInFarSpace(IC_RESULT(ic)) &&
4418 ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
4419 IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
4423 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
4425 assignResultValue(IC_RESULT(ic));
4428 freeAsmop(IC_RESULT(ic),NULL,ic);
4431 /*-----------------------------------------------------------------*/
4432 /* genZ80Code - generate code for Z80 based controllers */
4433 /*-----------------------------------------------------------------*/
4434 void genZ80Code (iCode *lic)
4441 _fReturn = _gbz80_return;
4442 _fTmp = _gbz80_return;
4445 _fReturn = _z80_return;
4446 _fTmp = _z80_return;
4448 tsprintf(zero, "!zero");
4450 lineHead = lineCurr = NULL;
4452 /* if debug information required */
4453 if (options.debug && currFunc) {
4454 cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
4456 if (IS_STATIC(currFunc->etype))
4457 emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name);
4459 emitcode("","G$%s$0$0 ==.",currFunc->name);
4462 /* stack pointer name */
4466 for (ic = lic ; ic ; ic = ic->next ) {
4468 if ( cln != ic->lineno ) {
4469 if ( options.debug ) {
4471 emitcode("","C$%s$%d$%d$%d ==.",
4472 ic->filename,ic->lineno,
4473 ic->level,ic->block);
4476 emitcode(";","%s %d",ic->filename,ic->lineno);
4479 /* if the result is marked as
4480 spilt and rematerializable or code for
4481 this has already been generated then
4483 if (resultRemat(ic) || ic->generated )
4486 /* depending on the operation */
4489 emitcode("", "; genNot");
4494 emitcode("", "; genCpl");
4499 emitcode("", "; genUminus");
4504 emitcode("", "; genIpush");
4509 /* IPOP happens only when trying to restore a
4510 spilt live range, if there is an ifx statement
4511 following this pop then the if statement might
4512 be using some of the registers being popped which
4513 would destory the contents of the register so
4514 we need to check for this condition and handle it */
4516 ic->next->op == IFX &&
4517 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) {
4518 emitcode("", "; genIfx");
4519 genIfx (ic->next,ic);
4522 emitcode("", "; genIpop");
4528 emitcode("", "; genCall");
4533 emitcode("", "; genPcall");
4538 emitcode("", "; genFunction");
4543 emitcode("", "; genEndFunction");
4544 genEndFunction (ic);
4548 emitcode("", "; genRet");
4553 emitcode("", "; genLabel");
4558 emitcode("", "; genGoto");
4563 emitcode("", "; genPlus");
4568 emitcode("", "; genMinus");
4573 emitcode("", "; genMult");
4578 emitcode("", "; genDiv");
4583 emitcode("", "; genMod");
4588 emitcode("", "; genCmpGt");
4589 genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));
4593 emitcode("", "; genCmpLt");
4594 genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
4601 /* note these two are xlated by algebraic equivalence
4602 during parsing SDCC.y */
4603 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
4604 "got '>=' or '<=' shouldn't have come here");
4608 emitcode("", "; genCmpEq");
4609 genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
4613 emitcode("", "; genAndOp");
4618 emitcode("", "; genOrOp");
4623 emitcode("", "; genXor");
4624 genXor (ic,ifxForOp(IC_RESULT(ic),ic));
4628 emitcode("", "; genOr");
4629 genOr (ic,ifxForOp(IC_RESULT(ic),ic));
4633 emitcode("", "; genAnd");
4634 genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
4638 emitcode("", "; genInline");
4643 emitcode("", "; genRRC");
4648 emitcode("", "; genRLC");
4653 emitcode("", "; genHBIT");
4657 emitcode("", "; genLeftShift");
4662 emitcode("", "; genRightShift");
4666 case GET_VALUE_AT_ADDRESS:
4667 emitcode("", "; genPointerGet");
4673 if (POINTER_SET(ic)) {
4674 emitcode("", "; genAssign (pointer)");
4678 emitcode("", "; genAssign");
4684 emitcode("", "; genIfx");
4689 emitcode("", "; genAddrOf");
4694 emitcode("", "; genJumpTab");
4699 emitcode("", "; genCast");
4704 emitcode("", "; genReceive");
4709 emitcode("", "; addSet");
4710 addSet(&sendSet,ic);
4715 /* piCode(ic,stdout); */
4721 /* now we are ready to call the
4722 peep hole optimizer */
4723 if (!options.nopeep)
4724 peepHole (&lineHead);
4726 /* now do the actual printing */
4727 printLine (lineHead,codeOutFile);