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(const 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(const char *s)
1056 /*-----------------------------------------------------------------*/
1057 /* aopPut - puts a string for a aop */
1058 /*-----------------------------------------------------------------*/
1059 static void aopPut (asmop *aop, const 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", 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 static void commitPair(asmop *aop, PAIR_ID id)
1192 if (id == PAIR_HL && requiresHL(aop)) {
1195 aopPut(aop, "a", 0);
1196 aopPut(aop, "d", 1);
1199 aopPut(aop, _pairs[id].l, 0);
1200 aopPut(aop, _pairs[id].h, 1);
1204 /*-----------------------------------------------------------------*/
1205 /* getDataSize - get the operand data size */
1206 /*-----------------------------------------------------------------*/
1207 int getDataSize(operand *op)
1210 size = AOP_SIZE(op);
1218 /*-----------------------------------------------------------------*/
1219 /* movLeft2Result - move byte from left to result */
1220 /*-----------------------------------------------------------------*/
1221 static void movLeft2Result (operand *left, int offl,
1222 operand *result, int offr, int sign)
1225 if(!sameRegs(AOP(left),AOP(result)) || (offl != offr)){
1226 l = aopGet(AOP(left),offl,FALSE);
1229 aopPut(AOP(result),l,offr);
1238 /** Put Acc into a register set
1240 void outAcc(operand *result)
1243 size = getDataSize(result);
1245 aopPut(AOP(result),"a",0);
1248 /* unsigned or positive */
1250 aopPut(AOP(result), zero, offset++);
1255 /** Take the value in carry and put it into a register
1257 void outBitC(operand *result)
1259 /* if the result is bit */
1260 if (AOP_TYPE(result) == AOP_CRY) {
1261 emitcode("", "; Note: outBitC form 1");
1262 aopPut(AOP(result),"blah",0);
1265 emit2("ld a,!zero");
1271 /*-----------------------------------------------------------------*/
1272 /* toBoolean - emit code for orl a,operator(sizeop) */
1273 /*-----------------------------------------------------------------*/
1274 void toBoolean(operand *oper)
1276 int size = AOP_SIZE(oper);
1279 emitcode("ld", "a,%s", aopGet(AOP(oper), offset++, FALSE));
1282 emitcode("or","a,%s",aopGet(AOP(oper),offset++,FALSE));
1285 if (AOP(oper)->type != AOP_ACC) {
1287 emitcode("or","a,%s",aopGet(AOP(oper),0,FALSE));
1292 /*-----------------------------------------------------------------*/
1293 /* genNot - generate code for ! operation */
1294 /*-----------------------------------------------------------------*/
1295 static void genNot (iCode *ic)
1297 link *optype = operandType(IC_LEFT(ic));
1299 /* assign asmOps to operand & result */
1300 aopOp (IC_LEFT(ic),ic,FALSE, TRUE);
1301 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1303 /* if in bit space then a special case */
1304 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) {
1308 /* if type float then do float */
1309 if (IS_FLOAT(optype)) {
1313 toBoolean(IC_LEFT(ic));
1318 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1319 emit2("sub a,!one");
1320 outBitC(IC_RESULT(ic));
1322 /* release the aops */
1323 freeAsmop(IC_LEFT(ic),NULL,ic);
1324 freeAsmop(IC_RESULT(ic),NULL,ic);
1327 /*-----------------------------------------------------------------*/
1328 /* genCpl - generate code for complement */
1329 /*-----------------------------------------------------------------*/
1330 static void genCpl (iCode *ic)
1336 /* assign asmOps to operand & result */
1337 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
1338 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1340 /* if both are in bit space then
1342 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1343 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1347 size = AOP_SIZE(IC_RESULT(ic));
1349 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1352 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1355 /* release the aops */
1356 freeAsmop(IC_LEFT(ic),NULL,ic);
1357 freeAsmop(IC_RESULT(ic),NULL,ic);
1360 /*-----------------------------------------------------------------*/
1361 /* genUminus - unary minus code generation */
1362 /*-----------------------------------------------------------------*/
1363 static void genUminus (iCode *ic)
1366 link *optype, *rtype;
1369 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1370 aopOp(IC_RESULT(ic),ic,TRUE, FALSE);
1372 /* if both in bit space then special
1374 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1375 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1380 optype = operandType(IC_LEFT(ic));
1381 rtype = operandType(IC_RESULT(ic));
1383 /* if float then do float stuff */
1384 if (IS_FLOAT(optype)) {
1389 /* otherwise subtract from zero */
1390 size = AOP_SIZE(IC_LEFT(ic));
1394 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1395 emit2("ld a,!zero");
1396 emit2("sbc a,%s",l);
1397 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1400 /* if any remaining bytes in the result */
1401 /* we just need to propagate the sign */
1402 if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic))))) {
1406 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1410 /* release the aops */
1411 freeAsmop(IC_LEFT(ic),NULL,ic);
1412 freeAsmop(IC_RESULT(ic),NULL,ic);
1415 static void _push(PAIR_ID pairId)
1417 emit2("push %s", _pairs[pairId].name);
1418 _G.stack.pushed += 2;
1421 static void _pop(PAIR_ID pairId)
1423 emit2("pop %s", _pairs[pairId].name);
1424 _G.stack.pushed -= 2;
1428 /*-----------------------------------------------------------------*/
1429 /* assignResultValue - */
1430 /*-----------------------------------------------------------------*/
1431 void assignResultValue(operand * oper)
1433 int size = AOP_SIZE(oper);
1437 topInA = requiresHL(AOP(oper));
1443 if (IS_GB && size == 4 && requiresHL(AOP(oper))) {
1444 /* We do it the hard way here. */
1446 aopPut(AOP(oper), _fReturn[0], 0);
1447 aopPut(AOP(oper), _fReturn[1], 1);
1448 emitcode("pop", "de");
1449 _G.stack.pushed -= 2;
1450 aopPut(AOP(oper), _fReturn[0], 2);
1451 aopPut(AOP(oper), _fReturn[1], 3);
1455 aopPut(AOP(oper), _fReturn[size], size);
1460 /*-----------------------------------------------------------------*/
1461 /* genIpush - genrate code for pushing this gets a little complex */
1462 /*-----------------------------------------------------------------*/
1463 static void genIpush (iCode *ic)
1465 int size, offset = 0 ;
1468 /* if this is not a parm push : ie. it is spill push
1469 and spill push is always done on the local stack */
1470 if (!ic->parmPush) {
1471 /* and the item is spilt then do nothing */
1472 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1475 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1476 size = AOP_SIZE(IC_LEFT(ic));
1477 /* push it on the stack */
1478 if (isPair(AOP(IC_LEFT(ic)))) {
1479 emitcode("push", getPairName(AOP(IC_LEFT(ic))));
1480 _G.stack.pushed += 2;
1485 /* Simple for now - load into A and PUSH AF */
1486 if (AOP(IC_LEFT(ic))->type == AOP_IY) {
1487 char *l = aopGetLitWordLong(AOP(IC_LEFT(ic)), --offset, FALSE);
1489 emit2("ld a,(%s)", l);
1492 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1493 emit2("ld a,%s", l);
1503 /* Hmmm... what about saving the currently used registers
1506 /* then do the push */
1507 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1509 size = AOP_SIZE(IC_LEFT(ic));
1511 if (isPair(AOP(IC_LEFT(ic)))) {
1513 emitcode("push", "%s", getPairName(AOP(IC_LEFT(ic))));
1517 fetchHL(AOP(IC_LEFT(ic)));
1518 emitcode("push", "hl");
1520 _G.stack.pushed += 2;
1524 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
1525 emitcode("push", "hl");
1527 _G.stack.pushed += 2;
1528 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 0);
1529 emitcode("push", "hl");
1531 _G.stack.pushed += 2;
1536 if (AOP(IC_LEFT(ic))->type == AOP_IY) {
1537 char *l = aopGetLitWordLong(AOP(IC_LEFT(ic)), --offset, FALSE);
1539 emit2("ld a,(%s)", l);
1542 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1543 emit2("ld a,%s", l);
1545 emitcode("push", "af");
1546 emitcode("inc", "sp");
1551 freeAsmop(IC_LEFT(ic),NULL,ic);
1554 /*-----------------------------------------------------------------*/
1555 /* genIpop - recover the registers: can happen only for spilling */
1556 /*-----------------------------------------------------------------*/
1557 static void genIpop (iCode *ic)
1562 /* if the temp was not pushed then */
1563 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1566 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1567 size = AOP_SIZE(IC_LEFT(ic));
1569 if (isPair(AOP(IC_LEFT(ic)))) {
1570 emitcode("pop", getPairName(AOP(IC_LEFT(ic))));
1574 emitcode("dec", "sp");
1575 emitcode("pop", "hl");
1577 aopPut(AOP(IC_LEFT(ic)), "l", offset--);
1581 freeAsmop(IC_LEFT(ic),NULL,ic);
1584 static int _isPairUsed(iCode *ic, PAIR_ID pairId)
1589 if (bitVectBitValue(ic->rUsed, D_IDX))
1591 if (bitVectBitValue(ic->rUsed, E_IDX))
1600 static int _opUsesPair(operand *op, iCode *ic, PAIR_ID pairId)
1604 symbol *sym = OP_SYMBOL(op);
1606 if (sym->isspilt || sym->nRegs == 0)
1609 aopOp(op, ic, FALSE, FALSE);
1612 if (aop->type == AOP_REG) {
1614 for (i=0; i < aop->size; i++) {
1615 if (pairId == PAIR_DE) {
1616 emit2("; name %s", aop->aopu.aop_reg[i]->name);
1617 if (!strcmp(aop->aopu.aop_reg[i]->name, "e"))
1619 if (!strcmp(aop->aopu.aop_reg[i]->name, "d"))
1628 freeAsmop(IC_LEFT(ic),NULL,ic);
1632 /** Emit the code for a call statement
1634 static void emitCall(iCode *ic, bool ispcall)
1637 link *detype = getSpec(operandType(IC_LEFT(ic)));
1639 if (IS_BANKED(detype))
1640 emit2("; call to a banked function");
1642 /* if caller saves & we have not saved then */
1643 if (!ic->regsSaved) {
1647 /* if send set is not empty then assign */
1651 int n = elementsInSet(sendSet);
1652 if (IS_Z80 && n == 2 && _isPairUsed(ic, PAIR_DE)) {
1653 /* Only push de if it is used and if it's not used
1654 in the return value */
1655 /* Panic if partly used */
1656 if (_opUsesPair(IC_RESULT(ic), ic, PAIR_DE) == 1) {
1657 emit2("; Warning: de crossover");
1659 else if (!_opUsesPair(IC_RESULT(ic), ic, PAIR_DE)) {
1666 if (IS_Z80 && n == 2 ) {
1667 /* Want to load HL first, then DE as HL may = DE */
1668 sic = setFirstItem(sendSet);
1669 sic = setNextItem(sendSet);
1670 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1671 fetchPair(PAIR_HL, AOP(IC_LEFT(sic)));
1673 freeAsmop (IC_LEFT(sic),NULL,sic);
1674 sic = setFirstItem(sendSet);
1675 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1676 fetchPair(PAIR_DE, AOP(IC_LEFT(sic)));
1678 freeAsmop (IC_LEFT(sic),NULL,sic);
1681 for (sic = setFirstItem(sendSet) ; sic ;
1682 sic = setNextItem(sendSet)) {
1684 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1685 size = AOP_SIZE(IC_LEFT(sic));
1687 /* Always send in pairs */
1690 if (IS_Z80 && n == 1)
1691 fetchPair(PAIR_HL, AOP(IC_LEFT(sic)));
1693 fetchPair(PAIR_DE, AOP(IC_LEFT(sic)));
1696 fetchPair(PAIR_HL, AOP(IC_LEFT(sic)));
1699 /* Send set too big */
1703 freeAsmop (IC_LEFT(sic),NULL,sic);
1712 if (IS_BANKED(detype)) {
1713 werror(W_INDIR_BANKED);
1715 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1717 if (isLitWord(AOP(IC_LEFT(ic)))) {
1718 emitcode("", "; Special case where the pCall is to a constant");
1719 emitcode("call", aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE));
1722 symbol *rlbl = newiTempLabel(NULL);
1724 emit2("ld hl,!immed!tlabel", (rlbl->key+100));
1725 emitcode("push", "hl");
1726 _G.stack.pushed += 2;
1728 fetchHL(AOP(IC_LEFT(ic)));
1730 emit2("!tlabeldef", (rlbl->key+100));
1731 _G.stack.pushed -= 2;
1733 freeAsmop(IC_LEFT(ic),NULL,ic);
1736 char *name = OP_SYMBOL(IC_LEFT(ic))->rname[0] ?
1737 OP_SYMBOL(IC_LEFT(ic))->rname :
1738 OP_SYMBOL(IC_LEFT(ic))->name;
1739 if (IS_BANKED(detype)) {
1740 emit2("call banked_call");
1741 emit2("!dws", name);
1742 emit2("!dw !bankimmeds", name);
1746 emit2("call %s", name);
1751 /* if we need assign a result value */
1752 if ((IS_ITEMP(IC_RESULT(ic)) &&
1753 (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
1754 OP_SYMBOL(IC_RESULT(ic))->spildir )) ||
1755 IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
1758 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
1761 assignResultValue(IC_RESULT(ic));
1763 freeAsmop(IC_RESULT(ic),NULL, ic);
1766 /* adjust the stack for parameters if required */
1767 if (IC_LEFT(ic)->parmBytes) {
1768 int i = IC_LEFT(ic)->parmBytes;
1769 _G.stack.pushed -= i;
1771 emit2("!ldaspsp", i);
1776 emitcode("ld", "hl,#%d", i);
1777 emitcode("add", "hl,sp");
1778 emitcode("ld", "sp,hl");
1782 emitcode("pop", "hl");
1786 emitcode("inc", "sp");
1795 /*-----------------------------------------------------------------*/
1796 /* genCall - generates a call statement */
1797 /*-----------------------------------------------------------------*/
1798 static void genCall (iCode *ic)
1800 link *detype = getSpec(operandType(IC_LEFT(ic)));
1801 if (IS_BANKED(detype)) emit2("; call to a banked function");
1802 emitCall(ic, FALSE);
1805 /*-----------------------------------------------------------------*/
1806 /* genPcall - generates a call by pointer statement */
1807 /*-----------------------------------------------------------------*/
1808 static void genPcall (iCode *ic)
1813 /*-----------------------------------------------------------------*/
1814 /* resultRemat - result is rematerializable */
1815 /*-----------------------------------------------------------------*/
1816 static int resultRemat (iCode *ic)
1818 if (SKIP_IC(ic) || ic->op == IFX)
1821 if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
1822 symbol *sym = OP_SYMBOL(IC_RESULT(ic));
1823 if (sym->remat && !POINTER_SET(ic))
1830 /*-----------------------------------------------------------------*/
1831 /* genFunction - generated code for function entry */
1832 /*-----------------------------------------------------------------*/
1833 static void genFunction (iCode *ic)
1835 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1839 /* create the function header */
1840 emit2("!functionheader", sym->name);
1841 /* PENDING: portability. */
1842 emit2("__%s_start:", sym->rname);
1843 emit2("!functionlabeldef", sym->rname);
1845 fetype = getSpec(operandType(IC_LEFT(ic)));
1847 /* if critical function then turn interrupts off */
1848 if (SPEC_CRTCL(fetype))
1850 if (SPEC_BANKED(fetype)) emit2("; Iam banked");
1852 /* if this is an interrupt service routine then
1853 save acc, b, dpl, dph */
1854 if (IS_ISR(sym->etype)) {
1857 /* PENDING: callee-save etc */
1859 /* If BC or DE are used, then push */
1860 _G.stack.pushed_bc = 0;
1861 _G.stack.pushed_de = 0;
1862 _G.stack.param_offset = 0;
1863 if (sym->regsUsed) {
1865 for ( i = 0 ; i < sym->regsUsed->size ; i++) {
1866 if (bitVectBitValue(sym->regsUsed, i)) {
1870 _G.stack.pushed_bc = 1;
1875 _G.stack.pushed_de = 1;
1880 if (_G.stack.pushed_bc) {
1882 _G.stack.param_offset += 2;
1884 if (_G.stack.pushed_de) {
1886 _G.stack.param_offset += 2;
1890 /* adjust the stack for the function */
1891 _G.stack.last = sym->stack;
1894 emit2("!enterx", sym->stack);
1897 _G.stack.offset = sym->stack;
1900 /*-----------------------------------------------------------------*/
1901 /* genEndFunction - generates epilogue for functions */
1902 /*-----------------------------------------------------------------*/
1903 static void genEndFunction (iCode *ic)
1905 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1907 if (IS_ISR(sym->etype)) {
1911 if (SPEC_CRTCL(sym->etype))
1914 /* PENDING: calleeSave */
1916 /* if debug then send end of function */
1917 if (options.debug && currFunc) {
1919 emitcode("","C$%s$%d$%d$%d ==.",
1920 ic->filename,currFunc->lastLine,
1921 ic->level,ic->block);
1922 if (IS_STATIC(currFunc->etype))
1923 emitcode("","XF%s$%s$0$0 ==.",moduleName,currFunc->name);
1925 emitcode("","XG$%s$0$0 ==.",currFunc->name);
1928 if (_G.stack.offset)
1929 emit2("!leavex", _G.stack.offset);
1933 if (_G.stack.pushed_de)
1935 if (_G.stack.pushed_bc)
1937 /* Both baned and non-banked just ret */
1940 /* PENDING: portability. */
1941 emit2("__%s_end:", sym->rname);
1943 _G.stack.pushed = 0;
1944 _G.stack.offset = 0;
1947 /*-----------------------------------------------------------------*/
1948 /* genRet - generate code for return statement */
1949 /*-----------------------------------------------------------------*/
1950 static void genRet (iCode *ic)
1953 /* Errk. This is a hack until I can figure out how
1954 to cause dehl to spill on a call */
1955 int size,offset = 0;
1957 /* if we have no return value then
1958 just generate the "ret" */
1962 /* we have something to return then
1963 move the return value into place */
1964 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1965 size = AOP_SIZE(IC_LEFT(ic));
1967 if ((size == 2) && ((l = aopGetWord(AOP(IC_LEFT(ic)), 0)))) {
1969 emitcode("ld", "de,%s", l);
1972 emitcode("ld", "hl,%s", l);
1976 if (IS_GB && size == 4 && requiresHL(AOP(IC_LEFT(ic)))) {
1977 fetchPair(PAIR_DE, AOP(IC_LEFT(ic)));
1978 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
1982 l = aopGet(AOP(IC_LEFT(ic)),offset,
1984 if (strcmp(_fReturn[offset],l))
1985 emitcode("ld","%s,%s", _fReturn[offset++],l);
1989 freeAsmop (IC_LEFT(ic),NULL,ic);
1992 /* generate a jump to the return label
1993 if the next is not the return statement */
1994 if (!(ic->next && ic->next->op == LABEL &&
1995 IC_LABEL(ic->next) == returnLabel))
1997 emit2("jp !tlabel", returnLabel->key+100);
2000 /*-----------------------------------------------------------------*/
2001 /* genLabel - generates a label */
2002 /*-----------------------------------------------------------------*/
2003 static void genLabel (iCode *ic)
2005 /* special case never generate */
2006 if (IC_LABEL(ic) == entryLabel)
2009 emitLabel(IC_LABEL(ic)->key+100);
2012 /*-----------------------------------------------------------------*/
2013 /* genGoto - generates a ljmp */
2014 /*-----------------------------------------------------------------*/
2015 static void genGoto (iCode *ic)
2017 emit2("jp !tlabel", IC_LABEL(ic)->key+100);
2020 /*-----------------------------------------------------------------*/
2021 /* genPlusIncr :- does addition with increment if possible */
2022 /*-----------------------------------------------------------------*/
2023 static bool genPlusIncr (iCode *ic)
2025 unsigned int icount ;
2026 unsigned int size = getDataSize(IC_RESULT(ic));
2027 PAIR_ID resultId = getPairId(AOP(IC_RESULT(ic)));
2029 /* will try to generate an increment */
2030 /* if the right side is not a literal
2032 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
2035 emitcode("", "; genPlusIncr");
2037 icount = floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
2039 /* If result is a pair */
2040 if (resultId != PAIR_INVALID) {
2041 if (isLitWord(AOP(IC_LEFT(ic)))) {
2042 fetchLitPair(getPairId(AOP(IC_RESULT(ic))), AOP(IC_LEFT(ic)), icount);
2045 if (isPair(AOP(IC_LEFT(ic))) && resultId == PAIR_HL && icount > 2) {
2046 fetchPair(resultId, AOP(IC_RIGHT(ic)));
2047 emitcode("add", "hl,%s", getPairName(AOP(IC_LEFT(ic))));
2053 if (!sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
2056 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
2057 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
2060 emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
2065 /* if the literal value of the right hand side
2066 is greater than 4 then it is not worth it */
2070 /* if increment 16 bits in register */
2071 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2076 symbol *tlbl = NULL;
2077 tlbl = newiTempLabel(NULL);
2079 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)), offset++, FALSE));
2081 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2084 emitLabel(tlbl->key+100);
2088 /* if the sizes are greater than 1 then we cannot */
2089 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2090 AOP_SIZE(IC_LEFT(ic)) > 1 )
2093 /* we can if the aops of the left & result match or
2094 if they are in registers and the registers are the
2096 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
2098 emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0, FALSE));
2105 /*-----------------------------------------------------------------*/
2106 /* outBitAcc - output a bit in acc */
2107 /*-----------------------------------------------------------------*/
2108 void outBitAcc(operand *result)
2110 symbol *tlbl = newiTempLabel(NULL);
2111 /* if the result is a bit */
2112 if (AOP_TYPE(result) == AOP_CRY){
2116 emit2("!shortjp z,!tlabel", tlbl->key+100);
2118 emitLabel(tlbl->key+100);
2123 /*-----------------------------------------------------------------*/
2124 /* genPlus - generates code for addition */
2125 /*-----------------------------------------------------------------*/
2126 static void genPlus (iCode *ic)
2128 int size, offset = 0;
2130 /* special cases :- */
2132 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
2133 aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
2134 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
2136 /* Swap the left and right operands if:
2138 if literal, literal on the right or
2139 if left requires ACC or right is already
2142 if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
2143 (AOP_NEEDSACC(IC_LEFT(ic))) ||
2144 AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
2145 operand *t = IC_RIGHT(ic);
2146 IC_RIGHT(ic) = IC_LEFT(ic);
2150 /* if both left & right are in bit
2152 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2153 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2158 /* if left in bit space & right literal */
2159 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2160 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
2161 /* Can happen I guess */
2165 /* if I can do an increment instead
2166 of add then GOOD for ME */
2167 if (genPlusIncr (ic) == TRUE)
2170 emit2("; genPlusIncr failed");
2172 size = getDataSize(IC_RESULT(ic));
2174 /* Special case when left and right are constant */
2175 if (isPair(AOP(IC_RESULT(ic)))) {
2178 left = aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE);
2179 right = aopGetLitWordLong(AOP(IC_RIGHT(ic)), 0, FALSE);
2180 if (left && right) {
2184 sprintf(buffer, "#(%s + %s)", left, right);
2185 emitcode("ld", "%s,%s", getPairName(AOP(IC_RESULT(ic))), buffer);
2190 if (isPair(AOP(IC_RIGHT(ic))) && getPairId(AOP(IC_RESULT(ic))) == PAIR_HL) {
2191 /* Fetch into HL then do the add */
2193 fetchPair(PAIR_HL, AOP(IC_LEFT(ic)));
2194 emitcode("add", "hl,%s", getPairName(AOP(IC_RIGHT(ic))));
2199 ld hl,sp+n trashes C so we cant afford to do it during an
2200 add with stack based varibles. Worst case is:
2213 So you cant afford to load up hl if either left, right, or result
2214 is on the stack (*sigh*) The alt is:
2222 Combinations in here are:
2223 * If left or right are in bc then the loss is small - trap later
2224 * If the result is in bc then the loss is also small
2227 if (AOP_TYPE(IC_LEFT(ic)) == AOP_STK ||
2228 AOP_TYPE(IC_RIGHT(ic)) == AOP_STK ||
2229 AOP_TYPE(IC_RESULT(ic)) == AOP_STK) {
2231 if (getPairId(AOP(IC_RIGHT(ic))) == PAIR_BC) {
2232 /* Swap left and right */
2233 operand *t = IC_RIGHT(ic);
2234 IC_RIGHT(ic) = IC_LEFT(ic);
2237 if (getPairId(AOP(IC_LEFT(ic))) == PAIR_BC) {
2238 fetchPair(PAIR_HL, AOP(IC_RIGHT(ic)));
2242 fetchPair(PAIR_DE, AOP(IC_LEFT(ic)));
2243 fetchPair(PAIR_HL, AOP(IC_RIGHT(ic)));
2246 commitPair(AOP(IC_RESULT(ic)), PAIR_HL);
2249 else if (size == 4) {
2250 emit2("; WARNING: This add is probably broken.\n");
2256 if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
2257 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2260 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2263 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2265 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2268 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2271 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2273 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2277 freeAsmop(IC_LEFT(ic),NULL,ic);
2278 freeAsmop(IC_RIGHT(ic),NULL,ic);
2279 freeAsmop(IC_RESULT(ic),NULL,ic);
2283 /*-----------------------------------------------------------------*/
2284 /* genMinusDec :- does subtraction with deccrement if possible */
2285 /*-----------------------------------------------------------------*/
2286 static bool genMinusDec (iCode *ic)
2288 unsigned int icount ;
2289 unsigned int size = getDataSize(IC_RESULT(ic));
2291 /* will try to generate an increment */
2292 /* if the right side is not a literal we cannot */
2293 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
2296 /* if the literal value of the right hand side
2297 is greater than 4 then it is not worth it */
2298 if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
2301 size = getDataSize(IC_RESULT(ic));
2304 /* if increment 16 bits in register */
2305 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2308 symbol *tlbl = newiTempLabel(NULL);
2309 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
2310 emitcode("jp", "np," LABEL_STR ,tlbl->key+100);
2312 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
2316 emitLabel(tlbl->key+100);
2321 /* if decrement 16 bits in register */
2322 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2323 (size > 1) && isPair(AOP(IC_RESULT(ic)))) {
2325 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2329 /* If result is a pair */
2330 if (isPair(AOP(IC_RESULT(ic)))) {
2331 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
2332 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
2334 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2338 /* if the sizes are greater than 1 then we cannot */
2339 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2340 AOP_SIZE(IC_LEFT(ic)) > 1 )
2343 /* we can if the aops of the left & result match or if they are in
2344 registers and the registers are the same */
2345 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
2347 emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE));
2354 /*-----------------------------------------------------------------*/
2355 /* genMinus - generates code for subtraction */
2356 /*-----------------------------------------------------------------*/
2357 static void genMinus (iCode *ic)
2359 int size, offset = 0;
2360 unsigned long lit = 0L;
2362 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
2363 aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
2364 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
2366 /* special cases :- */
2367 /* if both left & right are in bit space */
2368 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2369 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2374 /* if I can do an decrement instead of subtract then GOOD for ME */
2375 if (genMinusDec (ic) == TRUE)
2378 size = getDataSize(IC_RESULT(ic));
2380 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
2383 lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
2387 /* Same logic as genPlus */
2389 if (AOP_TYPE(IC_LEFT(ic)) == AOP_STK ||
2390 AOP_TYPE(IC_RIGHT(ic)) == AOP_STK ||
2391 AOP_TYPE(IC_RESULT(ic)) == AOP_STK) {
2393 PAIR_ID left = getPairId(AOP(IC_LEFT(ic)));
2394 PAIR_ID right = getPairId(AOP(IC_RIGHT(ic)));
2396 if (left == PAIR_INVALID && right == PAIR_INVALID) {
2400 else if (right == PAIR_INVALID)
2402 else if (left == PAIR_INVALID)
2405 fetchPair(left, AOP(IC_LEFT(ic)));
2406 /* Order is important. Right may be HL */
2407 fetchPair(right, AOP(IC_RIGHT(ic)));
2409 emit2("ld a,%s", _pairs[left].l);
2410 emit2("sub a,%s", _pairs[right].l);
2412 emit2("ld a,%s", _pairs[left].h);
2413 emit2("sbc a,%s", _pairs[right].h);
2415 aopPut(AOP(IC_RESULT(ic)), "a", 1);
2416 aopPut(AOP(IC_RESULT(ic)), "e", 0);
2419 else if (size == 4) {
2420 emit2("; WARNING: This sub is probably broken.\n");
2425 /* if literal, add a,#-lit, else normal subb */
2427 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2428 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) {
2430 emitcode("sub","a,%s",
2431 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2433 emitcode("sbc","a,%s",
2434 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2437 /* first add without previous c */
2439 emit2("add a,!immedbyte", (unsigned int)(lit & 0x0FFL));
2441 emit2("adc a,!immedbyte", (unsigned int)((lit >> (offset*8)) & 0x0FFL));
2443 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2446 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2447 AOP_SIZE(IC_LEFT(ic)) == 3 &&
2448 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2452 freeAsmop(IC_LEFT(ic),NULL,ic);
2453 freeAsmop(IC_RIGHT(ic),NULL,ic);
2454 freeAsmop(IC_RESULT(ic),NULL,ic);
2457 /*-----------------------------------------------------------------*/
2458 /* genMult - generates code for multiplication */
2459 /*-----------------------------------------------------------------*/
2460 static void genMult (iCode *ic)
2462 /* Shouldn't occur - all done through function calls */
2466 /*-----------------------------------------------------------------*/
2467 /* genDiv - generates code for division */
2468 /*-----------------------------------------------------------------*/
2469 static void genDiv (iCode *ic)
2471 /* Shouldn't occur - all done through function calls */
2475 /*-----------------------------------------------------------------*/
2476 /* genMod - generates code for division */
2477 /*-----------------------------------------------------------------*/
2478 static void genMod (iCode *ic)
2480 /* Shouldn't occur - all done through function calls */
2484 /*-----------------------------------------------------------------*/
2485 /* genIfxJump :- will create a jump depending on the ifx */
2486 /*-----------------------------------------------------------------*/
2487 static void genIfxJump (iCode *ic, char *jval)
2492 /* if true label then we jump if condition
2494 if ( IC_TRUE(ic) ) {
2496 if (!strcmp(jval, "a")) {
2499 else if (!strcmp(jval, "c")) {
2503 /* The buffer contains the bit on A that we should test */
2508 /* false label is present */
2509 jlbl = IC_FALSE(ic) ;
2510 if (!strcmp(jval, "a")) {
2513 else if (!strcmp(jval, "c")) {
2517 /* The buffer contains the bit on A that we should test */
2521 /* Z80 can do a conditional long jump */
2522 if (!strcmp(jval, "a")) {
2523 emitcode("or", "a,a");
2525 else if (!strcmp(jval, "c")) {
2528 emitcode("bit", "%s,a", jval);
2530 emit2("jp %s,!tlabel", inst, jlbl->key+100);
2532 /* mark the icode as generated */
2536 /** Generic compare for > or <
2538 static void genCmp (operand *left,operand *right,
2539 operand *result, iCode *ifx, int sign)
2541 int size, offset = 0 ;
2542 unsigned long lit = 0L;
2544 /* if left & right are bit variables */
2545 if (AOP_TYPE(left) == AOP_CRY &&
2546 AOP_TYPE(right) == AOP_CRY ) {
2547 /* Cant happen on the Z80 */
2550 /* subtract right from left if at the
2551 end the carry flag is set then we know that
2552 left is greater than right */
2553 size = max(AOP_SIZE(left),AOP_SIZE(right));
2555 /* if unsigned char cmp with lit, just compare */
2557 (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
2558 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2560 emit2("xor a,!immedbyte", 0x80);
2561 emit2("cp %s^!constbyte", aopGet(AOP(right), offset, FALSE), 0x80);
2564 emitcode("cp", "%s", aopGet(AOP(right), offset, FALSE));
2567 if(AOP_TYPE(right) == AOP_LIT) {
2568 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2569 /* optimize if(x < 0) or if(x >= 0) */
2572 /* No sign so it's always false */
2576 /* Just load in the top most bit */
2577 MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE));
2578 if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx) {
2579 genIfxJump (ifx,"7");
2583 emitcode("rlc","a");
2589 /* First setup h and l contaning the top most bytes XORed */
2590 bool fDidXor = FALSE;
2591 if (AOP_TYPE(left) == AOP_LIT){
2592 unsigned long lit = (unsigned long)
2593 floatFromVal(AOP(left)->aopu.aop_lit);
2594 emit2("ld %s,!immedbyte", _fTmp[0],
2595 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2598 emitcode("ld", "a,%s", aopGet(AOP(left), size-1, FALSE));
2599 emit2("xor a,!immedbyte", 0x80);
2600 emitcode("ld", "%s,a", _fTmp[0]);
2603 if (AOP_TYPE(right) == AOP_LIT) {
2604 unsigned long lit = (unsigned long)
2605 floatFromVal(AOP(right)->aopu.aop_lit);
2606 emit2("ld %s,!immedbyte", _fTmp[1],
2607 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2610 emitcode("ld", "a,%s", aopGet(AOP(right), size-1, FALSE));
2611 emit2("xor a,!immedbyte", 0x80);
2612 emitcode("ld", "%s,a", _fTmp[1]);
2622 /* Do a long subtract */
2623 if (!sign || size ) {
2624 MOVA(aopGet(AOP(left),offset,FALSE));
2626 if (sign && size == 0) {
2627 emitcode("ld", "a,%s", _fTmp[0]);
2628 emitcode("sbc", "a,%s", _fTmp[1]);
2631 /* Subtract through, propagating the carry */
2632 emitcode("sbc","a,%s ; 2",aopGet(AOP(right),offset++,FALSE));
2639 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2642 /* if the result is used in the next
2643 ifx conditional branch then generate
2644 code a little differently */
2646 genIfxJump (ifx,"c");
2649 /* leave the result in acc */
2653 /*-----------------------------------------------------------------*/
2654 /* genCmpGt :- greater than comparison */
2655 /*-----------------------------------------------------------------*/
2656 static void genCmpGt (iCode *ic, iCode *ifx)
2658 operand *left, *right, *result;
2659 link *letype , *retype;
2663 right= IC_RIGHT(ic);
2664 result = IC_RESULT(ic);
2666 letype = getSpec(operandType(left));
2667 retype =getSpec(operandType(right));
2668 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2669 /* assign the amsops */
2670 aopOp (left,ic,FALSE, FALSE);
2671 aopOp (right,ic,FALSE, FALSE);
2672 aopOp (result,ic,TRUE, FALSE);
2674 genCmp(right, left, result, ifx, sign);
2676 freeAsmop(left,NULL,ic);
2677 freeAsmop(right,NULL,ic);
2678 freeAsmop(result,NULL,ic);
2681 /*-----------------------------------------------------------------*/
2682 /* genCmpLt - less than comparisons */
2683 /*-----------------------------------------------------------------*/
2684 static void genCmpLt (iCode *ic, iCode *ifx)
2686 operand *left, *right, *result;
2687 link *letype , *retype;
2691 right= IC_RIGHT(ic);
2692 result = IC_RESULT(ic);
2694 letype = getSpec(operandType(left));
2695 retype =getSpec(operandType(right));
2696 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2698 /* assign the amsops */
2699 aopOp (left,ic,FALSE, FALSE);
2700 aopOp (right,ic,FALSE, FALSE);
2701 aopOp (result,ic,TRUE, FALSE);
2703 genCmp(left, right, result, ifx, sign);
2705 freeAsmop(left,NULL,ic);
2706 freeAsmop(right,NULL,ic);
2707 freeAsmop(result,NULL,ic);
2710 /*-----------------------------------------------------------------*/
2711 /* gencjneshort - compare and jump if not equal */
2712 /*-----------------------------------------------------------------*/
2713 static void gencjneshort(operand *left, operand *right, symbol *lbl)
2715 int size = max(AOP_SIZE(left),AOP_SIZE(right));
2717 unsigned long lit = 0L;
2719 /* Swap the left and right if it makes the computation easier */
2720 if (AOP_TYPE(left) == AOP_LIT) {
2726 if(AOP_TYPE(right) == AOP_LIT)
2727 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2729 /* if the right side is a literal then anything goes */
2730 if (AOP_TYPE(right) == AOP_LIT &&
2731 AOP_TYPE(left) != AOP_DIR ) {
2733 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2738 emitcode("or", "a,%s", aopGet(AOP(left), offset, FALSE));
2742 emitcode("or", "a,a");
2744 emit2("jp nz,!tlabel", lbl->key+100);
2748 emitcode("ld", "a,%s ; 2", aopGet(AOP(left),offset,FALSE));
2749 if ((AOP_TYPE(right) == AOP_LIT) && lit == 0)
2750 emitcode("or", "a,a");
2752 emitcode("cp", "a,%s", aopGet(AOP(right),offset,FALSE));
2753 emit2("jp nz,!tlabel", lbl->key+100);
2758 /* if the right side is in a register or in direct space or
2759 if the left is a pointer register & right is not */
2760 else if (AOP_TYPE(right) == AOP_REG ||
2761 AOP_TYPE(right) == AOP_DIR ||
2762 (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT)) {
2764 MOVA(aopGet(AOP(left),offset,FALSE));
2765 if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
2766 ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
2768 emit2("jp nz,!tlabel", lbl->key+100);
2770 emitcode("cp", "%s ; 4", aopGet(AOP(right),offset,FALSE));
2771 emit2("jp nz,!tlabel", lbl->key+100);
2776 /* right is a pointer reg need both a & b */
2777 /* PENDING: is this required? */
2779 MOVA(aopGet(AOP(right),offset,FALSE));
2780 emitcode("cp", "%s ; 5", aopGet(AOP(left), offset, FALSE));
2781 emit2("!shortjp nz,!tlabel", lbl->key+100);
2787 /*-----------------------------------------------------------------*/
2788 /* gencjne - compare and jump if not equal */
2789 /*-----------------------------------------------------------------*/
2790 static void gencjne(operand *left, operand *right, symbol *lbl)
2792 symbol *tlbl = newiTempLabel(NULL);
2794 gencjneshort(left, right, lbl);
2798 emit2("!shortjp !tlabel", tlbl->key+100);
2799 emitLabel(lbl->key+100);
2800 emitcode("xor","a,a");
2801 emitLabel(tlbl->key+100);
2804 /*-----------------------------------------------------------------*/
2805 /* genCmpEq - generates code for equal to */
2806 /*-----------------------------------------------------------------*/
2807 static void genCmpEq (iCode *ic, iCode *ifx)
2809 operand *left, *right, *result;
2811 aopOp((left=IC_LEFT(ic)),ic,FALSE, FALSE);
2812 aopOp((right=IC_RIGHT(ic)),ic,FALSE, FALSE);
2813 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2815 /* Swap operands if it makes the operation easier. ie if:
2816 1. Left is a literal.
2818 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
2819 operand *t = IC_RIGHT(ic);
2820 IC_RIGHT(ic) = IC_LEFT(ic);
2824 if (ifx && !AOP_SIZE(result)){
2826 /* if they are both bit variables */
2827 if (AOP_TYPE(left) == AOP_CRY &&
2828 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2831 tlbl = newiTempLabel(NULL);
2832 gencjneshort(left, right, tlbl);
2833 if ( IC_TRUE(ifx) ) {
2834 emit2("jp !tlabel", IC_TRUE(ifx)->key+100);
2835 emitLabel(tlbl->key+100);
2837 /* PENDING: do this better */
2838 symbol *lbl = newiTempLabel(NULL);
2839 emit2("!shortjp !tlabel", lbl->key+100);
2840 emitLabel(tlbl->key+100);
2841 emit2("jp !tlabel", IC_FALSE(ifx)->key+100);
2842 emitLabel(lbl->key+100);
2845 /* mark the icode as generated */
2850 /* if they are both bit variables */
2851 if (AOP_TYPE(left) == AOP_CRY &&
2852 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2855 gencjne(left,right,newiTempLabel(NULL));
2856 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2860 genIfxJump(ifx,"a");
2863 /* if the result is used in an arithmetic operation
2864 then put the result in place */
2865 if (AOP_TYPE(result) != AOP_CRY) {
2868 /* leave the result in acc */
2872 freeAsmop(left,NULL,ic);
2873 freeAsmop(right,NULL,ic);
2874 freeAsmop(result,NULL,ic);
2877 /*-----------------------------------------------------------------*/
2878 /* ifxForOp - returns the icode containing the ifx for operand */
2879 /*-----------------------------------------------------------------*/
2880 static iCode *ifxForOp ( operand *op, iCode *ic )
2882 /* if true symbol then needs to be assigned */
2883 if (IS_TRUE_SYMOP(op))
2886 /* if this has register type condition and
2887 the next instruction is ifx with the same operand
2888 and live to of the operand is upto the ifx only then */
2890 ic->next->op == IFX &&
2891 IC_COND(ic->next)->key == op->key &&
2892 OP_SYMBOL(op)->liveTo <= ic->next->seq )
2898 /*-----------------------------------------------------------------*/
2899 /* genAndOp - for && operation */
2900 /*-----------------------------------------------------------------*/
2901 static void genAndOp (iCode *ic)
2903 operand *left,*right, *result;
2906 /* note here that && operations that are in an if statement are
2907 taken away by backPatchLabels only those used in arthmetic
2908 operations remain */
2909 aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2910 aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2911 aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2913 /* if both are bit variables */
2914 if (AOP_TYPE(left) == AOP_CRY &&
2915 AOP_TYPE(right) == AOP_CRY ) {
2918 tlbl = newiTempLabel(NULL);
2920 emit2("!shortjp z,!tlabel", tlbl->key+100);
2922 emitLabel(tlbl->key+100);
2926 freeAsmop(left,NULL,ic);
2927 freeAsmop(right,NULL,ic);
2928 freeAsmop(result,NULL,ic);
2931 /*-----------------------------------------------------------------*/
2932 /* genOrOp - for || operation */
2933 /*-----------------------------------------------------------------*/
2934 static void genOrOp (iCode *ic)
2936 operand *left,*right, *result;
2939 /* note here that || operations that are in an
2940 if statement are taken away by backPatchLabels
2941 only those used in arthmetic operations remain */
2942 aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2943 aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2944 aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2946 /* if both are bit variables */
2947 if (AOP_TYPE(left) == AOP_CRY &&
2948 AOP_TYPE(right) == AOP_CRY ) {
2951 tlbl = newiTempLabel(NULL);
2953 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2955 emitLabel(tlbl->key+100);
2959 freeAsmop(left,NULL,ic);
2960 freeAsmop(right,NULL,ic);
2961 freeAsmop(result,NULL,ic);
2964 /*-----------------------------------------------------------------*/
2965 /* isLiteralBit - test if lit == 2^n */
2966 /*-----------------------------------------------------------------*/
2967 int isLiteralBit(unsigned long lit)
2969 unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
2970 0x100L,0x200L,0x400L,0x800L,
2971 0x1000L,0x2000L,0x4000L,0x8000L,
2972 0x10000L,0x20000L,0x40000L,0x80000L,
2973 0x100000L,0x200000L,0x400000L,0x800000L,
2974 0x1000000L,0x2000000L,0x4000000L,0x8000000L,
2975 0x10000000L,0x20000000L,0x40000000L,0x80000000L};
2978 for(idx = 0; idx < 32; idx++)
2984 /*-----------------------------------------------------------------*/
2985 /* jmpTrueOrFalse - */
2986 /*-----------------------------------------------------------------*/
2987 static void jmpTrueOrFalse (iCode *ic, symbol *tlbl)
2989 // ugly but optimized by peephole
2991 symbol *nlbl = newiTempLabel(NULL);
2992 emit2("jp !tlabel", nlbl->key+100);
2993 emitLabel(tlbl->key+100);
2994 emit2("jp !tlabel", IC_TRUE(ic)->key+100);
2995 emitLabel(nlbl->key+100);
2998 emit2("jp !tlabel", IC_FALSE(ic)->key+100);
2999 emitLabel(tlbl->key+100);
3004 /*-----------------------------------------------------------------*/
3005 /* genAnd - code for and */
3006 /*-----------------------------------------------------------------*/
3007 static void genAnd (iCode *ic, iCode *ifx)
3009 operand *left, *right, *result;
3011 unsigned long lit = 0L;
3014 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3015 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3016 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3019 emitcode("","; Type res[%d] = l[%d]&r[%d]",
3021 AOP_TYPE(left), AOP_TYPE(right));
3022 emitcode("","; Size res[%d] = l[%d]&r[%d]",
3024 AOP_SIZE(left), AOP_SIZE(right));
3027 /* if left is a literal & right is not then exchange them */
3028 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3029 AOP_NEEDSACC(left)) {
3030 operand *tmp = right ;
3035 /* if result = right then exchange them */
3036 if(sameRegs(AOP(result),AOP(right))){
3037 operand *tmp = right ;
3042 /* if right is bit then exchange them */
3043 if (AOP_TYPE(right) == AOP_CRY &&
3044 AOP_TYPE(left) != AOP_CRY){
3045 operand *tmp = right ;
3049 if(AOP_TYPE(right) == AOP_LIT)
3050 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3052 size = AOP_SIZE(result);
3054 if (AOP_TYPE(left) == AOP_CRY){
3059 // if(val & 0xZZ) - size = 0, ifx != FALSE -
3060 // bit = val & 0xZZ - size = 1, ifx = FALSE -
3061 if((AOP_TYPE(right) == AOP_LIT) &&
3062 (AOP_TYPE(result) == AOP_CRY) &&
3063 (AOP_TYPE(left) != AOP_CRY)) {
3064 int posbit = isLiteralBit(lit);
3068 MOVA(aopGet(AOP(left),posbit>>3,FALSE));
3072 emitcode("mov","c,acc.%d",posbit&0x07);
3077 sprintf(buffer, "%d", posbit&0x07);
3078 genIfxJump(ifx, buffer);
3086 symbol *tlbl = newiTempLabel(NULL);
3087 int sizel = AOP_SIZE(left);
3090 emitcode("setb","c");
3093 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
3094 MOVA( aopGet(AOP(left),offset,FALSE));
3096 if((posbit = isLiteralBit(bytelit)) != 0) {
3098 emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
3101 if(bytelit != 0x0FFL)
3102 emitcode("and","a,%s",
3103 aopGet(AOP(right),offset,FALSE));
3107 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3112 // bit = left & literal
3114 emitcode("clr","c");
3115 emit2("!tlabeldef", tlbl->key+100);
3117 // if(left & literal)
3120 jmpTrueOrFalse(ifx, tlbl);
3128 /* if left is same as result */
3129 if(sameRegs(AOP(result),AOP(left))){
3130 for(;size--; offset++) {
3131 if(AOP_TYPE(right) == AOP_LIT){
3132 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
3136 aopPut(AOP(result),zero,offset);
3138 MOVA(aopGet(AOP(left),offset,FALSE));
3139 emitcode("and","a,%s",
3140 aopGet(AOP(right),offset,FALSE));
3141 aopPut(AOP(left), "a", offset);
3146 if (AOP_TYPE(left) == AOP_ACC) {
3150 MOVA(aopGet(AOP(left),offset,FALSE));
3151 emitcode("and","a,%s",
3152 aopGet(AOP(right),offset,FALSE));
3153 aopPut(AOP(left), "a", offset);
3158 // left & result in different registers
3159 if(AOP_TYPE(result) == AOP_CRY){
3162 for(;(size--);offset++) {
3164 // result = left & right
3165 if(AOP_TYPE(right) == AOP_LIT){
3166 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
3168 aopGet(AOP(left),offset,FALSE),
3171 } else if(bytelit == 0){
3172 aopPut(AOP(result),zero,offset);
3176 // faster than result <- left, anl result,right
3177 // and better if result is SFR
3178 if (AOP_TYPE(left) == AOP_ACC)
3179 emitcode("and","a,%s",aopGet(AOP(right),offset,FALSE));
3181 MOVA(aopGet(AOP(left),offset,FALSE));
3182 emitcode("and","a,%s",
3183 aopGet(AOP(right),offset,FALSE));
3185 aopPut(AOP(result),"a",offset);
3192 freeAsmop(left,NULL,ic);
3193 freeAsmop(right,NULL,ic);
3194 freeAsmop(result,NULL,ic);
3197 /*-----------------------------------------------------------------*/
3198 /* genOr - code for or */
3199 /*-----------------------------------------------------------------*/
3200 static void genOr (iCode *ic, iCode *ifx)
3202 operand *left, *right, *result;
3204 unsigned long lit = 0L;
3206 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3207 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3208 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3211 emitcode("","; Type res[%d] = l[%d]&r[%d]",
3213 AOP_TYPE(left), AOP_TYPE(right));
3214 emitcode("","; Size res[%d] = l[%d]&r[%d]",
3216 AOP_SIZE(left), AOP_SIZE(right));
3219 /* if left is a literal & right is not then exchange them */
3220 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3221 AOP_NEEDSACC(left)) {
3222 operand *tmp = right ;
3227 /* if result = right then exchange them */
3228 if(sameRegs(AOP(result),AOP(right))){
3229 operand *tmp = right ;
3234 /* if right is bit then exchange them */
3235 if (AOP_TYPE(right) == AOP_CRY &&
3236 AOP_TYPE(left) != AOP_CRY){
3237 operand *tmp = right ;
3241 if(AOP_TYPE(right) == AOP_LIT)
3242 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3244 size = AOP_SIZE(result);
3246 if (AOP_TYPE(left) == AOP_CRY){
3251 if((AOP_TYPE(right) == AOP_LIT) &&
3252 (AOP_TYPE(result) == AOP_CRY) &&
3253 (AOP_TYPE(left) != AOP_CRY)){
3258 /* if left is same as result */
3259 if(sameRegs(AOP(result),AOP(left))){
3260 for(;size--; offset++) {
3261 if(AOP_TYPE(right) == AOP_LIT){
3262 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3265 MOVA(aopGet(AOP(left),offset,FALSE));
3266 emitcode("or","a,%s",
3267 aopGet(AOP(right),offset,FALSE));
3268 aopPut(AOP(result),"a", offset);
3271 if (AOP_TYPE(left) == AOP_ACC)
3272 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
3274 MOVA(aopGet(AOP(left),offset,FALSE));
3275 emitcode("or","a,%s",
3276 aopGet(AOP(right),offset,FALSE));
3277 aopPut(AOP(result),"a", offset);
3282 // left & result in different registers
3283 if(AOP_TYPE(result) == AOP_CRY){
3285 } else for(;(size--);offset++){
3287 // result = left & right
3288 if(AOP_TYPE(right) == AOP_LIT){
3289 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3291 aopGet(AOP(left),offset,FALSE),
3296 // faster than result <- left, anl result,right
3297 // and better if result is SFR
3298 if (AOP_TYPE(left) == AOP_ACC)
3299 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
3301 MOVA(aopGet(AOP(left),offset,FALSE));
3302 emitcode("or","a,%s",
3303 aopGet(AOP(right),offset,FALSE));
3305 aopPut(AOP(result),"a",offset);
3306 /* PENDING: something weird is going on here. Add exception. */
3307 if (AOP_TYPE(result) == AOP_ACC)
3313 freeAsmop(left,NULL,ic);
3314 freeAsmop(right,NULL,ic);
3315 freeAsmop(result,NULL,ic);
3318 /*-----------------------------------------------------------------*/
3319 /* genXor - code for xclusive or */
3320 /*-----------------------------------------------------------------*/
3321 static void genXor (iCode *ic, iCode *ifx)
3323 operand *left, *right, *result;
3325 unsigned long lit = 0L;
3327 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3328 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3329 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3331 /* if left is a literal & right is not then exchange them */
3332 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3333 AOP_NEEDSACC(left)) {
3334 operand *tmp = right ;
3339 /* if result = right then exchange them */
3340 if(sameRegs(AOP(result),AOP(right))){
3341 operand *tmp = right ;
3346 /* if right is bit then exchange them */
3347 if (AOP_TYPE(right) == AOP_CRY &&
3348 AOP_TYPE(left) != AOP_CRY){
3349 operand *tmp = right ;
3353 if(AOP_TYPE(right) == AOP_LIT)
3354 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3356 size = AOP_SIZE(result);
3358 if (AOP_TYPE(left) == AOP_CRY){
3363 if((AOP_TYPE(right) == AOP_LIT) &&
3364 (AOP_TYPE(result) == AOP_CRY) &&
3365 (AOP_TYPE(left) != AOP_CRY)){
3370 /* if left is same as result */
3371 if(sameRegs(AOP(result),AOP(left))){
3372 for(;size--; offset++) {
3373 if(AOP_TYPE(right) == AOP_LIT){
3374 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3377 MOVA(aopGet(AOP(right),offset,FALSE));
3378 emitcode("xor","a,%s",
3379 aopGet(AOP(left),offset,FALSE));
3380 aopPut(AOP(result),"a",0);
3383 if (AOP_TYPE(left) == AOP_ACC)
3384 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3386 MOVA(aopGet(AOP(right),offset,FALSE));
3387 emitcode("xor","a,%s",
3388 aopGet(AOP(left),offset,FALSE));
3389 aopPut(AOP(result),"a",0);
3394 // left & result in different registers
3395 if(AOP_TYPE(result) == AOP_CRY){
3397 } else for(;(size--);offset++){
3399 // result = left & right
3400 if(AOP_TYPE(right) == AOP_LIT){
3401 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3403 aopGet(AOP(left),offset,FALSE),
3408 // faster than result <- left, anl result,right
3409 // and better if result is SFR
3410 if (AOP_TYPE(left) == AOP_ACC)
3411 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3413 MOVA(aopGet(AOP(right),offset,FALSE));
3414 emitcode("xor","a,%s",
3415 aopGet(AOP(left),offset,FALSE));
3416 aopPut(AOP(result),"a",0);
3418 aopPut(AOP(result),"a",offset);
3423 freeAsmop(left,NULL,ic);
3424 freeAsmop(right,NULL,ic);
3425 freeAsmop(result,NULL,ic);
3428 /*-----------------------------------------------------------------*/
3429 /* genInline - write the inline code out */
3430 /*-----------------------------------------------------------------*/
3431 static void genInline (iCode *ic)
3433 char buffer[MAX_INLINEASM];
3437 inLine += (!options.asmpeep);
3438 strcpy(buffer,IC_INLINE(ic));
3440 /* emit each line as a code */
3459 /* emitcode("",buffer); */
3460 inLine -= (!options.asmpeep);
3463 /*-----------------------------------------------------------------*/
3464 /* genRRC - rotate right with carry */
3465 /*-----------------------------------------------------------------*/
3466 static void genRRC (iCode *ic)
3471 /*-----------------------------------------------------------------*/
3472 /* genRLC - generate code for rotate left with carry */
3473 /*-----------------------------------------------------------------*/
3474 static void genRLC (iCode *ic)
3479 /*-----------------------------------------------------------------*/
3480 /* shiftR2Left2Result - shift right two bytes from left to result */
3481 /*-----------------------------------------------------------------*/
3482 static void shiftR2Left2Result (operand *left, int offl,
3483 operand *result, int offr,
3484 int shCount, int sign)
3486 movLeft2Result(left, offl, result, offr, 0);
3487 movLeft2Result(left, offl+1, result, offr+1, 0);
3493 /* if (AOP(result)->type == AOP_REG) {*/
3496 symbol *tlbl , *tlbl1;
3499 tlbl = newiTempLabel(NULL);
3500 tlbl1 = newiTempLabel(NULL);
3502 /* Left is already in result - so now do the shift */
3504 emit2("ld a,!immedbyte+1", shCount);
3505 emit2("!shortjp !tlabel", tlbl1->key+100);
3506 emitLabel(tlbl->key+100);
3509 emitcode("or", "a,a");
3512 l = aopGet(AOP(result), --offset, FALSE);
3513 emitcode("rr","%s", l);
3516 emitLabel(tlbl1->key+100);
3517 emitcode("dec", "a");
3518 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3523 /*-----------------------------------------------------------------*/
3524 /* shiftL2Left2Result - shift left two bytes from left to result */
3525 /*-----------------------------------------------------------------*/
3526 static void shiftL2Left2Result (operand *left, int offl,
3527 operand *result, int offr, int shCount)
3529 if(sameRegs(AOP(result), AOP(left)) &&
3530 ((offl + MSB16) == offr)){
3533 /* Copy left into result */
3534 movLeft2Result(left, offl, result, offr, 0);
3535 movLeft2Result(left, offl+1, result, offr+1, 0);
3537 /* PENDING: for now just see if it'll work. */
3538 /*if (AOP(result)->type == AOP_REG) { */
3542 symbol *tlbl , *tlbl1;
3545 tlbl = newiTempLabel(NULL);
3546 tlbl1 = newiTempLabel(NULL);
3548 /* Left is already in result - so now do the shift */
3550 emit2("ld a,!immedbyte+1", shCount);
3551 emit2("!shortjp !tlabel", tlbl1->key+100);
3552 emitLabel(tlbl->key+100);
3555 emitcode("or", "a,a");
3557 l = aopGet(AOP(result),offset++,FALSE);
3558 emitcode("rl","%s", l);
3561 emitLabel(tlbl1->key+100);
3562 emitcode("dec", "a");
3563 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3568 /*-----------------------------------------------------------------*/
3569 /* AccRol - rotate left accumulator by known count */
3570 /*-----------------------------------------------------------------*/
3571 static void AccRol (int shCount)
3573 shCount &= 0x0007; // shCount : 0..7
3610 /*-----------------------------------------------------------------*/
3611 /* AccLsh - left shift accumulator by known count */
3612 /*-----------------------------------------------------------------*/
3613 static void AccLsh (int shCount)
3617 emitcode("add","a,a");
3619 else if(shCount == 2) {
3620 emitcode("add","a,a");
3621 emitcode("add","a,a");
3623 /* rotate left accumulator */
3625 /* and kill the lower order bits */
3626 emit2("and a,!immedbyte", SLMask[shCount]);
3631 /*-----------------------------------------------------------------*/
3632 /* shiftL1Left2Result - shift left one byte from left to result */
3633 /*-----------------------------------------------------------------*/
3634 static void shiftL1Left2Result (operand *left, int offl,
3635 operand *result, int offr, int shCount)
3638 l = aopGet(AOP(left),offl,FALSE);
3640 /* shift left accumulator */
3642 aopPut(AOP(result),"a",offr);
3646 /*-----------------------------------------------------------------*/
3647 /* genlshTwo - left shift two bytes by known amount != 0 */
3648 /*-----------------------------------------------------------------*/
3649 static void genlshTwo (operand *result,operand *left, int shCount)
3651 int size = AOP_SIZE(result);
3655 /* if shCount >= 8 */
3660 movLeft2Result(left, LSB, result, MSB16, 0);
3661 aopPut(AOP(result),zero, 0);
3662 shiftL1Left2Result(left, MSB16, result, MSB16, shCount);
3665 movLeft2Result(left, LSB, result, MSB16, 0);
3666 aopPut(AOP(result),zero, 0);
3670 aopPut(AOP(result),zero,LSB);
3673 /* 1 <= shCount <= 7 */
3679 shiftL2Left2Result(left, LSB, result, LSB, shCount);
3684 /*-----------------------------------------------------------------*/
3685 /* genlshOne - left shift a one byte quantity by known count */
3686 /*-----------------------------------------------------------------*/
3687 static void genlshOne (operand *result, operand *left, int shCount)
3689 shiftL1Left2Result(left, LSB, result, LSB, shCount);
3692 /*-----------------------------------------------------------------*/
3693 /* genLeftShiftLiteral - left shifting by known count */
3694 /*-----------------------------------------------------------------*/
3695 static void genLeftShiftLiteral (operand *left,
3700 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3703 freeAsmop(right,NULL,ic);
3705 aopOp(left,ic,FALSE, FALSE);
3706 aopOp(result,ic,FALSE, FALSE);
3708 size = getSize(operandType(result));
3711 emitcode("; shift left ","result %d, left %d",size,
3715 /* I suppose that the left size >= result size */
3720 else if(shCount >= (size * 8))
3722 aopPut(AOP(result),zero,size);
3726 genlshOne (result,left,shCount);
3729 genlshTwo (result,left,shCount);
3738 freeAsmop(left,NULL,ic);
3739 freeAsmop(result,NULL,ic);
3742 /*-----------------------------------------------------------------*/
3743 /* genLeftShift - generates code for left shifting */
3744 /*-----------------------------------------------------------------*/
3745 static void genLeftShift (iCode *ic)
3749 symbol *tlbl , *tlbl1;
3750 operand *left,*right, *result;
3752 right = IC_RIGHT(ic);
3754 result = IC_RESULT(ic);
3756 aopOp(right,ic,FALSE, FALSE);
3758 /* if the shift count is known then do it
3759 as efficiently as possible */
3760 if (AOP_TYPE(right) == AOP_LIT) {
3761 genLeftShiftLiteral (left,right,result,ic);
3765 /* shift count is unknown then we have to form a loop get the loop
3766 count in B : Note: we take only the lower order byte since
3767 shifting more that 32 bits make no sense anyway, ( the largest
3768 size of an object can be only 32 bits ) */
3769 emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE));
3770 emitcode("inc","a");
3771 freeAsmop (right,NULL,ic);
3772 aopOp(left,ic,FALSE, FALSE);
3773 aopOp(result,ic,FALSE, FALSE);
3775 /* now move the left to the result if they are not the
3778 if (!sameRegs(AOP(left),AOP(result))) {
3780 size = AOP_SIZE(result);
3783 l = aopGet(AOP(left),offset,FALSE);
3784 aopPut(AOP(result),l,offset);
3789 size = AOP_SIZE(result);
3792 l = aopGet(AOP(left),offset,FALSE);
3793 aopPut(AOP(result),l,offset);
3799 tlbl = newiTempLabel(NULL);
3800 size = AOP_SIZE(result);
3802 tlbl1 = newiTempLabel(NULL);
3804 emit2("!shortjp !tlabel", tlbl1->key+100);
3805 emitLabel(tlbl->key+100);
3806 l = aopGet(AOP(result),offset,FALSE);
3807 emitcode("or", "a,a");
3809 l = aopGet(AOP(result),offset++,FALSE);
3810 emitcode("rl","%s", l);
3812 emitLabel(tlbl1->key+100);
3813 emitcode("dec", "a");
3814 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3816 freeAsmop(left,NULL,ic);
3817 freeAsmop(result,NULL,ic);
3820 /*-----------------------------------------------------------------*/
3821 /* genrshOne - left shift two bytes by known amount != 0 */
3822 /*-----------------------------------------------------------------*/
3823 static void genrshOne (operand *result,operand *left, int shCount)
3826 int size = AOP_SIZE(result);
3832 l = aopGet(AOP(left),0,FALSE);
3833 if (AOP(result)->type == AOP_REG) {
3834 aopPut(AOP(result), l, 0);
3835 l = aopGet(AOP(result), 0, FALSE);
3837 emitcode("srl", "%s", l);
3842 emitcode("srl", "a");
3844 aopPut(AOP(result),"a",0);
3848 /*-----------------------------------------------------------------*/
3849 /* AccRsh - right shift accumulator by known count */
3850 /*-----------------------------------------------------------------*/
3851 static void AccRsh (int shCount)
3854 /* rotate right accumulator */
3855 AccRol(8 - shCount);
3856 /* and kill the higher order bits */
3857 emit2("and a,!immedbyte", SRMask[shCount]);
3861 /*-----------------------------------------------------------------*/
3862 /* shiftR1Left2Result - shift right one byte from left to result */
3863 /*-----------------------------------------------------------------*/
3864 static void shiftR1Left2Result (operand *left, int offl,
3865 operand *result, int offr,
3866 int shCount, int sign)
3868 MOVA(aopGet(AOP(left),offl,FALSE));
3875 aopPut(AOP(result),"a",offr);
3878 /*-----------------------------------------------------------------*/
3879 /* genrshTwo - right shift two bytes by known amount != 0 */
3880 /*-----------------------------------------------------------------*/
3881 static void genrshTwo (operand *result,operand *left,
3882 int shCount, int sign)
3884 /* if shCount >= 8 */
3888 shiftR1Left2Result(left, MSB16, result, LSB,
3892 movLeft2Result(left, MSB16, result, LSB, sign);
3894 aopPut(AOP(result),zero,1);
3896 /* 1 <= shCount <= 7 */
3898 shiftR2Left2Result(left, LSB, result, LSB, shCount, sign);
3902 /*-----------------------------------------------------------------*/
3903 /* genRightShiftLiteral - left shifting by known count */
3904 /*-----------------------------------------------------------------*/
3905 static void genRightShiftLiteral (operand *left,
3910 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3913 freeAsmop(right,NULL,ic);
3915 aopOp(left,ic,FALSE, FALSE);
3916 aopOp(result,ic,FALSE, FALSE);
3918 size = getSize(operandType(result));
3920 emitcode("; shift right ","result %d, left %d",size,
3923 /* I suppose that the left size >= result size */
3928 else if(shCount >= (size * 8))
3930 aopPut(AOP(result),zero,size);
3934 genrshOne(result, left, shCount);
3937 /* PENDING: sign support */
3938 genrshTwo(result, left, shCount, FALSE);
3947 freeAsmop(left,NULL,ic);
3948 freeAsmop(result,NULL,ic);
3951 /*-----------------------------------------------------------------*/
3952 /* genRightShift - generate code for right shifting */
3953 /*-----------------------------------------------------------------*/
3954 static void genRightShift (iCode *ic)
3956 operand *right, *left, *result;
3958 int size, offset, first = 1;
3962 symbol *tlbl, *tlbl1 ;
3964 /* if signed then we do it the hard way preserve the
3965 sign bit moving it inwards */
3966 retype = getSpec(operandType(IC_RESULT(ic)));
3968 is_signed = !SPEC_USIGN(retype);
3970 /* signed & unsigned types are treated the same : i.e. the
3971 signed is NOT propagated inwards : quoting from the
3972 ANSI - standard : "for E1 >> E2, is equivalent to division
3973 by 2**E2 if unsigned or if it has a non-negative value,
3974 otherwise the result is implementation defined ", MY definition
3975 is that the sign does not get propagated */
3977 right = IC_RIGHT(ic);
3979 result = IC_RESULT(ic);
3981 aopOp(right,ic,FALSE, FALSE);
3983 /* if the shift count is known then do it
3984 as efficiently as possible */
3985 if (AOP_TYPE(right) == AOP_LIT) {
3986 genRightShiftLiteral(left,right,result,ic);
3990 aopOp(left,ic,FALSE, FALSE);
3991 aopOp(result,ic,FALSE, FALSE);
3993 /* now move the left to the result if they are not the
3995 if (!sameRegs(AOP(left),AOP(result)) &&
3996 AOP_SIZE(result) > 1) {
3998 size = AOP_SIZE(result);
4001 l = aopGet(AOP(left),offset,FALSE);
4002 aopPut(AOP(result),l,offset);
4007 emitcode("ld", "a,%s",aopGet(AOP(right),0,FALSE));
4008 emitcode("inc","a");
4009 freeAsmop (right, NULL, ic);
4011 tlbl = newiTempLabel(NULL);
4012 tlbl1= newiTempLabel(NULL);
4013 size = AOP_SIZE(result);
4016 emit2("!shortjp !tlabel", tlbl1->key+100);
4017 emitLabel(tlbl->key+100);
4019 l = aopGet(AOP(result),offset--,FALSE);
4022 emitcode("sra", "%s", l);
4024 emitcode("srl", "%s", l);
4028 emitcode("rr", "%s", l);
4030 emitLabel(tlbl1->key+100);
4031 emitcode("dec", "a");
4032 emit2("!shortjp nz,!tlabel", tlbl->key+100);
4034 freeAsmop(left,NULL,ic);
4035 freeAsmop(result,NULL,ic);
4038 /*-----------------------------------------------------------------*/
4039 /* genGenPointerGet - get value from generic pointer space */
4040 /*-----------------------------------------------------------------*/
4041 static void genGenPointerGet (operand *left,
4042 operand *result, iCode *ic)
4045 link *retype = getSpec(operandType(result));
4051 aopOp(left,ic,FALSE, FALSE);
4052 aopOp(result,ic,FALSE, FALSE);
4054 if (isPair(AOP(left)) && AOP_SIZE(result)==1) {
4056 if (isPtrPair(AOP(left)))
4058 tsprintf(buffer, "!*pair", getPairName(AOP(left)));
4059 aopPut(AOP(result), buffer, 0);
4062 emit2("ld a,!*pair", getPairName(AOP(left)));
4063 aopPut(AOP(result),"a", 0);
4065 freeAsmop(left,NULL,ic);
4069 /* For now we always load into IY */
4070 /* if this is remateriazable */
4071 fetchPair(pair, AOP(left));
4073 /* so iy now contains the address */
4074 freeAsmop(left,NULL,ic);
4076 /* if bit then unpack */
4077 if (IS_BITVAR(retype)) {
4081 size = AOP_SIZE(result);
4085 /* PENDING: make this better */
4086 if (!IS_GB && AOP(result)->type == AOP_REG) {
4087 aopPut(AOP(result), "!*hl", offset++);
4090 emit2("ld a,!*pair", _pairs[pair].name);
4091 aopPut(AOP(result),"a",offset++);
4094 emit2("inc %s", _pairs[pair].name);
4100 freeAsmop(result,NULL,ic);
4103 /*-----------------------------------------------------------------*/
4104 /* genPointerGet - generate code for pointer get */
4105 /*-----------------------------------------------------------------*/
4106 static void genPointerGet (iCode *ic)
4108 operand *left, *result ;
4112 result = IC_RESULT(ic) ;
4114 /* depending on the type of pointer we need to
4115 move it to the correct pointer register */
4116 type = operandType(left);
4117 etype = getSpec(type);
4119 genGenPointerGet (left,result,ic);
4122 bool isRegOrLit(asmop *aop)
4124 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
4129 /*-----------------------------------------------------------------*/
4130 /* genGenPointerSet - stores the value into a pointer location */
4131 /*-----------------------------------------------------------------*/
4132 static void genGenPointerSet (operand *right,
4133 operand *result, iCode *ic)
4136 link *retype = getSpec(operandType(right));
4137 PAIR_ID pairId = PAIR_HL;
4139 aopOp(result,ic,FALSE, FALSE);
4140 aopOp(right,ic,FALSE, FALSE);
4145 /* Handle the exceptions first */
4146 if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
4148 char *l = aopGet(AOP(right), 0, FALSE);
4149 const char *pair = getPairName(AOP(result));
4150 if (canAssignToPtr(l) && isPtr(pair)) {
4151 emit2("ld !*pair,%s", pair, l);
4155 emit2("ld !*pair,a", pair);
4160 /* if the operand is already in dptr
4161 then we do nothing else we move the value to dptr */
4162 if (AOP_TYPE(result) != AOP_STR) {
4163 fetchPair(pairId, AOP(result));
4165 /* so hl know contains the address */
4166 freeAsmop(result,NULL,ic);
4168 /* if bit then unpack */
4169 if (IS_BITVAR(retype)) {
4173 size = AOP_SIZE(right);
4177 char *l = aopGet(AOP(right),offset,FALSE);
4178 if (isRegOrLit(AOP(right)) && !IS_GB) {
4179 emit2("ld !*pair,%s", _pairs[pairId].name, l);
4183 emit2("ld !*pair,a", _pairs[pairId].name);
4186 emitcode("inc", _pairs[pairId].name);
4192 freeAsmop(right,NULL,ic);
4195 /*-----------------------------------------------------------------*/
4196 /* genPointerSet - stores the value into a pointer location */
4197 /*-----------------------------------------------------------------*/
4198 static void genPointerSet (iCode *ic)
4200 operand *right, *result ;
4203 right = IC_RIGHT(ic);
4204 result = IC_RESULT(ic) ;
4206 /* depending on the type of pointer we need to
4207 move it to the correct pointer register */
4208 type = operandType(result);
4209 etype = getSpec(type);
4211 genGenPointerSet (right,result,ic);
4214 /*-----------------------------------------------------------------*/
4215 /* genIfx - generate code for Ifx statement */
4216 /*-----------------------------------------------------------------*/
4217 static void genIfx (iCode *ic, iCode *popIc)
4219 operand *cond = IC_COND(ic);
4222 aopOp(cond,ic,FALSE, TRUE);
4224 /* get the value into acc */
4225 if (AOP_TYPE(cond) != AOP_CRY)
4229 /* the result is now in the accumulator */
4230 freeAsmop(cond,NULL,ic);
4232 /* if there was something to be popped then do it */
4236 /* if the condition is a bit variable */
4237 if (isbit && IS_ITEMP(cond) &&
4239 genIfxJump(ic,SPIL_LOC(cond)->rname);
4241 if (isbit && !IS_ITEMP(cond))
4242 genIfxJump(ic,OP_SYMBOL(cond)->rname);
4249 /*-----------------------------------------------------------------*/
4250 /* genAddrOf - generates code for address of */
4251 /*-----------------------------------------------------------------*/
4252 static void genAddrOf (iCode *ic)
4254 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
4256 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
4258 /* if the operand is on the stack then we
4259 need to get the stack offset of this
4264 if (sym->stack <= 0) {
4265 emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
4268 emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
4270 emitcode("ld", "d,h");
4271 emitcode("ld", "e,l");
4274 emit2("ld de,!hashedstr", sym->rname);
4276 aopPut(AOP(IC_RESULT(ic)), "e", 0);
4277 aopPut(AOP(IC_RESULT(ic)), "d", 1);
4282 /* if it has an offset then we need to compute it */
4283 emitcode("ld", "hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
4284 emitcode("add", "hl,sp");
4287 emitcode("ld", "hl,#%s", sym->rname);
4289 aopPut(AOP(IC_RESULT(ic)), "l", 0);
4290 aopPut(AOP(IC_RESULT(ic)), "h", 1);
4292 freeAsmop(IC_RESULT(ic),NULL,ic);
4295 /*-----------------------------------------------------------------*/
4296 /* genAssign - generate code for assignment */
4297 /*-----------------------------------------------------------------*/
4298 static void genAssign (iCode *ic)
4300 operand *result, *right;
4302 unsigned long lit = 0L;
4304 result = IC_RESULT(ic);
4305 right = IC_RIGHT(ic) ;
4308 /* Dont bother assigning if they are the same */
4309 if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) {
4310 emitcode("", "; (operands are equal %u)", operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)));
4315 aopOp(right,ic,FALSE, FALSE);
4316 aopOp(result,ic,TRUE, FALSE);
4318 /* if they are the same registers */
4319 if (sameRegs(AOP(right),AOP(result))) {
4320 emitcode("", "; (registers are the same)");
4324 /* if the result is a bit */
4325 if (AOP_TYPE(result) == AOP_CRY) {
4330 size = AOP_SIZE(result);
4333 if(AOP_TYPE(right) == AOP_LIT)
4334 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
4335 if (isPair(AOP(result))) {
4336 fetchPair(getPairId(AOP(result)), AOP(right));
4338 else if((size > 1) &&
4339 (AOP_TYPE(result) != AOP_REG) &&
4340 (AOP_TYPE(right) == AOP_LIT) &&
4341 !IS_FLOAT(operandType(right)) &&
4343 bool fXored = FALSE;
4345 /* Work from the top down.
4346 Done this way so that we can use the cached copy of 0
4347 in A for a fast clear */
4349 if((unsigned int)((lit >> (offset*8)) & 0x0FFL)== 0) {
4350 if (!fXored && size>1) {
4351 emitcode("xor", "a,a");
4355 aopPut(AOP(result),"a",offset);
4358 aopPut(AOP(result), zero, offset);
4363 aopGet(AOP(right),offset,FALSE),
4368 else if (size == 2 && requiresHL(AOP(right)) && requiresHL(AOP(result)) && IS_GB) {
4369 /* Special case. Load into a and d, then load out. */
4370 MOVA(aopGet(AOP(right), 0, FALSE));
4371 emitcode("ld", "e,%s", aopGet(AOP(right), 1, FALSE));
4372 aopPut(AOP(result), "a", 0);
4373 aopPut(AOP(result), "e", 1);
4376 /* PENDING: do this check better */
4377 if (requiresHL(AOP(right)) && requiresHL(AOP(result))) {
4378 MOVA(aopGet(AOP(right), offset, FALSE));
4379 aopPut(AOP(result), "a", offset);
4383 aopGet(AOP(right),offset,FALSE),
4390 freeAsmop(right,NULL,ic);
4391 freeAsmop(result,NULL,ic);
4394 /*-----------------------------------------------------------------*/
4395 /* genJumpTab - genrates code for jump table */
4396 /*-----------------------------------------------------------------*/
4397 static void genJumpTab (iCode *ic)
4402 aopOp(IC_JTCOND(ic),ic,FALSE, FALSE);
4403 /* get the condition into accumulator */
4404 l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE);
4406 emitcode("push", "de");
4407 emitcode("ld", "e,%s", l);
4408 emit2("ld d,!zero");
4409 jtab = newiTempLabel(NULL);
4411 emit2("ld hl,!immed!tlabel", jtab->key+100);
4412 emitcode("add", "hl,de");
4413 emitcode("add", "hl,de");
4414 emitcode("add", "hl,de");
4415 freeAsmop(IC_JTCOND(ic),NULL,ic);
4417 emitcode("pop", "de");
4419 emitLabel(jtab->key+100);
4420 /* now generate the jump labels */
4421 for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
4422 jtab = setNextItem(IC_JTLABELS(ic)))
4423 emit2("jp !tlabel", jtab->key+100);
4426 /*-----------------------------------------------------------------*/
4427 /* genCast - gen code for casting */
4428 /*-----------------------------------------------------------------*/
4429 static void genCast (iCode *ic)
4431 operand *result = IC_RESULT(ic);
4432 link *ctype = operandType(IC_LEFT(ic));
4433 operand *right = IC_RIGHT(ic);
4436 /* if they are equivalent then do nothing */
4437 if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
4440 aopOp(right,ic,FALSE, FALSE);
4441 aopOp(result,ic,FALSE, FALSE);
4443 /* if the result is a bit */
4444 if (AOP_TYPE(result) == AOP_CRY) {
4448 /* if they are the same size : or less */
4449 if (AOP_SIZE(result) <= AOP_SIZE(right)) {
4451 /* if they are in the same place */
4452 if (sameRegs(AOP(right),AOP(result)))
4455 /* if they in different places then copy */
4456 size = AOP_SIZE(result);
4460 aopGet(AOP(right),offset,FALSE),
4467 /* PENDING: should be OK. */
4469 /* if the result is of type pointer */
4470 if (IS_PTR(ctype)) {
4475 /* so we now know that the size of destination is greater
4476 than the size of the source */
4477 /* we move to result for the size of source */
4478 size = AOP_SIZE(right);
4482 aopGet(AOP(right),offset,FALSE),
4487 /* now depending on the sign of the destination */
4488 size = AOP_SIZE(result) - AOP_SIZE(right);
4489 /* Unsigned or not an integral type - right fill with zeros */
4490 if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) {
4492 aopPut(AOP(result),zero,offset++);
4494 /* we need to extend the sign :{ */
4495 char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
4498 emitcode("", "; genCast: sign extend untested.");
4499 emitcode("rla", "");
4500 emitcode("sbc", "a,a");
4502 aopPut(AOP(result),"a",offset++);
4506 freeAsmop(right, NULL, ic);
4507 freeAsmop(result, NULL, ic);
4510 /*-----------------------------------------------------------------*/
4511 /* genReceive - generate code for a receive iCode */
4512 /*-----------------------------------------------------------------*/
4513 static void genReceive (iCode *ic)
4515 if (isOperandInFarSpace(IC_RESULT(ic)) &&
4516 ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
4517 IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
4521 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
4523 assignResultValue(IC_RESULT(ic));
4526 freeAsmop(IC_RESULT(ic),NULL,ic);
4529 /*-----------------------------------------------------------------*/
4530 /* genZ80Code - generate code for Z80 based controllers */
4531 /*-----------------------------------------------------------------*/
4532 void genZ80Code (iCode *lic)
4539 _fReturn = _gbz80_return;
4540 _fTmp = _gbz80_return;
4543 _fReturn = _z80_return;
4544 _fTmp = _z80_return;
4546 tsprintf(zero, "!zero");
4548 lineHead = lineCurr = NULL;
4550 /* if debug information required */
4551 if (options.debug && currFunc) {
4552 cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
4554 if (IS_STATIC(currFunc->etype))
4555 emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name);
4557 emitcode("","G$%s$0$0 ==.",currFunc->name);
4560 /* stack pointer name */
4564 for (ic = lic ; ic ; ic = ic->next ) {
4566 if ( cln != ic->lineno ) {
4567 if ( options.debug ) {
4569 emitcode("","C$%s$%d$%d$%d ==.",
4570 ic->filename,ic->lineno,
4571 ic->level,ic->block);
4574 emitcode(";","%s %d",ic->filename,ic->lineno);
4577 /* if the result is marked as
4578 spilt and rematerializable or code for
4579 this has already been generated then
4581 if (resultRemat(ic) || ic->generated )
4584 /* depending on the operation */
4587 emitcode("", "; genNot");
4592 emitcode("", "; genCpl");
4597 emitcode("", "; genUminus");
4602 emitcode("", "; genIpush");
4607 /* IPOP happens only when trying to restore a
4608 spilt live range, if there is an ifx statement
4609 following this pop then the if statement might
4610 be using some of the registers being popped which
4611 would destory the contents of the register so
4612 we need to check for this condition and handle it */
4614 ic->next->op == IFX &&
4615 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) {
4616 emitcode("", "; genIfx");
4617 genIfx (ic->next,ic);
4620 emitcode("", "; genIpop");
4626 emitcode("", "; genCall");
4631 emitcode("", "; genPcall");
4636 emitcode("", "; genFunction");
4641 emitcode("", "; genEndFunction");
4642 genEndFunction (ic);
4646 emitcode("", "; genRet");
4651 emitcode("", "; genLabel");
4656 emitcode("", "; genGoto");
4661 emitcode("", "; genPlus");
4666 emitcode("", "; genMinus");
4671 emitcode("", "; genMult");
4676 emitcode("", "; genDiv");
4681 emitcode("", "; genMod");
4686 emitcode("", "; genCmpGt");
4687 genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));
4691 emitcode("", "; genCmpLt");
4692 genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
4699 /* note these two are xlated by algebraic equivalence
4700 during parsing SDCC.y */
4701 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
4702 "got '>=' or '<=' shouldn't have come here");
4706 emitcode("", "; genCmpEq");
4707 genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
4711 emitcode("", "; genAndOp");
4716 emitcode("", "; genOrOp");
4721 emitcode("", "; genXor");
4722 genXor (ic,ifxForOp(IC_RESULT(ic),ic));
4726 emitcode("", "; genOr");
4727 genOr (ic,ifxForOp(IC_RESULT(ic),ic));
4731 emitcode("", "; genAnd");
4732 genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
4736 emitcode("", "; genInline");
4741 emitcode("", "; genRRC");
4746 emitcode("", "; genRLC");
4751 emitcode("", "; genHBIT");
4755 emitcode("", "; genLeftShift");
4760 emitcode("", "; genRightShift");
4764 case GET_VALUE_AT_ADDRESS:
4765 emitcode("", "; genPointerGet");
4771 if (POINTER_SET(ic)) {
4772 emitcode("", "; genAssign (pointer)");
4776 emitcode("", "; genAssign");
4782 emitcode("", "; genIfx");
4787 emitcode("", "; genAddrOf");
4792 emitcode("", "; genJumpTab");
4797 emitcode("", "; genCast");
4802 emitcode("", "; genReceive");
4807 emitcode("", "; addSet");
4808 addSet(&sendSet,ic);
4813 /* piCode(ic,stdout); */
4819 /* now we are ready to call the
4820 peep hole optimizer */
4821 if (!options.nopeep)
4822 peepHole (&lineHead);
4824 /* now do the actual printing */
4825 printLine (lineHead,codeOutFile);