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 - Sandeep Dutta . sandeep.dutta@usa.net (1998)
23 and - Jean-Louis VERN.jlvern@writeme.com (1999)
25 This program is free software; you can redistribute it and/or modify it
26 under the terms of the GNU General Public License as published by the
27 Free Software Foundation; either version 2, or (at your option) any
30 This program is distributed in the hope that it will be useful,
31 but WITHOUT ANY WARRANTY; without even the implied warranty of
32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 GNU General Public License for more details.
36 You should have received a copy of the GNU General Public License
37 along with this program; if not, write to the Free Software
38 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
40 In other words, you are welcome to use, share and improve this program.
41 You are forbidden to forbid anyone else to use, share and improve
42 what you give them. Help stamp out software-hoarding!
44 -------------------------------------------------------------------------*/
51 #ifdef HAVE_SYS_ISA_DEFS_H
52 #include <sys/isa_defs.h>
56 #include "SDCCpeeph.h"
60 /* this is the down and dirty file with all kinds of kludgy & hacky
61 stuff. This is what it is all about CODE GENERATION for a specific MCU.
62 Some of the routines may be reusable, will have to see */
65 static char *zero = "#0x00";
66 static char *one = "#0x01";
68 static char *_z80_return[] = {"l", "h", "e", "d" };
69 static char *_gbz80_return[] = { "e", "d", "l", "h" };
70 static char **_fReturn;
73 static char *accUse[] = {"a" };
79 extern int ptrRegReq ;
81 extern FILE *codeOutFile;
83 const char *_shortJP = "jp";
99 } _pairs[NUM_PAIRS] = {
104 { "iy", "iy.l?", "iy.h?" },
105 { "ix", "ix.l?", "ix.h?" }
108 #define RESULTONSTACK(x) \
109 (IC_RESULT(x) && IC_RESULT(x)->aop && \
110 IC_RESULT(x)->aop->type == AOP_STK )
112 #define MOVA(x) if (strcmp(x,"a")) emitcode("ld","a,%s",x);
113 #define CLRC emitcode("xor","a,a");
115 #define LABEL_STR "%05d$"
117 lineNode *lineHead = NULL;
118 lineNode *lineCurr = NULL;
120 unsigned char SLMask[] = {0xFF ,0xFE, 0xFC, 0xF8, 0xF0,
121 0xE0, 0xC0, 0x80, 0x00};
122 unsigned char SRMask[] = {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
123 0x07, 0x03, 0x01, 0x00};
151 static char *aopGet(asmop *aop, int offset, bool bit16);
153 static char *_strdup(const char *s)
156 ALLOC_ATOMIC(ret, strlen(s)+1);
161 /*-----------------------------------------------------------------*/
162 /* emitcode - writes the code into a file : for now it is simple */
163 /*-----------------------------------------------------------------*/
164 void emitcode (const char *inst, const char *fmt, ...)
167 char lb[MAX_INLINEASM];
173 sprintf(lb,"%s\t",inst);
174 vsprintf(lb+(strlen(lb)),fmt,ap);
178 while (isspace(*lbp)) lbp++;
181 lineCurr = (lineCurr ?
182 connectLine(lineCurr,newLineNode(lb)) :
183 (lineHead = newLineNode(lb)));
184 lineCurr->isInline = inLine;
185 lineCurr->isDebug = debugLine;
191 const char *szFormat;
194 static TOKEN _tokens[] = {
195 { "area", ".area %s" },
196 { "global", ".globl %s" },
197 { "labeldef", "%s::" },
198 { "tlabeldef", "%05d$:" },
199 { "fileprelude", "; Generated using the default tokens." },
201 "; ---------------------------------\n"
203 "; ---------------------------------"
205 { "functionlabeldef", "%s:" },
213 { "adjustsp", "\tlda sp,-%d(sp)" },
214 { "prelude", "\tpush bc" },
224 { "hli", "(hl+) ; 2" },
225 { "*hl", "(hl) ; 1" },
226 { "ldahlsp", "lda hl,%d(sp)" },
227 { "ldaspsp", "lda sp,%d(sp)" },
243 emitcode("ld", "sp,ix");
244 emitcode("pop", "ix");
245 emitcode("pop", "de");
250 #define NUM_TOKENS (sizeof(_tokens)/sizeof(_tokens[0]))
252 static const TOKEN *_findToken(const char *szName)
255 for (i=0; i < NUM_TOKENS; i++) {
256 if (!strcmp(_tokens[i].szName, szName))
262 static va_list _iprintf(char *pInto, const char *szFormat, va_list ap)
264 char *pStart = pInto;
265 char *sz = _strdup(szFormat);
270 /* See if it's a special emitter */
276 /* Scan out the arg and pass it on to sprintf */
280 /* Skip the format */
283 vsprintf(pInto, p, ap);
284 /* PENDING: Assume that the arg length was an int */
289 pInto = pStart + strlen(pStart);
300 static void vtprintf(char *buffer, const char *szFormat, va_list ap)
302 char *sz = _strdup(szFormat);
303 char *pInto = buffer, *p;
309 /* Start of a token. Search until the first
310 [non alplha, *] and call it a token. */
314 while (isalpha(*sz) || *sz == '*') {
319 /* Now find the token in the token list */
320 if ((t = _findToken(p))) {
321 ap = _iprintf(pInto, t->szFormat, ap);
322 pInto = buffer + strlen(buffer);
325 printf("Cant find token \"%s\"\n", p);
336 static void tprintf(char *buffer, const char *szFormat, ...)
340 va_start(ap, szFormat);
341 vtprintf(buffer, szFormat, ap);
344 static void emit2(const char *szFormat, ...)
349 va_start(ap, szFormat);
351 vtprintf(buffer, szFormat, ap);
353 lineCurr = (lineCurr ?
354 connectLine(lineCurr,newLineNode(buffer)) :
355 (lineHead = newLineNode(buffer)));
357 lineCurr->isInline = inLine;
358 lineCurr->isDebug = debugLine;
361 const char *getPairName(asmop *aop)
363 if (aop->type == AOP_REG) {
364 switch (aop->aopu.aop_reg[0]->rIdx) {
376 else if (aop->type == AOP_STR) {
377 switch (*aop->aopu.aop_str[0]) {
393 static PAIR_ID getPairId(asmop *aop)
395 if (aop->size == 2) {
396 if (aop->type == AOP_REG) {
397 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX)&&(aop->aopu.aop_reg[1]->rIdx == B_IDX)) {
400 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX)&&(aop->aopu.aop_reg[1]->rIdx == D_IDX)) {
403 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX)&&(aop->aopu.aop_reg[1]->rIdx == H_IDX)) {
407 if (aop->type == AOP_STR) {
408 if (!strcmp(aop->aopu.aop_str[0], "c")&&!strcmp(aop->aopu.aop_str[1], "b")) {
411 if (!strcmp(aop->aopu.aop_str[0], "e")&&!strcmp(aop->aopu.aop_str[1], "d")) {
414 if (!strcmp(aop->aopu.aop_str[0], "l")&&!strcmp(aop->aopu.aop_str[1], "h")) {
422 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
423 bool isPair(asmop *aop)
425 return (getPairId(aop) != PAIR_INVALID);
428 bool isPtrPair(asmop *aop)
430 PAIR_ID pairId = getPairId(aop);
440 /** Push a register pair onto the stack */
441 void genPairPush(asmop *aop)
443 emitcode("push", "%s", getPairName(aop));
447 /*-----------------------------------------------------------------*/
448 /* newAsmop - creates a new asmOp */
449 /*-----------------------------------------------------------------*/
450 static asmop *newAsmop (short type)
454 ALLOC(aop,sizeof(asmop));
459 /*-----------------------------------------------------------------*/
460 /* aopForSym - for a true symbol */
461 /*-----------------------------------------------------------------*/
462 static asmop *aopForSym (iCode *ic,symbol *sym,bool result)
465 memmap *space= SPEC_OCLS(sym->etype);
467 /* if already has one */
471 /* Assign depending on the storage class */
472 if (sym->onStack || sym->iaccess) {
473 sym->aop = aop = newAsmop(AOP_STK);
474 aop->size = getSize(sym->type);
475 aop->aopu.aop_stk = sym->stack;
479 /* special case for a function */
480 if (IS_FUNC(sym->type)) {
481 sym->aop = aop = newAsmop(AOP_IMMD);
482 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(sym->rname)+1);
483 strcpy(aop->aopu.aop_immd,sym->rname);
490 /* if it is in direct space */
491 if (IN_DIRSPACE(space)) {
492 sym->aop = aop = newAsmop (AOP_DIR);
493 aop->aopu.aop_dir = sym->rname ;
494 aop->size = getSize(sym->type);
495 emitcode("", "; AOP_DIR for %s", sym->rname);
501 /* only remaining is far space */
502 /* in which case DPTR gets the address */
504 sym->aop = aop = newAsmop(AOP_HL);
507 sym->aop = aop = newAsmop(AOP_IY);
509 aop->size = getSize(sym->type);
510 aop->aopu.aop_dir = sym->rname;
512 /* if it is in code space */
513 if (IN_CODESPACE(space))
519 /*-----------------------------------------------------------------*/
520 /* aopForRemat - rematerialzes an object */
521 /*-----------------------------------------------------------------*/
522 static asmop *aopForRemat (symbol *sym)
525 iCode *ic = sym->rematiCode;
526 asmop *aop = newAsmop(AOP_IMMD);
529 /* if plus or minus print the right hand side */
530 if (ic->op == '+' || ic->op == '-') {
531 sprintf(s,"0x%04x %c ",(int) operandLitValue(IC_RIGHT(ic)),
534 ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode;
537 /* we reached the end */
538 sprintf(s,"%s",OP_SYMBOL(IC_LEFT(ic))->rname);
542 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(buffer)+1);
543 strcpy(aop->aopu.aop_immd,buffer);
547 /*-----------------------------------------------------------------*/
548 /* regsInCommon - two operands have some registers in common */
549 /*-----------------------------------------------------------------*/
550 bool regsInCommon (operand *op1, operand *op2)
555 /* if they have registers in common */
556 if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
559 sym1 = OP_SYMBOL(op1);
560 sym2 = OP_SYMBOL(op2);
562 if (sym1->nRegs == 0 || sym2->nRegs == 0)
565 for (i = 0 ; i < sym1->nRegs ; i++) {
570 for (j = 0 ; j < sym2->nRegs ;j++ ) {
574 if (sym2->regs[j] == sym1->regs[i])
582 /*-----------------------------------------------------------------*/
583 /* operandsEqu - equivalent */
584 /*-----------------------------------------------------------------*/
585 bool operandsEqu ( operand *op1, operand *op2)
589 /* if they not symbols */
590 if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
593 sym1 = OP_SYMBOL(op1);
594 sym2 = OP_SYMBOL(op2);
596 /* if both are itemps & one is spilt
597 and the other is not then false */
598 if (IS_ITEMP(op1) && IS_ITEMP(op2) &&
599 sym1->isspilt != sym2->isspilt )
602 /* if they are the same */
606 if (strcmp(sym1->rname,sym2->rname) == 0)
610 /* if left is a tmp & right is not */
614 (sym1->usl.spillLoc == sym2))
621 (sym2->usl.spillLoc == sym1))
627 /*-----------------------------------------------------------------*/
628 /* sameRegs - two asmops have the same registers */
629 /*-----------------------------------------------------------------*/
630 bool sameRegs (asmop *aop1, asmop *aop2 )
637 if (aop1->type != AOP_REG ||
638 aop2->type != AOP_REG )
641 if (aop1->size != aop2->size)
644 for (i = 0 ; i < aop1->size ; i++ )
645 if (aop1->aopu.aop_reg[i] !=
646 aop2->aopu.aop_reg[i] )
652 /*-----------------------------------------------------------------*/
653 /* aopOp - allocates an asmop for an operand : */
654 /*-----------------------------------------------------------------*/
655 static void aopOp (operand *op, iCode *ic, bool result)
664 /* if this a literal */
665 if (IS_OP_LITERAL(op)) {
666 op->aop = aop = newAsmop(AOP_LIT);
667 aop->aopu.aop_lit = op->operand.valOperand;
668 aop->size = getSize(operandType(op));
672 /* if already has a asmop then continue */
676 /* if the underlying symbol has a aop */
677 if (IS_SYMOP(op) && OP_SYMBOL(op)->aop) {
678 op->aop = OP_SYMBOL(op)->aop;
682 /* if this is a true symbol */
683 if (IS_TRUE_SYMOP(op)) {
684 op->aop = aopForSym(ic,OP_SYMBOL(op),result);
688 /* this is a temporary : this has
694 e) can be a return use only */
698 /* if the type is a conditional */
699 if (sym->regType == REG_CND) {
700 aop = op->aop = sym->aop = newAsmop(AOP_CRY);
705 /* if it is spilt then two situations
707 b) has a spill location */
708 if (sym->isspilt || sym->nRegs == 0) {
709 /* rematerialize it NOW */
711 sym->aop = op->aop = aop =
713 aop->size = getSize(sym->type);
719 aop = op->aop = sym->aop = newAsmop(AOP_ACC);
720 aop->size = getSize(sym->type);
721 for ( i = 0 ; i < 2 ; i++ )
722 aop->aopu.aop_str[i] = accUse[i];
728 aop = op->aop = sym->aop = newAsmop(AOP_STR);
729 aop->size = getSize(sym->type);
730 for ( i = 0 ; i < 4 ; i++ )
731 aop->aopu.aop_str[i] = _fReturn[i];
735 /* else spill location */
736 sym->aop = op->aop = aop =
737 aopForSym(ic,sym->usl.spillLoc,result);
738 aop->size = getSize(sym->type);
742 /* must be in a register */
743 sym->aop = op->aop = aop = newAsmop(AOP_REG);
744 aop->size = sym->nRegs;
745 for ( i = 0 ; i < sym->nRegs ;i++)
746 aop->aopu.aop_reg[i] = sym->regs[i];
749 /*-----------------------------------------------------------------*/
750 /* freeAsmop - free up the asmop given to an operand */
751 /*----------------------------------------------------------------*/
752 static void freeAsmop (operand *op, asmop *aaop, iCode *ic)
770 /* all other cases just dealloc */
774 OP_SYMBOL(op)->aop = NULL;
775 /* if the symbol has a spill */
777 SPIL_LOC(op)->aop = NULL;
782 bool isLitWord(asmop *aop)
784 /* if (aop->size != 2)
795 char *aopGetLitWordLong(asmop *aop, int offset, bool with_hash)
801 if (aop->size != 2 && aop->type != AOP_HL)
804 wassert(offset == 0);
806 /* depending on type */
811 sprintf (s,"%s%s",with_hash ? "#" : "", aop->aopu.aop_immd);
812 ALLOC_ATOMIC(rs,strlen(s)+1);
816 value * val = aop->aopu.aop_lit;
817 /* if it is a float then it gets tricky */
818 /* otherwise it is fairly simple */
819 if (!IS_FLOAT(val->type)) {
820 unsigned long v = floatFromVal(val);
822 sprintf(buffer,"%s0x%04lx", with_hash ? "#" : "", v);
823 ALLOC_ATOMIC(rs,strlen(buffer)+1);
824 return strcpy (rs,buffer);
834 char *aopGetWord(asmop *aop, int offset)
836 return aopGetLitWordLong(aop, offset, TRUE);
839 bool isPtr(const char *s)
841 if (!strcmp(s, "hl"))
843 if (!strcmp(s, "ix"))
845 if (!strcmp(s, "iy"))
850 static void adjustPair(const char *pair, int *pold, int new)
854 while (*pold < new) {
855 emitcode("inc", "%s", pair);
858 while (*pold > new) {
859 emitcode("dec", "%s", pair);
864 static void spillPair(PAIR_ID pairId)
866 _G.pairs[pairId].last_type = AOP_INVALID;
867 _G.pairs[pairId].lit = NULL;
870 static void spillCached(void)
876 static bool requiresHL(asmop *aop)
887 static void fetchLitPair(PAIR_ID pairId, asmop *left, int offset)
890 const char *pair = _pairs[pairId].name;
891 l = aopGetLitWordLong(left, 0, FALSE);
895 if (pairId == PAIR_HL || pairId == PAIR_IY) {
896 if (_G.pairs[pairId].lit && !strcmp(_G.pairs[pairId].lit, l)) {
897 if (pairId == PAIR_HL && abs(_G.pairs[pairId].offset - offset) < 3) {
898 adjustPair(pair, &_G.pairs[pairId].offset, offset);
901 if (pairId == PAIR_IY && abs(offset)<127) {
906 _G.pairs[pairId].last_type = left->type;
907 _G.pairs[pairId].lit = _strdup(l);
908 _G.pairs[pairId].offset = offset;
910 /* Both a lit on the right and a true symbol on the left */
912 emitcode("ld", "%s,#%s + %d", pair, l, offset);
914 emitcode("ld", "%s,#%s", pair, l);
917 static void fetchPairLong(PAIR_ID pairId, asmop *aop, int offset)
919 /* if this is remateriazable */
920 if (isLitWord(aop)) {
921 fetchLitPair(pairId, aop, offset);
923 else { /* we need to get it byte by byte */
924 if (pairId == PAIR_HL && IS_GB && requiresHL(aop)) {
925 aopGet(aop, offset, FALSE);
931 emitcode("ld", "%s,%s", _pairs[pairId].l, aopGet(aop, offset, FALSE));
932 emitcode("ld", "%s,%s", _pairs[pairId].h, aopGet(aop, offset+1, FALSE));
934 /* PENDING: check? */
935 if (pairId == PAIR_HL)
940 static void fetchPair(PAIR_ID pairId, asmop *aop)
942 fetchPairLong(pairId, aop, 0);
945 static void fetchHL(asmop *aop)
947 fetchPair(PAIR_HL, aop);
950 static void setupPair(PAIR_ID pairId, asmop *aop, int offset)
952 assert(pairId == PAIR_HL || pairId == PAIR_IY);
957 fetchLitPair(pairId, aop, offset);
958 _G.pairs[pairId].offset = offset;
961 /* Doesnt include _G.stack.pushed */
962 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
963 assert(pairId == PAIR_HL);
964 /* In some cases we can still inc or dec hl */
965 if (_G.pairs[pairId].last_type == AOP_STK && abs(_G.pairs[pairId].offset - abso) < 3) {
966 adjustPair(_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
969 emit2("!ldahlsp", aop->aopu.aop_stk+offset + _G.stack.pushed + _G.stack.offset);
971 _G.pairs[pairId].offset = abso;
977 _G.pairs[pairId].last_type = aop->type;
980 static void emitLabel(int key)
982 emit2("!tlabeldef yeah?", key);
986 /*-----------------------------------------------------------------*/
987 /* aopGet - for fetching value of the aop */
988 /*-----------------------------------------------------------------*/
989 static char *aopGet(asmop *aop, int offset, bool bit16)
994 /* offset is greater than size then zero */
995 /* PENDING: this seems a bit screwed in some pointer cases. */
996 if (offset > (aop->size - 1) &&
997 aop->type != AOP_LIT)
1000 /* depending on type */
1001 switch (aop->type) {
1004 sprintf (s,"#%s ; 5",aop->aopu.aop_immd);
1007 wassert(offset == 1);
1009 aop->aopu.aop_immd);
1013 aop->aopu.aop_immd);
1014 ALLOC_ATOMIC(rs,strlen(s)+1);
1020 emitcode("ld", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
1022 ALLOC_ATOMIC(rs,strlen(s)+1);
1027 return aop->aopu.aop_reg[offset]->name;
1032 setupPair(PAIR_HL, aop, offset);
1038 setupPair(PAIR_IY, aop, offset);
1039 tprintf(s,"!*iyx", offset);
1040 ALLOC_ATOMIC(rs,strlen(s)+1);
1046 setupPair(PAIR_HL, aop, offset);
1050 tprintf(s,"!*ixx", aop->aopu.aop_stk+offset);
1052 ALLOC_ATOMIC(rs,strlen(s)+1);
1066 return aopLiteral (aop->aopu.aop_lit,offset);
1070 return aop->aopu.aop_str[offset];
1074 wassertl(0, "aopget got unsupported aop->type");
1078 bool isRegString(char *s)
1080 if (!strcmp(s, "b") ||
1091 bool isConstant(const char *s)
1096 bool canAssignToPtr(char *s)
1105 /*-----------------------------------------------------------------*/
1106 /* aopPut - puts a string for a aop */
1107 /*-----------------------------------------------------------------*/
1108 static void aopPut (asmop *aop, char *s, int offset)
1110 if (aop->size && offset > ( aop->size - 1)) {
1111 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1112 "aopPut got offset > aop->size");
1116 /* will assign value to value */
1117 /* depending on where it is ofcourse */
1118 switch (aop->type) {
1122 emitcode("ld", "a,%s", s);
1123 emitcode("ld", "(%s+%d),a", aop->aopu.aop_dir, offset);
1127 /* Dont bother if it's a ld x,x */
1128 if (strcmp(aop->aopu.aop_reg[offset]->name,s) != 0) {
1129 emitcode("ld","%s,%s",
1130 aop->aopu.aop_reg[offset]->name,s);
1136 setupPair(PAIR_IY, aop, offset);
1137 if (!canAssignToPtr(s)) {
1138 emitcode("ld", "a,%s", s);
1139 emitcode("ld", "%d(iy),a", offset);
1142 emitcode("ld", "%d(iy),%s", offset, s);
1147 if (!strcmp(s, "(hl)")) {
1148 emitcode("ld", "a,(hl)");
1152 setupPair(PAIR_HL, aop, offset);
1153 emitcode("ld", "(hl),%s", s);
1158 if (!strcmp("(hl)", s)) {
1159 emitcode("ld", "a,(hl)");
1162 setupPair(PAIR_HL, aop, offset);
1163 if (!canAssignToPtr(s)) {
1164 emitcode("ld", "a,%s", s);
1165 emitcode("ld", "(hl),a");
1168 emitcode("ld", "(hl),%s", s);
1171 if (!canAssignToPtr(s)) {
1172 emitcode("ld", "a,%s", s);
1173 emitcode("ld", "%d(ix),a", aop->aopu.aop_stk+offset);
1176 emitcode("ld", "%d(ix),%s", aop->aopu.aop_stk+offset, s);
1181 /* if bit variable */
1182 if (!aop->aopu.aop_dir) {
1183 emitcode("ld", "a,#0");
1184 emitcode("rla", "");
1186 /* In bit space but not in C - cant happen */
1193 if (strcmp(aop->aopu.aop_str[offset],s)) {
1194 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1200 if (!offset && (strcmp(s,"acc") == 0))
1204 emitcode("", "; Error aopPut AOP_ACC");
1207 if (strcmp(aop->aopu.aop_str[offset],s))
1208 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1213 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1214 "aopPut got unsupported aop->type");
1219 #define AOP(op) op->aop
1220 #define AOP_TYPE(op) AOP(op)->type
1221 #define AOP_SIZE(op) AOP(op)->size
1222 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1224 /*-----------------------------------------------------------------*/
1225 /* getDataSize - get the operand data size */
1226 /*-----------------------------------------------------------------*/
1227 int getDataSize(operand *op)
1230 size = AOP_SIZE(op);
1238 /*-----------------------------------------------------------------*/
1239 /* movLeft2Result - move byte from left to result */
1240 /*-----------------------------------------------------------------*/
1241 static void movLeft2Result (operand *left, int offl,
1242 operand *result, int offr, int sign)
1245 if(!sameRegs(AOP(left),AOP(result)) || (offl != offr)){
1246 l = aopGet(AOP(left),offl,FALSE);
1249 aopPut(AOP(result),l,offr);
1258 /** Put Acc into a register set
1260 void outAcc(operand *result)
1263 size = getDataSize(result);
1265 aopPut(AOP(result),"a",0);
1268 /* unsigned or positive */
1270 aopPut(AOP(result),zero,offset++);
1275 /** Take the value in carry and put it into a register
1277 void outBitC(operand *result)
1279 /* if the result is bit */
1280 if (AOP_TYPE(result) == AOP_CRY) {
1281 emitcode("", "; Note: outBitC form 1");
1282 aopPut(AOP(result),"blah",0);
1285 emitcode("ld", "a,#0");
1286 emitcode("rla", "");
1291 /*-----------------------------------------------------------------*/
1292 /* toBoolean - emit code for orl a,operator(sizeop) */
1293 /*-----------------------------------------------------------------*/
1294 void toBoolean(operand *oper)
1296 int size = AOP_SIZE(oper);
1299 emitcode("ld", "a,%s", aopGet(AOP(oper), offset++, FALSE));
1302 emitcode("or","a,%s",aopGet(AOP(oper),offset++,FALSE));
1305 if (AOP(oper)->type != AOP_ACC) {
1307 emitcode("or","a,%s",aopGet(AOP(oper),0,FALSE));
1312 /*-----------------------------------------------------------------*/
1313 /* genNot - generate code for ! operation */
1314 /*-----------------------------------------------------------------*/
1315 static void genNot (iCode *ic)
1317 link *optype = operandType(IC_LEFT(ic));
1319 /* assign asmOps to operand & result */
1320 aopOp (IC_LEFT(ic),ic,FALSE);
1321 aopOp (IC_RESULT(ic),ic,TRUE);
1323 /* if in bit space then a special case */
1324 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) {
1328 /* if type float then do float */
1329 if (IS_FLOAT(optype)) {
1333 toBoolean(IC_LEFT(ic));
1338 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1339 emitcode("sub", "a,#0x01");
1340 outBitC(IC_RESULT(ic));
1342 /* release the aops */
1343 freeAsmop(IC_LEFT(ic),NULL,ic);
1344 freeAsmop(IC_RESULT(ic),NULL,ic);
1347 /*-----------------------------------------------------------------*/
1348 /* genCpl - generate code for complement */
1349 /*-----------------------------------------------------------------*/
1350 static void genCpl (iCode *ic)
1356 /* assign asmOps to operand & result */
1357 aopOp (IC_LEFT(ic),ic,FALSE);
1358 aopOp (IC_RESULT(ic),ic,TRUE);
1360 /* if both are in bit space then
1362 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1363 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1367 size = AOP_SIZE(IC_RESULT(ic));
1369 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1372 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1375 /* release the aops */
1376 freeAsmop(IC_LEFT(ic),NULL,ic);
1377 freeAsmop(IC_RESULT(ic),NULL,ic);
1380 /*-----------------------------------------------------------------*/
1381 /* genUminus - unary minus code generation */
1382 /*-----------------------------------------------------------------*/
1383 static void genUminus (iCode *ic)
1386 link *optype, *rtype;
1389 aopOp(IC_LEFT(ic),ic,FALSE);
1390 aopOp(IC_RESULT(ic),ic,TRUE);
1392 /* if both in bit space then special
1394 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1395 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1400 optype = operandType(IC_LEFT(ic));
1401 rtype = operandType(IC_RESULT(ic));
1403 /* if float then do float stuff */
1404 if (IS_FLOAT(optype)) {
1409 /* otherwise subtract from zero */
1410 size = AOP_SIZE(IC_LEFT(ic));
1414 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1415 emitcode("ld", "a,#0");
1416 emitcode("sbc","a,%s",l);
1417 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1420 /* if any remaining bytes in the result */
1421 /* we just need to propagate the sign */
1422 if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic))))) {
1423 emitcode("rlc","a");
1424 emitcode("sbc","a,a");
1426 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1430 /* release the aops */
1431 freeAsmop(IC_LEFT(ic),NULL,ic);
1432 freeAsmop(IC_RESULT(ic),NULL,ic);
1435 /*-----------------------------------------------------------------*/
1436 /* assignResultValue - */
1437 /*-----------------------------------------------------------------*/
1438 void assignResultValue(operand * oper)
1440 int size = AOP_SIZE(oper);
1444 topInA = requiresHL(AOP(oper));
1448 if (IS_GB && size == 4 && requiresHL(AOP(oper))) {
1449 /* We do it the hard way here. */
1450 emitcode("push", "hl");
1451 _G.stack.pushed += 2;
1452 aopPut(AOP(oper), _fReturn[0], 0);
1453 aopPut(AOP(oper), _fReturn[1], 1);
1454 emitcode("pop", "de");
1455 _G.stack.pushed -= 2;
1456 aopPut(AOP(oper), _fReturn[0], 2);
1457 aopPut(AOP(oper), _fReturn[1], 3);
1461 aopPut(AOP(oper), _fReturn[size], size);
1466 /*-----------------------------------------------------------------*/
1467 /* genIpush - genrate code for pushing this gets a little complex */
1468 /*-----------------------------------------------------------------*/
1469 static void genIpush (iCode *ic)
1471 int size, offset = 0 ;
1475 /* if this is not a parm push : ie. it is spill push
1476 and spill push is always done on the local stack */
1477 if (!ic->parmPush) {
1478 /* and the item is spilt then do nothing */
1479 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1482 aopOp(IC_LEFT(ic),ic,FALSE);
1483 size = AOP_SIZE(IC_LEFT(ic));
1484 /* push it on the stack */
1485 if (isPair(AOP(IC_LEFT(ic)))) {
1486 emitcode("push", getPairName(AOP(IC_LEFT(ic))));
1487 _G.stack.pushed += 2;
1492 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1493 /* Simple for now - load into A and PUSH AF */
1494 emitcode("ld", "a,%s", l);
1495 emitcode("push", "af");
1496 emitcode("inc", "sp");
1503 /* Hmmm... what about saving the currently used registers
1506 /* then do the push */
1507 aopOp(IC_LEFT(ic),ic,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 ; 2");
1520 _G.stack.pushed += 2;
1525 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1526 emitcode("ld", "a,%s", l);
1527 emitcode("push", "af");
1528 emitcode("inc", "sp");
1533 freeAsmop(IC_LEFT(ic),NULL,ic);
1536 /*-----------------------------------------------------------------*/
1537 /* genIpop - recover the registers: can happen only for spilling */
1538 /*-----------------------------------------------------------------*/
1539 static void genIpop (iCode *ic)
1544 /* if the temp was not pushed then */
1545 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1548 aopOp(IC_LEFT(ic),ic,FALSE);
1549 size = AOP_SIZE(IC_LEFT(ic));
1551 if (isPair(AOP(IC_LEFT(ic)))) {
1552 emitcode("pop", getPairName(AOP(IC_LEFT(ic))));
1556 emitcode("dec", "sp");
1557 emitcode("pop", "hl");
1559 aopPut(AOP(IC_LEFT(ic)), "l", offset--);
1563 freeAsmop(IC_LEFT(ic),NULL,ic);
1566 /** Emit the code for a call statement
1568 static void emitCall (iCode *ic, bool ispcall)
1570 /* if caller saves & we have not saved then */
1571 if (!ic->regsSaved) {
1575 /* if send set is not empty then assign */
1578 for (sic = setFirstItem(sendSet) ; sic ;
1579 sic = setNextItem(sendSet)) {
1580 int size, offset = 0;
1581 aopOp(IC_LEFT(sic),sic,FALSE);
1582 size = AOP_SIZE(IC_LEFT(sic));
1584 char *l = aopGet(AOP(IC_LEFT(sic)),offset,
1586 if (strcmp(l, _fReturn[offset]))
1587 emitcode("ld","%s,%s",
1592 freeAsmop (IC_LEFT(sic),NULL,sic);
1598 aopOp(IC_LEFT(ic),ic,FALSE);
1600 if (isLitWord(AOP(IC_LEFT(ic)))) {
1601 emitcode("", "; Special case where the pCall is to a constant");
1602 emitcode("call", aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE));
1605 symbol *rlbl = newiTempLabel(NULL);
1607 emitcode("ld", "hl,#" LABEL_STR, (rlbl->key+100));
1608 emitcode("push", "hl");
1609 _G.stack.pushed += 2;
1611 fetchHL(AOP(IC_LEFT(ic)));
1612 emitcode("jp", "(hl)");
1613 emitcode("","%05d$:",(rlbl->key+100));
1614 _G.stack.pushed -= 2;
1616 freeAsmop(IC_LEFT(ic),NULL,ic);
1620 char *name = OP_SYMBOL(IC_LEFT(ic))->rname[0] ?
1621 OP_SYMBOL(IC_LEFT(ic))->rname :
1622 OP_SYMBOL(IC_LEFT(ic))->name;
1623 emitcode("call", "%s", name);
1627 /* if we need assign a result value */
1628 if ((IS_ITEMP(IC_RESULT(ic)) &&
1629 (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
1630 OP_SYMBOL(IC_RESULT(ic))->spildir )) ||
1631 IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
1634 aopOp(IC_RESULT(ic),ic,FALSE);
1637 assignResultValue(IC_RESULT(ic));
1639 freeAsmop(IC_RESULT(ic),NULL, ic);
1642 /* adjust the stack for parameters if required */
1643 if (IC_LEFT(ic)->parmBytes) {
1644 int i = IC_LEFT(ic)->parmBytes;
1645 _G.stack.pushed -= i;
1647 emit2("!ldaspsp", i);
1652 emitcode("ld", "hl,#%d", i);
1653 emitcode("add", "hl,sp");
1654 emitcode("ld", "sp,hl");
1658 emitcode("pop", "hl");
1662 emitcode("inc", "sp");
1670 /*-----------------------------------------------------------------*/
1671 /* genCall - generates a call statement */
1672 /*-----------------------------------------------------------------*/
1673 static void genCall (iCode *ic)
1675 emitCall(ic, FALSE);
1678 /*-----------------------------------------------------------------*/
1679 /* genPcall - generates a call by pointer statement */
1680 /*-----------------------------------------------------------------*/
1681 static void genPcall (iCode *ic)
1686 /*-----------------------------------------------------------------*/
1687 /* resultRemat - result is rematerializable */
1688 /*-----------------------------------------------------------------*/
1689 static int resultRemat (iCode *ic)
1691 if (SKIP_IC(ic) || ic->op == IFX)
1694 if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
1695 symbol *sym = OP_SYMBOL(IC_RESULT(ic));
1696 if (sym->remat && !POINTER_SET(ic))
1703 /*-----------------------------------------------------------------*/
1704 /* genFunction - generated code for function entry */
1705 /*-----------------------------------------------------------------*/
1706 static void genFunction (iCode *ic)
1708 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1712 /* create the function header */
1713 emit2("!functionheader", sym->name);
1714 emit2("!functionlabeldef", sym->rname);
1716 fetype = getSpec(operandType(IC_LEFT(ic)));
1718 /* if critical function then turn interrupts off */
1719 if (SPEC_CRTCL(fetype))
1722 /* if this is an interrupt service routine then
1723 save acc, b, dpl, dph */
1724 if (IS_ISR(sym->etype)) {
1727 /* PENDING: callee-save etc */
1729 /* adjust the stack for the function */
1732 _G.stack.last = sym->stack;
1735 emit2("!adjustsp", sym->stack);
1737 _G.stack.offset = sym->stack;
1740 /*-----------------------------------------------------------------*/
1741 /* genEndFunction - generates epilogue for functions */
1742 /*-----------------------------------------------------------------*/
1743 static void genEndFunction (iCode *ic)
1745 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1747 if (IS_ISR(sym->etype)) {
1751 if (SPEC_CRTCL(sym->etype))
1754 /* PENDING: calleeSave */
1756 /* if debug then send end of function */
1757 if (options.debug && currFunc) {
1759 emitcode("","C$%s$%d$%d$%d ==.",
1760 ic->filename,currFunc->lastLine,
1761 ic->level,ic->block);
1762 if (IS_STATIC(currFunc->etype))
1763 emitcode("","XF%s$%s$0$0 ==.",moduleName,currFunc->name);
1765 emitcode("","XG$%s$0$0 ==.",currFunc->name);
1768 if (_G.stack.offset)
1773 _G.stack.pushed = 0;
1774 _G.stack.offset = 0;
1777 /*-----------------------------------------------------------------*/
1778 /* genRet - generate code for return statement */
1779 /*-----------------------------------------------------------------*/
1780 static void genRet (iCode *ic)
1783 /* Errk. This is a hack until I can figure out how
1784 to cause dehl to spill on a call */
1785 int size,offset = 0;
1787 /* if we have no return value then
1788 just generate the "ret" */
1792 /* we have something to return then
1793 move the return value into place */
1794 aopOp(IC_LEFT(ic),ic,FALSE);
1795 size = AOP_SIZE(IC_LEFT(ic));
1797 if ((size == 2) && ((l = aopGetWord(AOP(IC_LEFT(ic)), 0)))) {
1799 emitcode("ld", "de,%s", l);
1802 emitcode("ld", "hl,%s", l);
1806 if (IS_GB && size == 4 && requiresHL(AOP(IC_LEFT(ic)))) {
1807 fetchPair(PAIR_DE, AOP(IC_LEFT(ic)));
1808 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
1812 l = aopGet(AOP(IC_LEFT(ic)),offset,
1814 if (strcmp(_fReturn[offset],l))
1815 emitcode("ld","%s,%s", _fReturn[offset++],l);
1819 freeAsmop (IC_LEFT(ic),NULL,ic);
1822 /* generate a jump to the return label
1823 if the next is not the return statement */
1824 if (!(ic->next && ic->next->op == LABEL &&
1825 IC_LABEL(ic->next) == returnLabel))
1827 emitcode("jp", LABEL_STR ,(returnLabel->key+100));
1830 /*-----------------------------------------------------------------*/
1831 /* genLabel - generates a label */
1832 /*-----------------------------------------------------------------*/
1833 static void genLabel (iCode *ic)
1835 /* special case never generate */
1836 if (IC_LABEL(ic) == entryLabel)
1839 emitLabel(IC_LABEL(ic)->key+100);
1842 /*-----------------------------------------------------------------*/
1843 /* genGoto - generates a ljmp */
1844 /*-----------------------------------------------------------------*/
1845 static void genGoto (iCode *ic)
1847 emitcode ("jp", LABEL_STR ,(IC_LABEL(ic)->key+100));
1850 /*-----------------------------------------------------------------*/
1851 /* genPlusIncr :- does addition with increment if possible */
1852 /*-----------------------------------------------------------------*/
1853 static bool genPlusIncr (iCode *ic)
1855 unsigned int icount ;
1856 unsigned int size = getDataSize(IC_RESULT(ic));
1857 PAIR_ID resultId = getPairId(AOP(IC_RESULT(ic)));
1859 /* will try to generate an increment */
1860 /* if the right side is not a literal
1862 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1865 emitcode("", "; genPlusIncr");
1867 icount = floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
1869 /* If result is a pair */
1870 if (resultId != PAIR_INVALID) {
1871 if (isLitWord(AOP(IC_LEFT(ic)))) {
1872 fetchLitPair(getPairId(AOP(IC_RESULT(ic))), AOP(IC_LEFT(ic)), icount);
1875 if (isPair(AOP(IC_LEFT(ic))) && resultId == PAIR_HL && icount > 2) {
1876 fetchPair(resultId, AOP(IC_RIGHT(ic)));
1877 emitcode("add", "hl,%s", getPairName(AOP(IC_LEFT(ic))));
1883 if (!sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
1886 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
1887 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
1890 emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
1895 /* if the literal value of the right hand side
1896 is greater than 4 then it is not worth it */
1900 /* if increment 16 bits in register */
1901 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1904 symbol *tlbl = newiTempLabel(NULL);
1905 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
1906 emitcode(_shortJP, "nz," LABEL_STR ,tlbl->key+100);
1908 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
1912 emitLabel(tlbl->key+100);
1916 /* if the sizes are greater than 1 then we cannot */
1917 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
1918 AOP_SIZE(IC_LEFT(ic)) > 1 )
1921 /* we can if the aops of the left & result match or
1922 if they are in registers and the registers are the
1924 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
1926 emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0, FALSE));
1934 /*-----------------------------------------------------------------*/
1935 /* outBitAcc - output a bit in acc */
1936 /*-----------------------------------------------------------------*/
1937 void outBitAcc(operand *result)
1939 symbol *tlbl = newiTempLabel(NULL);
1940 /* if the result is a bit */
1941 if (AOP_TYPE(result) == AOP_CRY){
1945 emitcode(_shortJP,"z," LABEL_STR ,tlbl->key+100);
1946 emitcode("ld","a,%s",one);
1947 emitLabel(tlbl->key+100);
1952 /*-----------------------------------------------------------------*/
1953 /* genPlus - generates code for addition */
1954 /*-----------------------------------------------------------------*/
1955 static void genPlus (iCode *ic)
1957 int size, offset = 0;
1959 /* special cases :- */
1961 aopOp (IC_LEFT(ic),ic,FALSE);
1962 aopOp (IC_RIGHT(ic),ic,FALSE);
1963 aopOp (IC_RESULT(ic),ic,TRUE);
1965 /* Swap the left and right operands if:
1967 if literal, literal on the right or
1968 if left requires ACC or right is already
1971 if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
1972 (AOP_NEEDSACC(IC_LEFT(ic))) ||
1973 AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
1974 operand *t = IC_RIGHT(ic);
1975 IC_RIGHT(ic) = IC_LEFT(ic);
1979 /* if both left & right are in bit
1981 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1982 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
1987 /* if left in bit space & right literal */
1988 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1989 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
1990 /* Can happen I guess */
1994 /* if I can do an increment instead
1995 of add then GOOD for ME */
1996 if (genPlusIncr (ic) == TRUE)
1999 size = getDataSize(IC_RESULT(ic));
2001 /* Special case when left and right are constant */
2002 if (isPair(AOP(IC_RESULT(ic)))) {
2005 left = aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE);
2006 right = aopGetLitWordLong(AOP(IC_RIGHT(ic)), 0, FALSE);
2007 if (left && right) {
2011 sprintf(buffer, "#(%s + %s)", left, right);
2012 emitcode("ld", "%s,%s", getPairName(AOP(IC_RESULT(ic))), buffer);
2017 if (isPair(AOP(IC_RIGHT(ic))) && getPairId(AOP(IC_RESULT(ic))) == PAIR_HL) {
2018 /* Fetch into HL then do the add */
2020 fetchPair(PAIR_HL, AOP(IC_LEFT(ic)));
2021 emitcode("add", "hl,%s", getPairName(AOP(IC_RIGHT(ic))));
2026 if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
2027 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2029 emitcode("add","a,%s",
2030 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2032 emitcode("adc","a,%s",
2033 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2035 MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2037 emitcode("add","a,%s",
2038 aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2040 emitcode("adc","a,%s",
2041 aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2043 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2046 /* Some kind of pointer arith. */
2047 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2048 AOP_SIZE(IC_LEFT(ic)) == 3 &&
2049 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2052 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2053 AOP_SIZE(IC_RIGHT(ic)) == 3 &&
2054 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
2059 freeAsmop(IC_LEFT(ic),NULL,ic);
2060 freeAsmop(IC_RIGHT(ic),NULL,ic);
2061 freeAsmop(IC_RESULT(ic),NULL,ic);
2065 /*-----------------------------------------------------------------*/
2066 /* genMinusDec :- does subtraction with deccrement if possible */
2067 /*-----------------------------------------------------------------*/
2068 static bool genMinusDec (iCode *ic)
2070 unsigned int icount ;
2071 unsigned int size = getDataSize(IC_RESULT(ic));
2073 /* will try to generate an increment */
2074 /* if the right side is not a literal we cannot */
2075 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
2078 /* if the literal value of the right hand side
2079 is greater than 4 then it is not worth it */
2080 if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
2083 size = getDataSize(IC_RESULT(ic));
2086 /* if increment 16 bits in register */
2087 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2090 symbol *tlbl = newiTempLabel(NULL);
2091 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
2092 emitcode("jp", "np," LABEL_STR ,tlbl->key+100);
2094 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
2098 emitLabel(tlbl->key+100);
2103 /* if decrement 16 bits in register */
2104 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2105 (size > 1) && isPair(AOP(IC_RESULT(ic)))) {
2107 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2111 /* If result is a pair */
2112 if (isPair(AOP(IC_RESULT(ic)))) {
2113 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
2114 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
2116 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2120 /* if the sizes are greater than 1 then we cannot */
2121 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2122 AOP_SIZE(IC_LEFT(ic)) > 1 )
2125 /* we can if the aops of the left & result match or if they are in
2126 registers and the registers are the same */
2127 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
2129 emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE));
2136 /*-----------------------------------------------------------------*/
2137 /* genMinus - generates code for subtraction */
2138 /*-----------------------------------------------------------------*/
2139 static void genMinus (iCode *ic)
2141 int size, offset = 0;
2142 unsigned long lit = 0L;
2144 aopOp (IC_LEFT(ic),ic,FALSE);
2145 aopOp (IC_RIGHT(ic),ic,FALSE);
2146 aopOp (IC_RESULT(ic),ic,TRUE);
2148 /* special cases :- */
2149 /* if both left & right are in bit space */
2150 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2151 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2156 /* if I can do an decrement instead of subtract then GOOD for ME */
2157 if (genMinusDec (ic) == TRUE)
2160 size = getDataSize(IC_RESULT(ic));
2162 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
2165 lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
2170 /* if literal, add a,#-lit, else normal subb */
2172 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2173 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) {
2175 emitcode("sub","a,%s",
2176 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2178 emitcode("sbc","a,%s",
2179 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2182 /* first add without previous c */
2184 emitcode("add","a,#0x%02x",
2185 (unsigned int)(lit & 0x0FFL));
2187 emitcode("adc","a,#0x%02x",
2188 (unsigned int)((lit >> (offset*8)) & 0x0FFL));
2190 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2193 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2194 AOP_SIZE(IC_LEFT(ic)) == 3 &&
2195 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2199 freeAsmop(IC_LEFT(ic),NULL,ic);
2200 freeAsmop(IC_RIGHT(ic),NULL,ic);
2201 freeAsmop(IC_RESULT(ic),NULL,ic);
2204 /*-----------------------------------------------------------------*/
2205 /* genMult - generates code for multiplication */
2206 /*-----------------------------------------------------------------*/
2207 static void genMult (iCode *ic)
2209 /* Shouldn't occur - all done through function calls */
2213 /*-----------------------------------------------------------------*/
2214 /* genDiv - generates code for division */
2215 /*-----------------------------------------------------------------*/
2216 static void genDiv (iCode *ic)
2218 /* Shouldn't occur - all done through function calls */
2222 /*-----------------------------------------------------------------*/
2223 /* genMod - generates code for division */
2224 /*-----------------------------------------------------------------*/
2225 static void genMod (iCode *ic)
2227 /* Shouldn't occur - all done through function calls */
2231 /*-----------------------------------------------------------------*/
2232 /* genIfxJump :- will create a jump depending on the ifx */
2233 /*-----------------------------------------------------------------*/
2234 static void genIfxJump (iCode *ic, char *jval)
2239 /* if true label then we jump if condition
2241 if ( IC_TRUE(ic) ) {
2243 if (!strcmp(jval, "a")) {
2246 else if (!strcmp(jval, "c")) {
2250 /* The buffer contains the bit on A that we should test */
2255 /* false label is present */
2256 jlbl = IC_FALSE(ic) ;
2257 if (!strcmp(jval, "a")) {
2260 else if (!strcmp(jval, "c")) {
2264 /* The buffer contains the bit on A that we should test */
2268 /* Z80 can do a conditional long jump */
2269 if (!strcmp(jval, "a")) {
2270 emitcode("or", "a,a");
2272 else if (!strcmp(jval, "c")) {
2275 emitcode("bit", "%s,a", jval);
2277 emitcode("jp", "%s," LABEL_STR , inst, jlbl->key+100);
2279 /* mark the icode as generated */
2283 /** Generic compare for > or <
2285 static void genCmp (operand *left,operand *right,
2286 operand *result, iCode *ifx, int sign)
2288 int size, offset = 0 ;
2289 unsigned long lit = 0L;
2291 /* if left & right are bit variables */
2292 if (AOP_TYPE(left) == AOP_CRY &&
2293 AOP_TYPE(right) == AOP_CRY ) {
2294 /* Cant happen on the Z80 */
2297 /* subtract right from left if at the
2298 end the carry flag is set then we know that
2299 left is greater than right */
2300 size = max(AOP_SIZE(left),AOP_SIZE(right));
2302 /* if unsigned char cmp with lit, just compare */
2304 (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
2305 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2307 emitcode("xor", "a,#0x80");
2308 emitcode("cp", "%s^0x80", aopGet(AOP(right), offset, FALSE));
2311 emitcode("cp", "%s ; 7", aopGet(AOP(right), offset, FALSE));
2314 if(AOP_TYPE(right) == AOP_LIT) {
2315 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2316 /* optimize if(x < 0) or if(x >= 0) */
2319 /* No sign so it's always false */
2323 /* Just load in the top most bit */
2324 MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE));
2325 if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx) {
2326 genIfxJump (ifx,"7");
2330 emitcode("rlc","a");
2336 /* First setup h and l contaning the top most bytes XORed */
2337 bool fDidXor = FALSE;
2338 if (AOP_TYPE(left) == AOP_LIT){
2339 unsigned long lit = (unsigned long)
2340 floatFromVal(AOP(left)->aopu.aop_lit);
2341 emitcode("ld", "%s,#0x%02x", _fTmp[0],
2342 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2345 emitcode("ld", "a,%s", aopGet(AOP(left), size-1, FALSE));
2346 emitcode("xor", "a,#0x80");
2347 emitcode("ld", "%s,a", _fTmp[0]);
2350 if (AOP_TYPE(right) == AOP_LIT) {
2351 unsigned long lit = (unsigned long)
2352 floatFromVal(AOP(right)->aopu.aop_lit);
2353 emitcode("ld", "%s,#0x%02x", _fTmp[1],
2354 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2357 emitcode("ld", "a,%s", aopGet(AOP(right), size-1, FALSE));
2358 emitcode("xor", "a,#0x80");
2359 emitcode("ld", "%s,a", _fTmp[1]);
2369 /* Do a long subtract */
2370 if (!sign || size ) {
2371 MOVA(aopGet(AOP(left),offset,FALSE));
2373 if (sign && size == 0) {
2374 emitcode("ld", "a,%s", _fTmp[0]);
2375 emitcode("sbc", "a,%s", _fTmp[1]);
2378 /* Subtract through, propagating the carry */
2379 emitcode("sbc","a,%s ; 2",aopGet(AOP(right),offset++,FALSE));
2386 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2389 /* if the result is used in the next
2390 ifx conditional branch then generate
2391 code a little differently */
2393 genIfxJump (ifx,"c");
2396 /* leave the result in acc */
2400 /*-----------------------------------------------------------------*/
2401 /* genCmpGt :- greater than comparison */
2402 /*-----------------------------------------------------------------*/
2403 static void genCmpGt (iCode *ic, iCode *ifx)
2405 operand *left, *right, *result;
2406 link *letype , *retype;
2410 right= IC_RIGHT(ic);
2411 result = IC_RESULT(ic);
2413 letype = getSpec(operandType(left));
2414 retype =getSpec(operandType(right));
2415 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2416 /* assign the amsops */
2417 aopOp (left,ic,FALSE);
2418 aopOp (right,ic,FALSE);
2419 aopOp (result,ic,TRUE);
2421 genCmp(right, left, result, ifx, sign);
2423 freeAsmop(left,NULL,ic);
2424 freeAsmop(right,NULL,ic);
2425 freeAsmop(result,NULL,ic);
2428 /*-----------------------------------------------------------------*/
2429 /* genCmpLt - less than comparisons */
2430 /*-----------------------------------------------------------------*/
2431 static void genCmpLt (iCode *ic, iCode *ifx)
2433 operand *left, *right, *result;
2434 link *letype , *retype;
2438 right= IC_RIGHT(ic);
2439 result = IC_RESULT(ic);
2441 letype = getSpec(operandType(left));
2442 retype =getSpec(operandType(right));
2443 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2445 /* assign the amsops */
2446 aopOp (left,ic,FALSE);
2447 aopOp (right,ic,FALSE);
2448 aopOp (result,ic,TRUE);
2450 genCmp(left, right, result, ifx, sign);
2452 freeAsmop(left,NULL,ic);
2453 freeAsmop(right,NULL,ic);
2454 freeAsmop(result,NULL,ic);
2457 /*-----------------------------------------------------------------*/
2458 /* gencjneshort - compare and jump if not equal */
2459 /*-----------------------------------------------------------------*/
2460 static void gencjneshort(operand *left, operand *right, symbol *lbl)
2462 int size = max(AOP_SIZE(left),AOP_SIZE(right));
2464 unsigned long lit = 0L;
2466 /* Swap the left and right if it makes the computation easier */
2467 if (AOP_TYPE(left) == AOP_LIT) {
2473 if(AOP_TYPE(right) == AOP_LIT)
2474 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2476 /* if the right side is a literal then anything goes */
2477 if (AOP_TYPE(right) == AOP_LIT &&
2478 AOP_TYPE(left) != AOP_DIR ) {
2480 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2485 emitcode("or", "a,%s", aopGet(AOP(left), offset, FALSE));
2489 emitcode("or", "a,a");
2491 emitcode("jp", "nz," LABEL_STR, lbl->key+100);
2495 emitcode("ld", "a,%s ; 2", aopGet(AOP(left),offset,FALSE));
2496 if ((AOP_TYPE(right) == AOP_LIT) && lit == 0)
2497 emitcode("or", "a,a");
2499 emitcode("cp", "a,%s", aopGet(AOP(right),offset,FALSE));
2500 emitcode("jp", "nz," LABEL_STR , lbl->key+100);
2505 /* if the right side is in a register or in direct space or
2506 if the left is a pointer register & right is not */
2507 else if (AOP_TYPE(right) == AOP_REG ||
2508 AOP_TYPE(right) == AOP_DIR ||
2509 (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT)) {
2511 MOVA(aopGet(AOP(left),offset,FALSE));
2512 if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
2513 ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
2515 emitcode("jp","nz," LABEL_STR ,lbl->key+100);
2517 emitcode("cp", "%s ; 4", aopGet(AOP(right),offset,FALSE));
2518 emitcode("jp", "nz," LABEL_STR , lbl->key+100);
2523 /* right is a pointer reg need both a & b */
2524 /* PENDING: is this required? */
2526 MOVA(aopGet(AOP(right),offset,FALSE));
2527 emitcode("cp", "%s ; 5", aopGet(AOP(left), offset, FALSE));
2528 emitcode("jr", "nz," LABEL_STR, lbl->key+100);
2534 /*-----------------------------------------------------------------*/
2535 /* gencjne - compare and jump if not equal */
2536 /*-----------------------------------------------------------------*/
2537 static void gencjne(operand *left, operand *right, symbol *lbl)
2539 symbol *tlbl = newiTempLabel(NULL);
2541 gencjneshort(left, right, lbl);
2544 emitcode("ld","a,%s",one);
2545 emitcode(_shortJP, LABEL_STR ,tlbl->key+100);
2546 emitLabel(lbl->key+100);
2547 emitcode("xor","a,a");
2548 emitLabel(tlbl->key+100);
2551 /*-----------------------------------------------------------------*/
2552 /* genCmpEq - generates code for equal to */
2553 /*-----------------------------------------------------------------*/
2554 static void genCmpEq (iCode *ic, iCode *ifx)
2556 operand *left, *right, *result;
2558 aopOp((left=IC_LEFT(ic)),ic,FALSE);
2559 aopOp((right=IC_RIGHT(ic)),ic,FALSE);
2560 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2562 /* Swap operands if it makes the operation easier. ie if:
2563 1. Left is a literal.
2565 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
2566 operand *t = IC_RIGHT(ic);
2567 IC_RIGHT(ic) = IC_LEFT(ic);
2571 if (ifx && !AOP_SIZE(result)){
2573 /* if they are both bit variables */
2574 if (AOP_TYPE(left) == AOP_CRY &&
2575 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2578 tlbl = newiTempLabel(NULL);
2579 gencjneshort(left, right, tlbl);
2580 if ( IC_TRUE(ifx) ) {
2581 emitcode("jp", LABEL_STR ,IC_TRUE(ifx)->key+100);
2582 emitLabel(tlbl->key+100);
2584 /* PENDING: do this better */
2585 symbol *lbl = newiTempLabel(NULL);
2586 emitcode(_shortJP, LABEL_STR ,lbl->key+100);
2587 emitLabel(tlbl->key+100);
2588 emitcode("jp", LABEL_STR ,IC_FALSE(ifx)->key+100);
2589 emitLabel(lbl->key+100);
2592 /* mark the icode as generated */
2597 /* if they are both bit variables */
2598 if (AOP_TYPE(left) == AOP_CRY &&
2599 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2602 gencjne(left,right,newiTempLabel(NULL));
2603 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2607 genIfxJump(ifx,"a");
2610 /* if the result is used in an arithmetic operation
2611 then put the result in place */
2612 if (AOP_TYPE(result) != AOP_CRY) {
2615 /* leave the result in acc */
2619 freeAsmop(left,NULL,ic);
2620 freeAsmop(right,NULL,ic);
2621 freeAsmop(result,NULL,ic);
2624 /*-----------------------------------------------------------------*/
2625 /* ifxForOp - returns the icode containing the ifx for operand */
2626 /*-----------------------------------------------------------------*/
2627 static iCode *ifxForOp ( operand *op, iCode *ic )
2629 /* if true symbol then needs to be assigned */
2630 if (IS_TRUE_SYMOP(op))
2633 /* if this has register type condition and
2634 the next instruction is ifx with the same operand
2635 and live to of the operand is upto the ifx only then */
2637 ic->next->op == IFX &&
2638 IC_COND(ic->next)->key == op->key &&
2639 OP_SYMBOL(op)->liveTo <= ic->next->seq )
2645 /*-----------------------------------------------------------------*/
2646 /* genAndOp - for && operation */
2647 /*-----------------------------------------------------------------*/
2648 static void genAndOp (iCode *ic)
2650 operand *left,*right, *result;
2653 /* note here that && operations that are in an if statement are
2654 taken away by backPatchLabels only those used in arthmetic
2655 operations remain */
2656 aopOp((left=IC_LEFT(ic)),ic,FALSE);
2657 aopOp((right=IC_RIGHT(ic)),ic,FALSE);
2658 aopOp((result=IC_RESULT(ic)),ic,FALSE);
2660 /* if both are bit variables */
2661 if (AOP_TYPE(left) == AOP_CRY &&
2662 AOP_TYPE(right) == AOP_CRY ) {
2665 tlbl = newiTempLabel(NULL);
2667 emitcode(_shortJP, "z," LABEL_STR ,tlbl->key+100);
2669 emitLabel(tlbl->key+100);
2673 freeAsmop(left,NULL,ic);
2674 freeAsmop(right,NULL,ic);
2675 freeAsmop(result,NULL,ic);
2678 /*-----------------------------------------------------------------*/
2679 /* genOrOp - for || operation */
2680 /*-----------------------------------------------------------------*/
2681 static void genOrOp (iCode *ic)
2683 operand *left,*right, *result;
2686 /* note here that || operations that are in an
2687 if statement are taken away by backPatchLabels
2688 only those used in arthmetic operations remain */
2689 aopOp((left=IC_LEFT(ic)),ic,FALSE);
2690 aopOp((right=IC_RIGHT(ic)),ic,FALSE);
2691 aopOp((result=IC_RESULT(ic)),ic,FALSE);
2693 /* if both are bit variables */
2694 if (AOP_TYPE(left) == AOP_CRY &&
2695 AOP_TYPE(right) == AOP_CRY ) {
2698 tlbl = newiTempLabel(NULL);
2700 emitcode(_shortJP, "nz," LABEL_STR,tlbl->key+100);
2702 emitLabel(tlbl->key+100);
2706 freeAsmop(left,NULL,ic);
2707 freeAsmop(right,NULL,ic);
2708 freeAsmop(result,NULL,ic);
2711 /*-----------------------------------------------------------------*/
2712 /* isLiteralBit - test if lit == 2^n */
2713 /*-----------------------------------------------------------------*/
2714 int isLiteralBit(unsigned long lit)
2716 unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
2717 0x100L,0x200L,0x400L,0x800L,
2718 0x1000L,0x2000L,0x4000L,0x8000L,
2719 0x10000L,0x20000L,0x40000L,0x80000L,
2720 0x100000L,0x200000L,0x400000L,0x800000L,
2721 0x1000000L,0x2000000L,0x4000000L,0x8000000L,
2722 0x10000000L,0x20000000L,0x40000000L,0x80000000L};
2725 for(idx = 0; idx < 32; idx++)
2731 /*-----------------------------------------------------------------*/
2732 /* jmpTrueOrFalse - */
2733 /*-----------------------------------------------------------------*/
2734 static void jmpTrueOrFalse (iCode *ic, symbol *tlbl)
2736 // ugly but optimized by peephole
2738 symbol *nlbl = newiTempLabel(NULL);
2739 emitcode("jp", LABEL_STR, nlbl->key+100);
2740 emitLabel(tlbl->key+100);
2741 emitcode("jp",LABEL_STR,IC_TRUE(ic)->key+100);
2742 emitLabel(nlbl->key+100);
2745 emitcode("jp", LABEL_STR, IC_FALSE(ic)->key+100);
2746 emitLabel(tlbl->key+100);
2751 /*-----------------------------------------------------------------*/
2752 /* genAnd - code for and */
2753 /*-----------------------------------------------------------------*/
2754 static void genAnd (iCode *ic, iCode *ifx)
2756 operand *left, *right, *result;
2758 unsigned long lit = 0L;
2761 aopOp((left = IC_LEFT(ic)),ic,FALSE);
2762 aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2763 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2766 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2768 AOP_TYPE(left), AOP_TYPE(right));
2769 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2771 AOP_SIZE(left), AOP_SIZE(right));
2774 /* if left is a literal & right is not then exchange them */
2775 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2776 AOP_NEEDSACC(left)) {
2777 operand *tmp = right ;
2782 /* if result = right then exchange them */
2783 if(sameRegs(AOP(result),AOP(right))){
2784 operand *tmp = right ;
2789 /* if right is bit then exchange them */
2790 if (AOP_TYPE(right) == AOP_CRY &&
2791 AOP_TYPE(left) != AOP_CRY){
2792 operand *tmp = right ;
2796 if(AOP_TYPE(right) == AOP_LIT)
2797 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2799 size = AOP_SIZE(result);
2801 if (AOP_TYPE(left) == AOP_CRY){
2806 // if(val & 0xZZ) - size = 0, ifx != FALSE -
2807 // bit = val & 0xZZ - size = 1, ifx = FALSE -
2808 if((AOP_TYPE(right) == AOP_LIT) &&
2809 (AOP_TYPE(result) == AOP_CRY) &&
2810 (AOP_TYPE(left) != AOP_CRY)) {
2811 int posbit = isLiteralBit(lit);
2815 MOVA(aopGet(AOP(left),posbit>>3,FALSE));
2819 emitcode("mov","c,acc.%d",posbit&0x07);
2824 sprintf(buffer, "%d", posbit&0x07);
2825 genIfxJump(ifx, buffer);
2833 symbol *tlbl = newiTempLabel(NULL);
2834 int sizel = AOP_SIZE(left);
2837 emitcode("setb","c");
2840 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
2841 MOVA( aopGet(AOP(left),offset,FALSE));
2843 if((posbit = isLiteralBit(bytelit)) != 0) {
2845 emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
2848 if(bytelit != 0x0FFL)
2849 emitcode("and","a,%s",
2850 aopGet(AOP(right),offset,FALSE));
2851 emitcode("jr","nz, %05d$",tlbl->key+100);
2856 // bit = left & literal
2858 emitcode("clr","c");
2859 emitcode("","%05d$:",tlbl->key+100);
2861 // if(left & literal)
2864 jmpTrueOrFalse(ifx, tlbl);
2872 /* if left is same as result */
2873 if(sameRegs(AOP(result),AOP(left))){
2874 for(;size--; offset++) {
2875 if(AOP_TYPE(right) == AOP_LIT){
2876 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
2880 aopPut(AOP(result),zero,offset);
2882 MOVA(aopGet(AOP(left),offset,FALSE));
2883 emitcode("and","a,%s",
2884 aopGet(AOP(right),offset,FALSE));
2885 emitcode("ld", "%s,a", aopGet(AOP(left),offset,FALSE));
2890 if (AOP_TYPE(left) == AOP_ACC) {
2894 MOVA(aopGet(AOP(right),offset,FALSE));
2895 emitcode("and","%s,a",
2896 aopGet(AOP(left),offset,FALSE));
2901 // left & result in different registers
2902 if(AOP_TYPE(result) == AOP_CRY){
2905 for(;(size--);offset++) {
2907 // result = left & right
2908 if(AOP_TYPE(right) == AOP_LIT){
2909 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
2911 aopGet(AOP(left),offset,FALSE),
2914 } else if(bytelit == 0){
2915 aopPut(AOP(result),zero,offset);
2919 // faster than result <- left, anl result,right
2920 // and better if result is SFR
2921 if (AOP_TYPE(left) == AOP_ACC)
2922 emitcode("and","a,%s",aopGet(AOP(right),offset,FALSE));
2924 MOVA(aopGet(AOP(right),offset,FALSE));
2925 emitcode("and","a,%s",
2926 aopGet(AOP(left),offset,FALSE));
2928 aopPut(AOP(result),"a",offset);
2935 freeAsmop(left,NULL,ic);
2936 freeAsmop(right,NULL,ic);
2937 freeAsmop(result,NULL,ic);
2940 /*-----------------------------------------------------------------*/
2941 /* genOr - code for or */
2942 /*-----------------------------------------------------------------*/
2943 static void genOr (iCode *ic, iCode *ifx)
2945 operand *left, *right, *result;
2947 unsigned long lit = 0L;
2949 aopOp((left = IC_LEFT(ic)),ic,FALSE);
2950 aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2951 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2954 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2956 AOP_TYPE(left), AOP_TYPE(right));
2957 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2959 AOP_SIZE(left), AOP_SIZE(right));
2962 /* if left is a literal & right is not then exchange them */
2963 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2964 AOP_NEEDSACC(left)) {
2965 operand *tmp = right ;
2970 /* if result = right then exchange them */
2971 if(sameRegs(AOP(result),AOP(right))){
2972 operand *tmp = right ;
2977 /* if right is bit then exchange them */
2978 if (AOP_TYPE(right) == AOP_CRY &&
2979 AOP_TYPE(left) != AOP_CRY){
2980 operand *tmp = right ;
2984 if(AOP_TYPE(right) == AOP_LIT)
2985 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2987 size = AOP_SIZE(result);
2989 if (AOP_TYPE(left) == AOP_CRY){
2994 if((AOP_TYPE(right) == AOP_LIT) &&
2995 (AOP_TYPE(result) == AOP_CRY) &&
2996 (AOP_TYPE(left) != AOP_CRY)){
3001 /* if left is same as result */
3002 if(sameRegs(AOP(result),AOP(left))){
3003 for(;size--; offset++) {
3004 if(AOP_TYPE(right) == AOP_LIT){
3005 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3008 MOVA(aopGet(AOP(right),offset,FALSE));
3009 emitcode("or","a,%s; 5",
3010 aopGet(AOP(left),offset,FALSE));
3011 aopPut(AOP(result),"a ; 8", offset);
3014 if (AOP_TYPE(left) == AOP_ACC)
3015 emitcode("or","a,%s ; 6",aopGet(AOP(right),offset,FALSE));
3017 MOVA(aopGet(AOP(right),offset,FALSE));
3018 emitcode("or","a,%s ; 7",
3019 aopGet(AOP(left),offset,FALSE));
3020 aopPut(AOP(result),"a ; 8", offset);
3025 // left & result in different registers
3026 if(AOP_TYPE(result) == AOP_CRY){
3028 } else for(;(size--);offset++){
3030 // result = left & right
3031 if(AOP_TYPE(right) == AOP_LIT){
3032 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3034 aopGet(AOP(left),offset,FALSE),
3039 // faster than result <- left, anl result,right
3040 // and better if result is SFR
3041 if (AOP_TYPE(left) == AOP_ACC)
3042 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
3044 MOVA(aopGet(AOP(right),offset,FALSE));
3045 emitcode("or","a,%s",
3046 aopGet(AOP(left),offset,FALSE));
3048 aopPut(AOP(result),"a",offset);
3049 /* PENDING: something weird is going on here. Add exception. */
3050 if (AOP_TYPE(result) == AOP_ACC)
3056 freeAsmop(left,NULL,ic);
3057 freeAsmop(right,NULL,ic);
3058 freeAsmop(result,NULL,ic);
3061 /*-----------------------------------------------------------------*/
3062 /* genXor - code for xclusive or */
3063 /*-----------------------------------------------------------------*/
3064 static void genXor (iCode *ic, iCode *ifx)
3066 operand *left, *right, *result;
3068 unsigned long lit = 0L;
3070 aopOp((left = IC_LEFT(ic)),ic,FALSE);
3071 aopOp((right= IC_RIGHT(ic)),ic,FALSE);
3072 aopOp((result=IC_RESULT(ic)),ic,TRUE);
3074 /* if left is a literal & right is not then exchange them */
3075 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3076 AOP_NEEDSACC(left)) {
3077 operand *tmp = right ;
3082 /* if result = right then exchange them */
3083 if(sameRegs(AOP(result),AOP(right))){
3084 operand *tmp = right ;
3089 /* if right is bit then exchange them */
3090 if (AOP_TYPE(right) == AOP_CRY &&
3091 AOP_TYPE(left) != AOP_CRY){
3092 operand *tmp = right ;
3096 if(AOP_TYPE(right) == AOP_LIT)
3097 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3099 size = AOP_SIZE(result);
3101 if (AOP_TYPE(left) == AOP_CRY){
3106 if((AOP_TYPE(right) == AOP_LIT) &&
3107 (AOP_TYPE(result) == AOP_CRY) &&
3108 (AOP_TYPE(left) != AOP_CRY)){
3113 /* if left is same as result */
3114 if(sameRegs(AOP(result),AOP(left))){
3115 for(;size--; offset++) {
3116 if(AOP_TYPE(right) == AOP_LIT){
3117 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3120 MOVA(aopGet(AOP(right),offset,FALSE));
3121 emitcode("xor","a,%s",
3122 aopGet(AOP(left),offset,FALSE));
3123 aopPut(AOP(result),"a",0);
3126 if (AOP_TYPE(left) == AOP_ACC)
3127 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3129 MOVA(aopGet(AOP(right),offset,FALSE));
3130 emitcode("xor","a,%s",
3131 aopGet(AOP(left),offset,FALSE));
3132 aopPut(AOP(result),"a",0);
3137 // left & result in different registers
3138 if(AOP_TYPE(result) == AOP_CRY){
3140 } else for(;(size--);offset++){
3142 // result = left & right
3143 if(AOP_TYPE(right) == AOP_LIT){
3144 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3146 aopGet(AOP(left),offset,FALSE),
3151 // faster than result <- left, anl result,right
3152 // and better if result is SFR
3153 if (AOP_TYPE(left) == AOP_ACC)
3154 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3156 MOVA(aopGet(AOP(right),offset,FALSE));
3157 emitcode("xor","a,%s",
3158 aopGet(AOP(left),offset,FALSE));
3159 aopPut(AOP(result),"a",0);
3161 aopPut(AOP(result),"a",offset);
3166 freeAsmop(left,NULL,ic);
3167 freeAsmop(right,NULL,ic);
3168 freeAsmop(result,NULL,ic);
3171 /*-----------------------------------------------------------------*/
3172 /* genInline - write the inline code out */
3173 /*-----------------------------------------------------------------*/
3174 static void genInline (iCode *ic)
3176 char buffer[MAX_INLINEASM];
3180 inLine += (!options.asmpeep);
3181 strcpy(buffer,IC_INLINE(ic));
3183 /* emit each line as a code */
3202 /* emitcode("",buffer); */
3203 inLine -= (!options.asmpeep);
3206 /*-----------------------------------------------------------------*/
3207 /* genRRC - rotate right with carry */
3208 /*-----------------------------------------------------------------*/
3209 static void genRRC (iCode *ic)
3214 /*-----------------------------------------------------------------*/
3215 /* genRLC - generate code for rotate left with carry */
3216 /*-----------------------------------------------------------------*/
3217 static void genRLC (iCode *ic)
3222 /*-----------------------------------------------------------------*/
3223 /* shiftR2Left2Result - shift right two bytes from left to result */
3224 /*-----------------------------------------------------------------*/
3225 static void shiftR2Left2Result (operand *left, int offl,
3226 operand *result, int offr,
3227 int shCount, int sign)
3229 if(sameRegs(AOP(result), AOP(left)) &&
3230 ((offl + MSB16) == offr)){
3233 movLeft2Result(left, offl, result, offr, 0);
3234 movLeft2Result(left, offl+1, result, offr+1, 0);
3241 /* if (AOP(result)->type == AOP_REG) {*/
3244 symbol *tlbl , *tlbl1;
3247 /* Left is already in result - so now do the shift */
3249 emitcode("ld","a,#%u+1", shCount);
3250 tlbl = newiTempLabel(NULL);
3251 tlbl1 = newiTempLabel(NULL);
3252 emitcode(_shortJP, LABEL_STR ,tlbl1->key+100);
3253 emitLabel(tlbl->key+100);
3256 emitcode("or", "a,a");
3259 l = aopGet(AOP(result), --offset, FALSE);
3260 emitcode("rr","%s", l);
3263 emitLabel(tlbl1->key+100);
3264 emitcode("dec", "a");
3265 emitcode(_shortJP,"nz," LABEL_STR ,tlbl->key+100);
3270 /*-----------------------------------------------------------------*/
3271 /* shiftL2Left2Result - shift left two bytes from left to result */
3272 /*-----------------------------------------------------------------*/
3273 static void shiftL2Left2Result (operand *left, int offl,
3274 operand *result, int offr, int shCount)
3276 if(sameRegs(AOP(result), AOP(left)) &&
3277 ((offl + MSB16) == offr)){
3280 /* Copy left into result */
3281 movLeft2Result(left, offl, result, offr, 0);
3282 movLeft2Result(left, offl+1, result, offr+1, 0);
3284 /* PENDING: for now just see if it'll work. */
3285 /*if (AOP(result)->type == AOP_REG) { */
3289 symbol *tlbl , *tlbl1;
3292 /* Left is already in result - so now do the shift */
3294 emitcode("ld","a,#%u+1", shCount);
3295 tlbl = newiTempLabel(NULL);
3296 tlbl1 = newiTempLabel(NULL);
3297 emitcode(_shortJP, LABEL_STR ,tlbl1->key+100);
3298 emitLabel(tlbl->key+100);
3301 emitcode("or", "a,a");
3303 l = aopGet(AOP(result),offset++,FALSE);
3304 emitcode("rl","%s", l);
3307 emitLabel(tlbl1->key+100);
3308 emitcode("dec", "a");
3309 emitcode(_shortJP,"nz," LABEL_STR ,tlbl->key+100);
3314 /*-----------------------------------------------------------------*/
3315 /* AccRol - rotate left accumulator by known count */
3316 /*-----------------------------------------------------------------*/
3317 static void AccRol (int shCount)
3319 shCount &= 0x0007; // shCount : 0..7
3356 /*-----------------------------------------------------------------*/
3357 /* AccLsh - left shift accumulator by known count */
3358 /*-----------------------------------------------------------------*/
3359 static void AccLsh (int shCount)
3363 emitcode("add","a,a");
3366 emitcode("add","a,a");
3367 emitcode("add","a,a");
3369 /* rotate left accumulator */
3371 /* and kill the lower order bits */
3372 emitcode("and","a,#0x%02x", SLMask[shCount]);
3377 /*-----------------------------------------------------------------*/
3378 /* shiftL1Left2Result - shift left one byte from left to result */
3379 /*-----------------------------------------------------------------*/
3380 static void shiftL1Left2Result (operand *left, int offl,
3381 operand *result, int offr, int shCount)
3384 l = aopGet(AOP(left),offl,FALSE);
3386 /* shift left accumulator */
3388 aopPut(AOP(result),"a",offr);
3392 /*-----------------------------------------------------------------*/
3393 /* genlshTwo - left shift two bytes by known amount != 0 */
3394 /*-----------------------------------------------------------------*/
3395 static void genlshTwo (operand *result,operand *left, int shCount)
3397 int size = AOP_SIZE(result);
3401 /* if shCount >= 8 */
3407 movLeft2Result(left, LSB, result, MSB16, 0);
3408 aopPut(AOP(result),zero, 0);
3409 shiftL1Left2Result(left, MSB16, result, MSB16, shCount-8);
3412 movLeft2Result(left, LSB, result, MSB16, 0);
3413 aopPut(AOP(result),zero, 0);
3416 aopPut(AOP(result),zero,LSB);
3418 /* 1 <= shCount <= 7 */
3424 shiftL2Left2Result(left, LSB, result, LSB, shCount);
3429 /*-----------------------------------------------------------------*/
3430 /* genlshOne - left shift a one byte quantity by known count */
3431 /*-----------------------------------------------------------------*/
3432 static void genlshOne (operand *result, operand *left, int shCount)
3434 shiftL1Left2Result(left, LSB, result, LSB, shCount);
3437 /*-----------------------------------------------------------------*/
3438 /* genLeftShiftLiteral - left shifting by known count */
3439 /*-----------------------------------------------------------------*/
3440 static void genLeftShiftLiteral (operand *left,
3445 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3448 freeAsmop(right,NULL,ic);
3450 aopOp(left,ic,FALSE);
3451 aopOp(result,ic,FALSE);
3453 size = getSize(operandType(result));
3456 emitcode("; shift left ","result %d, left %d",size,
3460 /* I suppose that the left size >= result size */
3465 else if(shCount >= (size * 8))
3467 aopPut(AOP(result),zero,size);
3471 genlshOne (result,left,shCount);
3474 genlshTwo (result,left,shCount);
3483 freeAsmop(left,NULL,ic);
3484 freeAsmop(result,NULL,ic);
3487 /*-----------------------------------------------------------------*/
3488 /* genLeftShift - generates code for left shifting */
3489 /*-----------------------------------------------------------------*/
3490 static void genLeftShift (iCode *ic)
3494 symbol *tlbl , *tlbl1;
3495 operand *left,*right, *result;
3497 right = IC_RIGHT(ic);
3499 result = IC_RESULT(ic);
3501 aopOp(right,ic,FALSE);
3503 /* if the shift count is known then do it
3504 as efficiently as possible */
3505 if (AOP_TYPE(right) == AOP_LIT) {
3506 genLeftShiftLiteral (left,right,result,ic);
3510 /* shift count is unknown then we have to form a loop get the loop
3511 count in B : Note: we take only the lower order byte since
3512 shifting more that 32 bits make no sense anyway, ( the largest
3513 size of an object can be only 32 bits ) */
3514 emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE));
3515 emitcode("inc","a");
3516 freeAsmop (right,NULL,ic);
3517 aopOp(left,ic,FALSE);
3518 aopOp(result,ic,FALSE);
3520 /* now move the left to the result if they are not the
3523 if (!sameRegs(AOP(left),AOP(result))) {
3525 size = AOP_SIZE(result);
3528 l = aopGet(AOP(left),offset,FALSE);
3529 aopPut(AOP(result),l,offset);
3534 size = AOP_SIZE(result);
3537 l = aopGet(AOP(left),offset,FALSE);
3538 aopPut(AOP(result),l,offset);
3544 tlbl = newiTempLabel(NULL);
3545 size = AOP_SIZE(result);
3547 tlbl1 = newiTempLabel(NULL);
3549 emitcode(_shortJP, LABEL_STR ,tlbl1->key+100);
3550 emitLabel(tlbl->key+100);
3551 l = aopGet(AOP(result),offset,FALSE);
3552 emitcode("or", "a,a");
3554 l = aopGet(AOP(result),offset++,FALSE);
3555 emitcode("rl","%s", l);
3557 emitLabel(tlbl1->key+100);
3558 emitcode("dec", "a");
3559 emitcode(_shortJP,"nz," LABEL_STR ,tlbl->key+100);
3561 freeAsmop(left,NULL,ic);
3562 freeAsmop(result,NULL,ic);
3565 /*-----------------------------------------------------------------*/
3566 /* genlshTwo - left shift two bytes by known amount != 0 */
3567 /*-----------------------------------------------------------------*/
3568 static void genrshOne (operand *result,operand *left, int shCount)
3571 int size = AOP_SIZE(result);
3577 l = aopGet(AOP(left),0,FALSE);
3578 if (AOP(result)->type == AOP_REG) {
3579 aopPut(AOP(result), l, 0);
3580 l = aopGet(AOP(result), 0, FALSE);
3582 emitcode("srl", "%s", l);
3587 emitcode("srl", "a");
3589 aopPut(AOP(result),"a",0);
3593 /*-----------------------------------------------------------------*/
3594 /* AccRsh - right shift accumulator by known count */
3595 /*-----------------------------------------------------------------*/
3596 static void AccRsh (int shCount)
3603 /* rotate right accumulator */
3604 AccRol(8 - shCount);
3605 /* and kill the higher order bits */
3606 emitcode("and","a,#0x%02x", SRMask[shCount]);
3611 /*-----------------------------------------------------------------*/
3612 /* shiftR1Left2Result - shift right one byte from left to result */
3613 /*-----------------------------------------------------------------*/
3614 static void shiftR1Left2Result (operand *left, int offl,
3615 operand *result, int offr,
3616 int shCount, int sign)
3618 MOVA(aopGet(AOP(left),offl,FALSE));
3625 aopPut(AOP(result),"a",offr);
3628 /*-----------------------------------------------------------------*/
3629 /* genrshTwo - right shift two bytes by known amount != 0 */
3630 /*-----------------------------------------------------------------*/
3631 static void genrshTwo (operand *result,operand *left,
3632 int shCount, int sign)
3634 /* if shCount >= 8 */
3639 shiftR1Left2Result(left, MSB16, result, LSB,
3643 movLeft2Result(left, MSB16, result, LSB, sign);
3644 aopPut(AOP(result),zero,1);
3647 /* 1 <= shCount <= 7 */
3649 shiftR2Left2Result(left, LSB, result, LSB, shCount, sign);
3653 /*-----------------------------------------------------------------*/
3654 /* genRightShiftLiteral - left shifting by known count */
3655 /*-----------------------------------------------------------------*/
3656 static void genRightShiftLiteral (operand *left,
3661 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3664 freeAsmop(right,NULL,ic);
3666 aopOp(left,ic,FALSE);
3667 aopOp(result,ic,FALSE);
3669 size = getSize(operandType(result));
3671 emitcode("; shift right ","result %d, left %d",size,
3674 /* I suppose that the left size >= result size */
3679 else if(shCount >= (size * 8))
3681 aopPut(AOP(result),zero,size);
3685 genrshOne(result, left, shCount);
3688 /* PENDING: sign support */
3689 genrshTwo(result, left, shCount, FALSE);
3698 freeAsmop(left,NULL,ic);
3699 freeAsmop(result,NULL,ic);
3702 /*-----------------------------------------------------------------*/
3703 /* genRightShift - generate code for right shifting */
3704 /*-----------------------------------------------------------------*/
3705 static void genRightShift (iCode *ic)
3707 operand *right, *left, *result;
3709 int size, offset, first = 1;
3713 symbol *tlbl, *tlbl1 ;
3715 /* if signed then we do it the hard way preserve the
3716 sign bit moving it inwards */
3717 retype = getSpec(operandType(IC_RESULT(ic)));
3719 is_signed = !SPEC_USIGN(retype);
3721 /* signed & unsigned types are treated the same : i.e. the
3722 signed is NOT propagated inwards : quoting from the
3723 ANSI - standard : "for E1 >> E2, is equivalent to division
3724 by 2**E2 if unsigned or if it has a non-negative value,
3725 otherwise the result is implementation defined ", MY definition
3726 is that the sign does not get propagated */
3728 right = IC_RIGHT(ic);
3730 result = IC_RESULT(ic);
3732 aopOp(right,ic,FALSE);
3734 /* if the shift count is known then do it
3735 as efficiently as possible */
3736 if (AOP_TYPE(right) == AOP_LIT) {
3737 genRightShiftLiteral(left,right,result,ic);
3741 aopOp(left,ic,FALSE);
3742 aopOp(result,ic,FALSE);
3744 /* now move the left to the result if they are not the
3746 if (!sameRegs(AOP(left),AOP(result)) &&
3747 AOP_SIZE(result) > 1) {
3749 size = AOP_SIZE(result);
3752 l = aopGet(AOP(left),offset,FALSE);
3753 aopPut(AOP(result),l,offset);
3758 emitcode("ld", "a,%s",aopGet(AOP(right),0,FALSE));
3759 emitcode("inc","a");
3760 freeAsmop (right, NULL, ic);
3762 tlbl = newiTempLabel(NULL);
3763 tlbl1= newiTempLabel(NULL);
3764 size = AOP_SIZE(result);
3767 emitcode(_shortJP, LABEL_STR, tlbl1->key+100);
3768 emitcode("", LABEL_STR ":", tlbl->key+100);
3770 l = aopGet(AOP(result),offset--,FALSE);
3773 emitcode("sra", "%s", l);
3775 emitcode("srl", "%s", l);
3779 emitcode("rr", "%s", l);
3781 emitcode("", LABEL_STR ":", tlbl1->key+100);
3782 emitcode("dec", "a");
3783 emitcode(_shortJP, "nz," LABEL_STR, tlbl->key+100);
3785 freeAsmop(left,NULL,ic);
3786 freeAsmop(result,NULL,ic);
3789 /*-----------------------------------------------------------------*/
3790 /* genGenPointerGet - gget value from generic pointer space */
3791 /*-----------------------------------------------------------------*/
3792 static void genGenPointerGet (operand *left,
3793 operand *result, iCode *ic)
3796 link *retype = getSpec(operandType(result));
3802 aopOp(left,ic,FALSE);
3803 aopOp(result,ic,FALSE);
3805 if (isPair(AOP(left)) && AOP_SIZE(result)==1) {
3807 if (isPtrPair(AOP(left)))
3809 sprintf(buffer, "(%s)", getPairName(AOP(left)));
3810 aopPut(AOP(result), buffer, 0);
3813 emitcode("ld", "a,(%s)", getPairName(AOP(left)));
3814 aopPut(AOP(result),"a", 0);
3816 freeAsmop(left,NULL,ic);
3820 /* For now we always load into IY */
3821 /* if this is remateriazable */
3822 fetchPair(pair, AOP(left));
3824 /* so iy now contains the address */
3825 freeAsmop(left,NULL,ic);
3827 /* if bit then unpack */
3828 if (IS_BITVAR(retype)) {
3832 size = AOP_SIZE(result);
3836 /* PENDING: make this better */
3837 if (!IS_GB && AOP(result)->type == AOP_REG) {
3838 aopPut(AOP(result),"(hl)",offset++);
3841 emitcode("ld", "a,(%s)", _pairs[pair].name, offset);
3842 aopPut(AOP(result),"a",offset++);
3845 emitcode("inc", "%s", _pairs[pair].name);
3851 freeAsmop(result,NULL,ic);
3854 /*-----------------------------------------------------------------*/
3855 /* genPointerGet - generate code for pointer get */
3856 /*-----------------------------------------------------------------*/
3857 static void genPointerGet (iCode *ic)
3859 operand *left, *result ;
3863 result = IC_RESULT(ic) ;
3865 /* depending on the type of pointer we need to
3866 move it to the correct pointer register */
3867 type = operandType(left);
3868 etype = getSpec(type);
3870 genGenPointerGet (left,result,ic);
3873 bool isRegOrLit(asmop *aop)
3875 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
3880 /*-----------------------------------------------------------------*/
3881 /* genGenPointerSet - stores the value into a pointer location */
3882 /*-----------------------------------------------------------------*/
3883 static void genGenPointerSet (operand *right,
3884 operand *result, iCode *ic)
3887 link *retype = getSpec(operandType(right));
3888 PAIR_ID pairId = PAIR_HL;
3890 aopOp(result,ic,FALSE);
3891 aopOp(right,ic,FALSE);
3896 /* Handle the exceptions first */
3897 if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
3899 char *l = aopGet(AOP(right), 0, FALSE);
3900 const char *pair = getPairName(AOP(result));
3901 if (canAssignToPtr(l) && isPtr(pair)) {
3902 emitcode("ld", "(%s),%s", pair, l);
3906 emitcode("ld", "(%s),a ; 1", pair);
3911 /* if the operand is already in dptr
3912 then we do nothing else we move the value to dptr */
3913 if (AOP_TYPE(result) != AOP_STR) {
3914 fetchPair(pairId, AOP(result));
3916 /* so hl know contains the address */
3917 freeAsmop(result,NULL,ic);
3919 /* if bit then unpack */
3920 if (IS_BITVAR(retype)) {
3924 size = AOP_SIZE(right);
3928 char *l = aopGet(AOP(right),offset,FALSE);
3929 if (isRegOrLit(AOP(right)) && !IS_GB) {
3930 emitcode("ld", "(%s),%s ; 2", _pairs[pairId].name, l);
3934 emitcode("ld", "(%s),a ; 3", _pairs[pairId].name, offset);
3937 emitcode("inc", _pairs[pairId].name);
3943 freeAsmop(right,NULL,ic);
3946 /*-----------------------------------------------------------------*/
3947 /* genPointerSet - stores the value into a pointer location */
3948 /*-----------------------------------------------------------------*/
3949 static void genPointerSet (iCode *ic)
3951 operand *right, *result ;
3954 right = IC_RIGHT(ic);
3955 result = IC_RESULT(ic) ;
3957 /* depending on the type of pointer we need to
3958 move it to the correct pointer register */
3959 type = operandType(result);
3960 etype = getSpec(type);
3962 genGenPointerSet (right,result,ic);
3965 /*-----------------------------------------------------------------*/
3966 /* genIfx - generate code for Ifx statement */
3967 /*-----------------------------------------------------------------*/
3968 static void genIfx (iCode *ic, iCode *popIc)
3970 operand *cond = IC_COND(ic);
3973 aopOp(cond,ic,FALSE);
3975 /* get the value into acc */
3976 if (AOP_TYPE(cond) != AOP_CRY)
3980 /* the result is now in the accumulator */
3981 freeAsmop(cond,NULL,ic);
3983 /* if there was something to be popped then do it */
3987 /* if the condition is a bit variable */
3988 if (isbit && IS_ITEMP(cond) &&
3990 genIfxJump(ic,SPIL_LOC(cond)->rname);
3992 if (isbit && !IS_ITEMP(cond))
3993 genIfxJump(ic,OP_SYMBOL(cond)->rname);
4000 /*-----------------------------------------------------------------*/
4001 /* genAddrOf - generates code for address of */
4002 /*-----------------------------------------------------------------*/
4003 static void genAddrOf (iCode *ic)
4005 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
4007 aopOp(IC_RESULT(ic),ic,FALSE);
4009 /* if the operand is on the stack then we
4010 need to get the stack offset of this
4015 emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
4016 emitcode("ld", "d,h");
4017 emitcode("ld", "e,l");
4020 emitcode("ld", "de,#%s", sym->rname);
4022 aopPut(AOP(IC_RESULT(ic)), "e", 0);
4023 aopPut(AOP(IC_RESULT(ic)), "d", 1);
4028 /* if it has an offset then we need to compute it */
4029 emitcode("ld", "hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
4030 emitcode("add", "hl,sp");
4033 emitcode("ld", "hl,#%s", sym->rname);
4035 aopPut(AOP(IC_RESULT(ic)), "l", 0);
4036 aopPut(AOP(IC_RESULT(ic)), "h", 1);
4038 freeAsmop(IC_RESULT(ic),NULL,ic);
4041 /*-----------------------------------------------------------------*/
4042 /* genAssign - generate code for assignment */
4043 /*-----------------------------------------------------------------*/
4044 static void genAssign (iCode *ic)
4046 operand *result, *right;
4048 unsigned long lit = 0L;
4050 result = IC_RESULT(ic);
4051 right = IC_RIGHT(ic) ;
4054 /* Dont bother assigning if they are the same */
4055 if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) {
4056 emitcode("", "; (operands are equal %u)", operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)));
4061 aopOp(right,ic,FALSE);
4062 aopOp(result,ic,TRUE);
4064 /* if they are the same registers */
4065 if (sameRegs(AOP(right),AOP(result))) {
4066 emitcode("", "; (registers are the same)");
4070 /* if the result is a bit */
4071 if (AOP_TYPE(result) == AOP_CRY) {
4076 size = AOP_SIZE(result);
4079 if(AOP_TYPE(right) == AOP_LIT)
4080 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
4081 if (isPair(AOP(result)) && AOP_TYPE(right) == AOP_LIT) {
4082 emitcode("ld", "%s,%s", getPairName(AOP(result)), aopGetWord(AOP(right), 0));
4084 else if((size > 1) &&
4085 (AOP_TYPE(result) != AOP_REG) &&
4086 (AOP_TYPE(right) == AOP_LIT) &&
4087 !IS_FLOAT(operandType(right)) &&
4089 bool fXored = FALSE;
4091 /* Work from the top down.
4092 Done this way so that we can use the cached copy of 0
4093 in A for a fast clear */
4095 if((unsigned int)((lit >> (offset*8)) & 0x0FFL)== 0) {
4096 if (!fXored && size>1) {
4097 emitcode("xor", "a,a");
4101 aopPut(AOP(result),"a",offset);
4104 aopPut(AOP(result), "#0", offset);
4109 aopGet(AOP(right),offset,FALSE),
4114 else if (size == 2 && requiresHL(AOP(right)) && requiresHL(AOP(result))) {
4115 /* Special case. Load into a and d, then load out. */
4116 MOVA(aopGet(AOP(right), 0, FALSE));
4117 emitcode("ld", "e,%s", aopGet(AOP(right), 1, FALSE));
4118 aopPut(AOP(result), "a", 0);
4119 aopPut(AOP(result), "e", 1);
4123 aopGet(AOP(right),offset,FALSE),
4130 freeAsmop(right,NULL,ic);
4131 freeAsmop(result,NULL,ic);
4134 /*-----------------------------------------------------------------*/
4135 /* genJumpTab - genrates code for jump table */
4136 /*-----------------------------------------------------------------*/
4137 static void genJumpTab (iCode *ic)
4142 aopOp(IC_JTCOND(ic),ic,FALSE);
4143 /* get the condition into accumulator */
4144 l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE);
4147 emitcode("push", "de");
4148 emitcode("ld", "e,%s", l);
4149 emitcode("ld", "d,#0");
4150 jtab = newiTempLabel(NULL);
4152 emitcode("ld", "hl,#" LABEL_STR, jtab->key+100);
4153 emitcode("add", "hl,de");
4154 emitcode("add", "hl,de");
4155 emitcode("add", "hl,de");
4156 freeAsmop(IC_JTCOND(ic),NULL,ic);
4158 emitcode("pop", "de");
4159 emitcode("jp", "(hl)");
4160 emitLabel(jtab->key+100);
4161 /* now generate the jump labels */
4162 for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
4163 jtab = setNextItem(IC_JTLABELS(ic)))
4164 emitcode("jp", LABEL_STR, jtab->key+100);
4167 /*-----------------------------------------------------------------*/
4168 /* genCast - gen code for casting */
4169 /*-----------------------------------------------------------------*/
4170 static void genCast (iCode *ic)
4172 operand *result = IC_RESULT(ic);
4173 link *ctype = operandType(IC_LEFT(ic));
4174 operand *right = IC_RIGHT(ic);
4177 /* if they are equivalent then do nothing */
4178 if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
4181 aopOp(right,ic,FALSE) ;
4182 aopOp(result,ic,FALSE);
4184 /* if the result is a bit */
4185 if (AOP_TYPE(result) == AOP_CRY) {
4189 /* if they are the same size : or less */
4190 if (AOP_SIZE(result) <= AOP_SIZE(right)) {
4192 /* if they are in the same place */
4193 if (sameRegs(AOP(right),AOP(result)))
4196 /* if they in different places then copy */
4197 size = AOP_SIZE(result);
4201 aopGet(AOP(right),offset,FALSE),
4208 /* PENDING: should be OK. */
4210 /* if the result is of type pointer */
4211 if (IS_PTR(ctype)) {
4216 /* so we now know that the size of destination is greater
4217 than the size of the source */
4218 /* we move to result for the size of source */
4219 size = AOP_SIZE(right);
4223 aopGet(AOP(right),offset,FALSE),
4228 /* now depending on the sign of the destination */
4229 size = AOP_SIZE(result) - AOP_SIZE(right);
4230 /* Unsigned or not an integral type - right fill with zeros */
4231 if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) {
4233 aopPut(AOP(result),zero,offset++);
4235 /* we need to extend the sign :{ */
4236 char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
4239 emitcode("", "; genCast: sign extend untested.");
4240 emitcode("rla", "");
4241 emitcode("sbc", "a,a");
4243 aopPut(AOP(result),"a",offset++);
4247 freeAsmop(right, NULL, ic);
4248 freeAsmop(result, NULL, ic);
4251 /*-----------------------------------------------------------------*/
4252 /* genReceive - generate code for a receive iCode */
4253 /*-----------------------------------------------------------------*/
4254 static void genReceive (iCode *ic)
4256 if (isOperandInFarSpace(IC_RESULT(ic)) &&
4257 ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
4258 IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
4262 aopOp(IC_RESULT(ic),ic,FALSE);
4264 assignResultValue(IC_RESULT(ic));
4267 freeAsmop(IC_RESULT(ic),NULL,ic);
4270 /*-----------------------------------------------------------------*/
4271 /* genZ80Code - generate code for Z80 based controllers */
4272 /*-----------------------------------------------------------------*/
4273 void genZ80Code (iCode *lic)
4280 _fReturn = _gbz80_return;
4281 _fTmp = _gbz80_return;
4285 _fReturn = _z80_return;
4286 _fTmp = _z80_return;
4290 lineHead = lineCurr = NULL;
4292 /* if debug information required */
4293 if (options.debug && currFunc) {
4294 cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
4296 if (IS_STATIC(currFunc->etype))
4297 emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name);
4299 emitcode("","G$%s$0$0 ==.",currFunc->name);
4302 /* stack pointer name */
4306 for (ic = lic ; ic ; ic = ic->next ) {
4308 if ( cln != ic->lineno ) {
4309 if ( options.debug ) {
4311 emitcode("","C$%s$%d$%d$%d ==.",
4312 ic->filename,ic->lineno,
4313 ic->level,ic->block);
4316 emitcode(";","%s %d",ic->filename,ic->lineno);
4319 /* if the result is marked as
4320 spilt and rematerializable or code for
4321 this has already been generated then
4323 if (resultRemat(ic) || ic->generated )
4326 /* depending on the operation */
4329 emitcode("", "; genNot");
4334 emitcode("", "; genCpl");
4339 emitcode("", "; genUminus");
4344 emitcode("", "; genIpush");
4349 /* IPOP happens only when trying to restore a
4350 spilt live range, if there is an ifx statement
4351 following this pop then the if statement might
4352 be using some of the registers being popped which
4353 would destory the contents of the register so
4354 we need to check for this condition and handle it */
4356 ic->next->op == IFX &&
4357 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) {
4358 emitcode("", "; genIfx");
4359 genIfx (ic->next,ic);
4362 emitcode("", "; genIpop");
4368 emitcode("", "; genCall");
4373 emitcode("", "; genPcall");
4378 emitcode("", "; genFunction");
4383 emitcode("", "; genEndFunction");
4384 genEndFunction (ic);
4388 emitcode("", "; genRet");
4393 emitcode("", "; genLabel");
4398 emitcode("", "; genGoto");
4403 emitcode("", "; genPlus");
4408 emitcode("", "; genMinus");
4413 emitcode("", "; genMult");
4418 emitcode("", "; genDiv");
4423 emitcode("", "; genMod");
4428 emitcode("", "; genCmpGt");
4429 genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));
4433 emitcode("", "; genCmpLt");
4434 genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
4441 /* note these two are xlated by algebraic equivalence
4442 during parsing SDCC.y */
4443 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
4444 "got '>=' or '<=' shouldn't have come here");
4448 emitcode("", "; genCmpEq");
4449 genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
4453 emitcode("", "; genAndOp");
4458 emitcode("", "; genOrOp");
4463 emitcode("", "; genXor");
4464 genXor (ic,ifxForOp(IC_RESULT(ic),ic));
4468 emitcode("", "; genOr");
4469 genOr (ic,ifxForOp(IC_RESULT(ic),ic));
4473 emitcode("", "; genAnd");
4474 genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
4478 emitcode("", "; genInline");
4483 emitcode("", "; genRRC");
4488 emitcode("", "; genRLC");
4493 emitcode("", "; genHBIT");
4497 emitcode("", "; genLeftShift");
4502 emitcode("", "; genRightShift");
4506 case GET_VALUE_AT_ADDRESS:
4507 emitcode("", "; genPointerGet");
4513 if (POINTER_SET(ic)) {
4514 emitcode("", "; genAssign (pointer)");
4518 emitcode("", "; genAssign");
4524 emitcode("", "; genIfx");
4529 emitcode("", "; genAddrOf");
4534 emitcode("", "; genJumpTab");
4539 emitcode("", "; genCast");
4544 emitcode("", "; genReceive");
4549 emitcode("", "; addSet");
4550 addSet(&sendSet,ic);
4555 /* piCode(ic,stdout); */
4561 /* now we are ready to call the
4562 peep hole optimizer */
4563 if (!options.nopeep)
4564 peepHole (&lineHead);
4566 /* now do the actual printing */
4567 printLine (lineHead,codeOutFile);