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 *_z80_return[] = {"l", "h", "e", "d" };
66 static char *_gbz80_return[] = { "e", "d", "l", "h" };
67 static char **_fReturn;
73 static char *accUse[] = {"a" };
79 extern int ptrRegReq ;
81 extern FILE *codeOutFile;
98 } _pairs[NUM_PAIRS] = {
103 { "iy", "iy.l?", "iy.h?" },
104 { "ix", "ix.l?", "ix.h?" }
107 #define RESULTONSTACK(x) \
108 (IC_RESULT(x) && IC_RESULT(x)->aop && \
109 IC_RESULT(x)->aop->type == AOP_STK )
111 #define MOVA(x) if (strcmp(x,"a")) emitcode("ld","a,%s",x);
112 #define CLRC emitcode("xor","a,a");
114 lineNode *lineHead = NULL;
115 lineNode *lineCurr = NULL;
117 static const unsigned char SLMask[] =
118 {0xFF ,0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00};
119 static const unsigned char SRMask[] =
120 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00};
148 static char *aopGet(asmop *aop, int offset, bool bit16);
150 static void _tidyUp(char *buf)
152 /* Clean up the line so that it is 'prettier' */
153 if (strchr(buf, ':')) {
154 /* Is a label - cant do anything */
157 /* Change the first (and probably only) ' ' to a tab so
169 static void emit2(const char *szFormat, ...)
174 va_start(ap, szFormat);
176 tvsprintf(buffer, szFormat, ap);
179 lineCurr = (lineCurr ?
180 connectLine(lineCurr,newLineNode(buffer)) :
181 (lineHead = newLineNode(buffer)));
183 lineCurr->isInline = inLine;
184 lineCurr->isDebug = debugLine;
187 /*-----------------------------------------------------------------*/
188 /* emitcode - writes the code into a file : for now it is simple */
189 /*-----------------------------------------------------------------*/
190 void emitcode (const char *inst, const char *fmt, ...)
193 char lb[MAX_INLINEASM];
199 sprintf(lb,"%s\t",inst);
200 vsprintf(lb+(strlen(lb)),fmt,ap);
204 while (isspace(*lbp)) lbp++;
207 lineCurr = (lineCurr ?
208 connectLine(lineCurr,newLineNode(lb)) :
209 (lineHead = newLineNode(lb)));
210 lineCurr->isInline = inLine;
211 lineCurr->isDebug = debugLine;
228 emitcode("ld", "sp,ix");
229 emitcode("pop", "ix");
230 emitcode("pop", "de");
235 const char *getPairName(asmop *aop)
237 if (aop->type == AOP_REG) {
238 switch (aop->aopu.aop_reg[0]->rIdx) {
250 else if (aop->type == AOP_STR) {
251 switch (*aop->aopu.aop_str[0]) {
267 static PAIR_ID getPairId(asmop *aop)
269 if (aop->size == 2) {
270 if (aop->type == AOP_REG) {
271 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX)&&(aop->aopu.aop_reg[1]->rIdx == B_IDX)) {
274 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX)&&(aop->aopu.aop_reg[1]->rIdx == D_IDX)) {
277 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX)&&(aop->aopu.aop_reg[1]->rIdx == H_IDX)) {
281 if (aop->type == AOP_STR) {
282 if (!strcmp(aop->aopu.aop_str[0], "c")&&!strcmp(aop->aopu.aop_str[1], "b")) {
285 if (!strcmp(aop->aopu.aop_str[0], "e")&&!strcmp(aop->aopu.aop_str[1], "d")) {
288 if (!strcmp(aop->aopu.aop_str[0], "l")&&!strcmp(aop->aopu.aop_str[1], "h")) {
296 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
297 bool isPair(asmop *aop)
299 return (getPairId(aop) != PAIR_INVALID);
302 bool isPtrPair(asmop *aop)
304 PAIR_ID pairId = getPairId(aop);
314 /** Push a register pair onto the stack */
315 void genPairPush(asmop *aop)
317 emitcode("push", "%s", getPairName(aop));
321 /*-----------------------------------------------------------------*/
322 /* newAsmop - creates a new asmOp */
323 /*-----------------------------------------------------------------*/
324 static asmop *newAsmop (short type)
328 ALLOC(aop,sizeof(asmop));
333 /*-----------------------------------------------------------------*/
334 /* aopForSym - for a true symbol */
335 /*-----------------------------------------------------------------*/
336 static asmop *aopForSym (iCode *ic,symbol *sym,bool result)
339 memmap *space= SPEC_OCLS(sym->etype);
341 /* if already has one */
345 /* Assign depending on the storage class */
346 if (sym->onStack || sym->iaccess) {
347 sym->aop = aop = newAsmop(AOP_STK);
348 aop->size = getSize(sym->type);
349 aop->aopu.aop_stk = sym->stack;
353 /* special case for a function */
354 if (IS_FUNC(sym->type)) {
355 sym->aop = aop = newAsmop(AOP_IMMD);
356 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(sym->rname)+1);
357 strcpy(aop->aopu.aop_immd,sym->rname);
364 /* if it is in direct space */
365 if (IN_DIRSPACE(space)) {
366 sym->aop = aop = newAsmop (AOP_DIR);
367 aop->aopu.aop_dir = sym->rname ;
368 aop->size = getSize(sym->type);
369 emitcode("", "; AOP_DIR for %s", sym->rname);
375 /* only remaining is far space */
376 /* in which case DPTR gets the address */
378 sym->aop = aop = newAsmop(AOP_HL);
381 sym->aop = aop = newAsmop(AOP_IY);
383 aop->size = getSize(sym->type);
384 aop->aopu.aop_dir = sym->rname;
386 /* if it is in code space */
387 if (IN_CODESPACE(space))
393 /*-----------------------------------------------------------------*/
394 /* aopForRemat - rematerialzes an object */
395 /*-----------------------------------------------------------------*/
396 static asmop *aopForRemat (symbol *sym)
399 iCode *ic = sym->rematiCode;
400 asmop *aop = newAsmop(AOP_IMMD);
403 /* if plus or minus print the right hand side */
404 if (ic->op == '+' || ic->op == '-') {
405 /* PENDING: for re-target */
406 sprintf(s,"0x%04x %c ",(int) operandLitValue(IC_RIGHT(ic)),
409 ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode;
412 /* we reached the end */
413 sprintf(s,"%s",OP_SYMBOL(IC_LEFT(ic))->rname);
417 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(buffer)+1);
418 strcpy(aop->aopu.aop_immd,buffer);
422 /*-----------------------------------------------------------------*/
423 /* regsInCommon - two operands have some registers in common */
424 /*-----------------------------------------------------------------*/
425 bool regsInCommon (operand *op1, operand *op2)
430 /* if they have registers in common */
431 if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
434 sym1 = OP_SYMBOL(op1);
435 sym2 = OP_SYMBOL(op2);
437 if (sym1->nRegs == 0 || sym2->nRegs == 0)
440 for (i = 0 ; i < sym1->nRegs ; i++) {
445 for (j = 0 ; j < sym2->nRegs ;j++ ) {
449 if (sym2->regs[j] == sym1->regs[i])
457 /*-----------------------------------------------------------------*/
458 /* operandsEqu - equivalent */
459 /*-----------------------------------------------------------------*/
460 bool operandsEqu ( operand *op1, operand *op2)
464 /* if they not symbols */
465 if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
468 sym1 = OP_SYMBOL(op1);
469 sym2 = OP_SYMBOL(op2);
471 /* if both are itemps & one is spilt
472 and the other is not then false */
473 if (IS_ITEMP(op1) && IS_ITEMP(op2) &&
474 sym1->isspilt != sym2->isspilt )
477 /* if they are the same */
481 if (strcmp(sym1->rname,sym2->rname) == 0)
485 /* if left is a tmp & right is not */
489 (sym1->usl.spillLoc == sym2))
496 (sym2->usl.spillLoc == sym1))
502 /*-----------------------------------------------------------------*/
503 /* sameRegs - two asmops have the same registers */
504 /*-----------------------------------------------------------------*/
505 bool sameRegs (asmop *aop1, asmop *aop2 )
512 if (aop1->type != AOP_REG ||
513 aop2->type != AOP_REG )
516 if (aop1->size != aop2->size)
519 for (i = 0 ; i < aop1->size ; i++ )
520 if (aop1->aopu.aop_reg[i] !=
521 aop2->aopu.aop_reg[i] )
527 /*-----------------------------------------------------------------*/
528 /* aopOp - allocates an asmop for an operand : */
529 /*-----------------------------------------------------------------*/
530 static void aopOp (operand *op, iCode *ic, bool result)
539 /* if this a literal */
540 if (IS_OP_LITERAL(op)) {
541 op->aop = aop = newAsmop(AOP_LIT);
542 aop->aopu.aop_lit = op->operand.valOperand;
543 aop->size = getSize(operandType(op));
547 /* if already has a asmop then continue */
551 /* if the underlying symbol has a aop */
552 if (IS_SYMOP(op) && OP_SYMBOL(op)->aop) {
553 op->aop = OP_SYMBOL(op)->aop;
557 /* if this is a true symbol */
558 if (IS_TRUE_SYMOP(op)) {
559 op->aop = aopForSym(ic,OP_SYMBOL(op),result);
563 /* this is a temporary : this has
569 e) can be a return use only */
573 /* if the type is a conditional */
574 if (sym->regType == REG_CND) {
575 aop = op->aop = sym->aop = newAsmop(AOP_CRY);
580 /* if it is spilt then two situations
582 b) has a spill location */
583 if (sym->isspilt || sym->nRegs == 0) {
584 /* rematerialize it NOW */
586 sym->aop = op->aop = aop =
588 aop->size = getSize(sym->type);
594 aop = op->aop = sym->aop = newAsmop(AOP_ACC);
595 aop->size = getSize(sym->type);
596 for ( i = 0 ; i < 2 ; i++ )
597 aop->aopu.aop_str[i] = accUse[i];
603 aop = op->aop = sym->aop = newAsmop(AOP_STR);
604 aop->size = getSize(sym->type);
605 for ( i = 0 ; i < 4 ; i++ )
606 aop->aopu.aop_str[i] = _fReturn[i];
610 /* else spill location */
611 sym->aop = op->aop = aop =
612 aopForSym(ic,sym->usl.spillLoc,result);
613 aop->size = getSize(sym->type);
617 /* must be in a register */
618 sym->aop = op->aop = aop = newAsmop(AOP_REG);
619 aop->size = sym->nRegs;
620 for ( i = 0 ; i < sym->nRegs ;i++)
621 aop->aopu.aop_reg[i] = sym->regs[i];
624 /*-----------------------------------------------------------------*/
625 /* freeAsmop - free up the asmop given to an operand */
626 /*----------------------------------------------------------------*/
627 static void freeAsmop (operand *op, asmop *aaop, iCode *ic)
645 /* all other cases just dealloc */
649 OP_SYMBOL(op)->aop = NULL;
650 /* if the symbol has a spill */
652 SPIL_LOC(op)->aop = NULL;
657 bool isLitWord(asmop *aop)
659 /* if (aop->size != 2)
670 char *aopGetLitWordLong(asmop *aop, int offset, bool with_hash)
676 if (aop->size != 2 && aop->type != AOP_HL)
679 wassert(offset == 0);
681 /* depending on type */
686 /* PENDING: for re-target */
688 tsprintf(s, "!hashedstr", aop->aopu.aop_immd);
690 strcpy(s, aop->aopu.aop_immd);
691 ALLOC_ATOMIC(rs,strlen(s)+1);
695 value * val = aop->aopu.aop_lit;
696 /* if it is a float then it gets tricky */
697 /* otherwise it is fairly simple */
698 if (!IS_FLOAT(val->type)) {
699 unsigned long v = floatFromVal(val);
701 tsprintf(buffer, "!immedword", v);
703 tsprintf(buffer, "!constword", v);
704 ALLOC_ATOMIC(rs,strlen(buffer)+1);
705 return strcpy (rs,buffer);
715 char *aopGetWord(asmop *aop, int offset)
717 return aopGetLitWordLong(aop, offset, TRUE);
720 bool isPtr(const char *s)
722 if (!strcmp(s, "hl"))
724 if (!strcmp(s, "ix"))
726 if (!strcmp(s, "iy"))
731 static void adjustPair(const char *pair, int *pold, int new)
735 while (*pold < new) {
736 emitcode("inc", "%s", pair);
739 while (*pold > new) {
740 emitcode("dec", "%s", pair);
745 static void spillPair(PAIR_ID pairId)
747 _G.pairs[pairId].last_type = AOP_INVALID;
748 _G.pairs[pairId].lit = NULL;
751 static void spillCached(void)
757 static bool requiresHL(asmop *aop)
768 static void fetchLitPair(PAIR_ID pairId, asmop *left, int offset)
771 const char *pair = _pairs[pairId].name;
772 l = aopGetLitWordLong(left, 0, FALSE);
776 if (pairId == PAIR_HL || pairId == PAIR_IY) {
777 if (_G.pairs[pairId].lit && !strcmp(_G.pairs[pairId].lit, l)) {
778 if (pairId == PAIR_HL && abs(_G.pairs[pairId].offset - offset) < 3) {
779 adjustPair(pair, &_G.pairs[pairId].offset, offset);
782 if (pairId == PAIR_IY && abs(offset)<127) {
787 _G.pairs[pairId].last_type = left->type;
788 _G.pairs[pairId].lit = gc_strdup(l);
789 _G.pairs[pairId].offset = offset;
791 /* Both a lit on the right and a true symbol on the left */
792 /* PENDING: for re-target */
794 emit2("ld %s,!hashedstr + %d", pair, l, offset);
796 emit2("ld %s,!hashedstr", pair, l);
799 static void fetchPairLong(PAIR_ID pairId, asmop *aop, int offset)
801 /* if this is remateriazable */
802 if (isLitWord(aop)) {
803 fetchLitPair(pairId, aop, offset);
805 else { /* we need to get it byte by byte */
806 if (pairId == PAIR_HL && IS_GB && requiresHL(aop)) {
807 aopGet(aop, offset, FALSE);
813 emitcode("ld", "%s,%s", _pairs[pairId].l, aopGet(aop, offset, FALSE));
814 emitcode("ld", "%s,%s", _pairs[pairId].h, aopGet(aop, offset+1, FALSE));
816 /* PENDING: check? */
817 if (pairId == PAIR_HL)
822 static void fetchPair(PAIR_ID pairId, asmop *aop)
824 fetchPairLong(pairId, aop, 0);
827 static void fetchHL(asmop *aop)
829 fetchPair(PAIR_HL, aop);
832 static void setupPair(PAIR_ID pairId, asmop *aop, int offset)
834 assert(pairId == PAIR_HL || pairId == PAIR_IY);
839 fetchLitPair(pairId, aop, offset);
840 _G.pairs[pairId].offset = offset;
843 /* Doesnt include _G.stack.pushed */
844 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
845 assert(pairId == PAIR_HL);
846 /* In some cases we can still inc or dec hl */
847 if (_G.pairs[pairId].last_type == AOP_STK && abs(_G.pairs[pairId].offset - abso) < 3) {
848 adjustPair(_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
851 emit2("!ldahlsp", aop->aopu.aop_stk+offset + _G.stack.pushed + _G.stack.offset);
853 _G.pairs[pairId].offset = abso;
859 _G.pairs[pairId].last_type = aop->type;
862 static void emitLabel(int key)
864 emit2("!tlabeldef", key);
868 /*-----------------------------------------------------------------*/
869 /* aopGet - for fetching value of the aop */
870 /*-----------------------------------------------------------------*/
871 static char *aopGet(asmop *aop, int offset, bool bit16)
876 /* offset is greater than size then zero */
877 /* PENDING: this seems a bit screwed in some pointer cases. */
878 if (offset > (aop->size - 1) &&
879 aop->type != AOP_LIT)
882 /* depending on type */
885 /* PENDING: re-target */
887 tsprintf (s,"!immedwords", aop->aopu.aop_immd);
890 wassert(offset == 1);
891 tsprintf(s, "!lsbimmeds", aop->aopu.aop_immd);
894 tsprintf(s, "!msbimmeds", aop->aopu.aop_immd);
895 ALLOC_ATOMIC(rs,strlen(s)+1);
901 /* PENDING: for re-target: currently unsupported. */
903 emitcode("ld", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
905 ALLOC_ATOMIC(rs,strlen(s)+1);
910 return aop->aopu.aop_reg[offset]->name;
914 setupPair(PAIR_HL, aop, offset);
920 setupPair(PAIR_IY, aop, offset);
921 tsprintf(s,"!*iyx", offset);
922 ALLOC_ATOMIC(rs,strlen(s)+1);
928 setupPair(PAIR_HL, aop, offset);
932 tsprintf(s,"!*ixx", aop->aopu.aop_stk+offset);
934 ALLOC_ATOMIC(rs,strlen(s)+1);
948 return aopLiteral (aop->aopu.aop_lit,offset);
952 return aop->aopu.aop_str[offset];
956 wassertl(0, "aopget got unsupported aop->type");
960 bool isRegString(char *s)
962 if (!strcmp(s, "b") ||
973 bool isConstant(const char *s)
975 /* This is a bit of a hack... */
976 return (*s == '#' || *s == '$');
979 bool canAssignToPtr(char *s)
988 /*-----------------------------------------------------------------*/
989 /* aopPut - puts a string for a aop */
990 /*-----------------------------------------------------------------*/
991 static void aopPut (asmop *aop, char *s, int offset)
993 if (aop->size && offset > ( aop->size - 1)) {
994 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
995 "aopPut got offset > aop->size");
999 /* will assign value to value */
1000 /* depending on where it is ofcourse */
1001 switch (aop->type) {
1005 /* Currently unsupported */
1007 emitcode("ld", "a,%s", s);
1008 emitcode("ld", "(%s+%d),a", aop->aopu.aop_dir, offset);
1012 emitcode("ld","%s,%s",
1013 aop->aopu.aop_reg[offset]->name,s);
1018 setupPair(PAIR_IY, aop, offset);
1019 if (!canAssignToPtr(s)) {
1020 emit2("ld a,%s", s);
1021 emit2("ld !*iyx,a", offset);
1024 emit2("ld !*iyx,%s", offset, s);
1029 /* PENDING: for re-target */
1030 if (!strcmp(s, "!*hl") || !strcmp(s, "(hl)") || !strcmp(s, "[hl]")) {
1034 setupPair(PAIR_HL, aop, offset);
1036 emit2("ld !*hl,%s", s);
1041 /* PENDING: re-target */
1042 if (!strcmp(s, "!*hl") || !strcmp(s, "(hl)") || !strcmp(s, "[hl]")) {
1046 setupPair(PAIR_HL, aop, offset);
1047 if (!canAssignToPtr(s)) {
1048 emit2("ld a,%s", s);
1052 emit2("ld !*hl,%s ; 3", s);
1055 if (!canAssignToPtr(s)) {
1056 emit2("ld a,%s", s);
1057 emit2("ld !*ixx,a", aop->aopu.aop_stk+offset);
1060 emit2("ld !*ixx,%s", aop->aopu.aop_stk+offset, s);
1065 /* if bit variable */
1066 if (!aop->aopu.aop_dir) {
1070 /* In bit space but not in C - cant happen */
1077 if (strcmp(aop->aopu.aop_str[offset],s)) {
1078 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1084 if (!offset && (strcmp(s,"acc") == 0))
1088 emitcode("", "; Error aopPut AOP_ACC");
1091 if (strcmp(aop->aopu.aop_str[offset],s))
1092 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1097 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1098 "aopPut got unsupported aop->type");
1103 #define AOP(op) op->aop
1104 #define AOP_TYPE(op) AOP(op)->type
1105 #define AOP_SIZE(op) AOP(op)->size
1106 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1108 /*-----------------------------------------------------------------*/
1109 /* getDataSize - get the operand data size */
1110 /*-----------------------------------------------------------------*/
1111 int getDataSize(operand *op)
1114 size = AOP_SIZE(op);
1122 /*-----------------------------------------------------------------*/
1123 /* movLeft2Result - move byte from left to result */
1124 /*-----------------------------------------------------------------*/
1125 static void movLeft2Result (operand *left, int offl,
1126 operand *result, int offr, int sign)
1129 if(!sameRegs(AOP(left),AOP(result)) || (offl != offr)){
1130 l = aopGet(AOP(left),offl,FALSE);
1133 aopPut(AOP(result),l,offr);
1142 /** Put Acc into a register set
1144 void outAcc(operand *result)
1147 size = getDataSize(result);
1149 aopPut(AOP(result),"a",0);
1152 /* unsigned or positive */
1154 aopPut(AOP(result), zero, offset++);
1159 /** Take the value in carry and put it into a register
1161 void outBitC(operand *result)
1163 /* if the result is bit */
1164 if (AOP_TYPE(result) == AOP_CRY) {
1165 emitcode("", "; Note: outBitC form 1");
1166 aopPut(AOP(result),"blah",0);
1169 emit2("ld a,!zero");
1175 /*-----------------------------------------------------------------*/
1176 /* toBoolean - emit code for orl a,operator(sizeop) */
1177 /*-----------------------------------------------------------------*/
1178 void toBoolean(operand *oper)
1180 int size = AOP_SIZE(oper);
1183 emitcode("ld", "a,%s", aopGet(AOP(oper), offset++, FALSE));
1186 emitcode("or","a,%s",aopGet(AOP(oper),offset++,FALSE));
1189 if (AOP(oper)->type != AOP_ACC) {
1191 emitcode("or","a,%s",aopGet(AOP(oper),0,FALSE));
1196 /*-----------------------------------------------------------------*/
1197 /* genNot - generate code for ! operation */
1198 /*-----------------------------------------------------------------*/
1199 static void genNot (iCode *ic)
1201 link *optype = operandType(IC_LEFT(ic));
1203 /* assign asmOps to operand & result */
1204 aopOp (IC_LEFT(ic),ic,FALSE);
1205 aopOp (IC_RESULT(ic),ic,TRUE);
1207 /* if in bit space then a special case */
1208 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) {
1212 /* if type float then do float */
1213 if (IS_FLOAT(optype)) {
1217 toBoolean(IC_LEFT(ic));
1222 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1223 emit2("sub a,!one");
1224 outBitC(IC_RESULT(ic));
1226 /* release the aops */
1227 freeAsmop(IC_LEFT(ic),NULL,ic);
1228 freeAsmop(IC_RESULT(ic),NULL,ic);
1231 /*-----------------------------------------------------------------*/
1232 /* genCpl - generate code for complement */
1233 /*-----------------------------------------------------------------*/
1234 static void genCpl (iCode *ic)
1240 /* assign asmOps to operand & result */
1241 aopOp (IC_LEFT(ic),ic,FALSE);
1242 aopOp (IC_RESULT(ic),ic,TRUE);
1244 /* if both are in bit space then
1246 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1247 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1251 size = AOP_SIZE(IC_RESULT(ic));
1253 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1256 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1259 /* release the aops */
1260 freeAsmop(IC_LEFT(ic),NULL,ic);
1261 freeAsmop(IC_RESULT(ic),NULL,ic);
1264 /*-----------------------------------------------------------------*/
1265 /* genUminus - unary minus code generation */
1266 /*-----------------------------------------------------------------*/
1267 static void genUminus (iCode *ic)
1270 link *optype, *rtype;
1273 aopOp(IC_LEFT(ic),ic,FALSE);
1274 aopOp(IC_RESULT(ic),ic,TRUE);
1276 /* if both in bit space then special
1278 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1279 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1284 optype = operandType(IC_LEFT(ic));
1285 rtype = operandType(IC_RESULT(ic));
1287 /* if float then do float stuff */
1288 if (IS_FLOAT(optype)) {
1293 /* otherwise subtract from zero */
1294 size = AOP_SIZE(IC_LEFT(ic));
1298 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1299 emit2("ld a,!zero");
1300 emit2("sbc a,%s",l);
1301 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1304 /* if any remaining bytes in the result */
1305 /* we just need to propagate the sign */
1306 if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic))))) {
1310 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1314 /* release the aops */
1315 freeAsmop(IC_LEFT(ic),NULL,ic);
1316 freeAsmop(IC_RESULT(ic),NULL,ic);
1319 /*-----------------------------------------------------------------*/
1320 /* assignResultValue - */
1321 /*-----------------------------------------------------------------*/
1322 void assignResultValue(operand * oper)
1324 int size = AOP_SIZE(oper);
1328 topInA = requiresHL(AOP(oper));
1332 if (IS_GB && size == 4 && requiresHL(AOP(oper))) {
1333 /* We do it the hard way here. */
1334 emitcode("push", "hl");
1335 _G.stack.pushed += 2;
1336 aopPut(AOP(oper), _fReturn[0], 0);
1337 aopPut(AOP(oper), _fReturn[1], 1);
1338 emitcode("pop", "de");
1339 _G.stack.pushed -= 2;
1340 aopPut(AOP(oper), _fReturn[0], 2);
1341 aopPut(AOP(oper), _fReturn[1], 3);
1345 aopPut(AOP(oper), _fReturn[size], size);
1350 /*-----------------------------------------------------------------*/
1351 /* genIpush - genrate code for pushing this gets a little complex */
1352 /*-----------------------------------------------------------------*/
1353 static void genIpush (iCode *ic)
1355 int size, offset = 0 ;
1359 /* if this is not a parm push : ie. it is spill push
1360 and spill push is always done on the local stack */
1361 if (!ic->parmPush) {
1362 /* and the item is spilt then do nothing */
1363 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1366 aopOp(IC_LEFT(ic),ic,FALSE);
1367 size = AOP_SIZE(IC_LEFT(ic));
1368 /* push it on the stack */
1369 if (isPair(AOP(IC_LEFT(ic)))) {
1370 emitcode("push", getPairName(AOP(IC_LEFT(ic))));
1371 _G.stack.pushed += 2;
1376 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1377 /* Simple for now - load into A and PUSH AF */
1378 emitcode("ld", "a,%s", l);
1379 emitcode("push", "af");
1380 emitcode("inc", "sp");
1387 /* Hmmm... what about saving the currently used registers
1390 /* then do the push */
1391 aopOp(IC_LEFT(ic),ic,FALSE);
1393 size = AOP_SIZE(IC_LEFT(ic));
1395 if (isPair(AOP(IC_LEFT(ic)))) {
1397 emitcode("push", "%s", getPairName(AOP(IC_LEFT(ic))));
1401 fetchHL(AOP(IC_LEFT(ic)));
1402 emitcode("push", "hl");
1404 _G.stack.pushed += 2;
1409 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1410 emitcode("ld", "a,%s", l);
1411 emitcode("push", "af");
1412 emitcode("inc", "sp");
1417 freeAsmop(IC_LEFT(ic),NULL,ic);
1420 /*-----------------------------------------------------------------*/
1421 /* genIpop - recover the registers: can happen only for spilling */
1422 /*-----------------------------------------------------------------*/
1423 static void genIpop (iCode *ic)
1428 /* if the temp was not pushed then */
1429 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1432 aopOp(IC_LEFT(ic),ic,FALSE);
1433 size = AOP_SIZE(IC_LEFT(ic));
1435 if (isPair(AOP(IC_LEFT(ic)))) {
1436 emitcode("pop", getPairName(AOP(IC_LEFT(ic))));
1440 emitcode("dec", "sp");
1441 emitcode("pop", "hl");
1443 aopPut(AOP(IC_LEFT(ic)), "l", offset--);
1447 freeAsmop(IC_LEFT(ic),NULL,ic);
1450 /** Emit the code for a call statement
1452 static void emitCall (iCode *ic, bool ispcall)
1454 /* if caller saves & we have not saved then */
1455 if (!ic->regsSaved) {
1459 /* if send set is not empty then assign */
1462 for (sic = setFirstItem(sendSet) ; sic ;
1463 sic = setNextItem(sendSet)) {
1464 int size, offset = 0;
1465 aopOp(IC_LEFT(sic),sic,FALSE);
1466 size = AOP_SIZE(IC_LEFT(sic));
1468 char *l = aopGet(AOP(IC_LEFT(sic)),offset,
1470 if (strcmp(l, _fReturn[offset]))
1471 emitcode("ld","%s,%s",
1476 freeAsmop (IC_LEFT(sic),NULL,sic);
1482 aopOp(IC_LEFT(ic),ic,FALSE);
1484 if (isLitWord(AOP(IC_LEFT(ic)))) {
1485 emitcode("", "; Special case where the pCall is to a constant");
1486 emitcode("call", aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE));
1489 symbol *rlbl = newiTempLabel(NULL);
1491 emit2("ld hl,#!tlabel", (rlbl->key+100));
1492 emitcode("push", "hl");
1493 _G.stack.pushed += 2;
1495 fetchHL(AOP(IC_LEFT(ic)));
1497 emit2("!tlabeldef", (rlbl->key+100));
1498 _G.stack.pushed -= 2;
1500 freeAsmop(IC_LEFT(ic),NULL,ic);
1504 char *name = OP_SYMBOL(IC_LEFT(ic))->rname[0] ?
1505 OP_SYMBOL(IC_LEFT(ic))->rname :
1506 OP_SYMBOL(IC_LEFT(ic))->name;
1507 emitcode("call", "%s", name);
1511 /* if we need assign a result value */
1512 if ((IS_ITEMP(IC_RESULT(ic)) &&
1513 (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
1514 OP_SYMBOL(IC_RESULT(ic))->spildir )) ||
1515 IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
1518 aopOp(IC_RESULT(ic),ic,FALSE);
1521 assignResultValue(IC_RESULT(ic));
1523 freeAsmop(IC_RESULT(ic),NULL, ic);
1526 /* adjust the stack for parameters if required */
1527 if (IC_LEFT(ic)->parmBytes) {
1528 int i = IC_LEFT(ic)->parmBytes;
1529 _G.stack.pushed -= i;
1531 emit2("!ldaspsp", i);
1536 emitcode("ld", "hl,#%d", i);
1537 emitcode("add", "hl,sp");
1538 emitcode("ld", "sp,hl");
1542 emitcode("pop", "hl");
1546 emitcode("inc", "sp");
1554 /*-----------------------------------------------------------------*/
1555 /* genCall - generates a call statement */
1556 /*-----------------------------------------------------------------*/
1557 static void genCall (iCode *ic)
1559 emitCall(ic, FALSE);
1562 /*-----------------------------------------------------------------*/
1563 /* genPcall - generates a call by pointer statement */
1564 /*-----------------------------------------------------------------*/
1565 static void genPcall (iCode *ic)
1570 /*-----------------------------------------------------------------*/
1571 /* resultRemat - result is rematerializable */
1572 /*-----------------------------------------------------------------*/
1573 static int resultRemat (iCode *ic)
1575 if (SKIP_IC(ic) || ic->op == IFX)
1578 if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
1579 symbol *sym = OP_SYMBOL(IC_RESULT(ic));
1580 if (sym->remat && !POINTER_SET(ic))
1587 /*-----------------------------------------------------------------*/
1588 /* genFunction - generated code for function entry */
1589 /*-----------------------------------------------------------------*/
1590 static void genFunction (iCode *ic)
1592 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1596 /* create the function header */
1597 emit2("!functionheader", sym->name);
1598 /* PENDING: portability. */
1599 emit2("__%s_start:", sym->rname);
1600 emit2("!functionlabeldef", sym->rname);
1602 fetype = getSpec(operandType(IC_LEFT(ic)));
1604 /* if critical function then turn interrupts off */
1605 if (SPEC_CRTCL(fetype))
1608 /* if this is an interrupt service routine then
1609 save acc, b, dpl, dph */
1610 if (IS_ISR(sym->etype)) {
1613 /* PENDING: callee-save etc */
1615 /* adjust the stack for the function */
1616 _G.stack.last = sym->stack;
1619 emit2("!enterx", sym->stack);
1622 _G.stack.offset = sym->stack;
1625 /*-----------------------------------------------------------------*/
1626 /* genEndFunction - generates epilogue for functions */
1627 /*-----------------------------------------------------------------*/
1628 static void genEndFunction (iCode *ic)
1630 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1632 if (IS_ISR(sym->etype)) {
1636 if (SPEC_CRTCL(sym->etype))
1639 /* PENDING: calleeSave */
1641 /* if debug then send end of function */
1642 if (options.debug && currFunc) {
1644 emitcode("","C$%s$%d$%d$%d ==.",
1645 ic->filename,currFunc->lastLine,
1646 ic->level,ic->block);
1647 if (IS_STATIC(currFunc->etype))
1648 emitcode("","XF%s$%s$0$0 ==.",moduleName,currFunc->name);
1650 emitcode("","XG$%s$0$0 ==.",currFunc->name);
1653 if (_G.stack.offset)
1654 emit2("!leavex", _G.stack.offset);
1657 /* PENDING: portability. */
1658 emit2("__%s_end:", sym->rname);
1660 _G.stack.pushed = 0;
1661 _G.stack.offset = 0;
1664 /*-----------------------------------------------------------------*/
1665 /* genRet - generate code for return statement */
1666 /*-----------------------------------------------------------------*/
1667 static void genRet (iCode *ic)
1670 /* Errk. This is a hack until I can figure out how
1671 to cause dehl to spill on a call */
1672 int size,offset = 0;
1674 /* if we have no return value then
1675 just generate the "ret" */
1679 /* we have something to return then
1680 move the return value into place */
1681 aopOp(IC_LEFT(ic),ic,FALSE);
1682 size = AOP_SIZE(IC_LEFT(ic));
1684 if ((size == 2) && ((l = aopGetWord(AOP(IC_LEFT(ic)), 0)))) {
1686 emitcode("ld", "de,%s", l);
1689 emitcode("ld", "hl,%s", l);
1693 if (IS_GB && size == 4 && requiresHL(AOP(IC_LEFT(ic)))) {
1694 fetchPair(PAIR_DE, AOP(IC_LEFT(ic)));
1695 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
1699 l = aopGet(AOP(IC_LEFT(ic)),offset,
1701 if (strcmp(_fReturn[offset],l))
1702 emitcode("ld","%s,%s", _fReturn[offset++],l);
1706 freeAsmop (IC_LEFT(ic),NULL,ic);
1709 /* generate a jump to the return label
1710 if the next is not the return statement */
1711 if (!(ic->next && ic->next->op == LABEL &&
1712 IC_LABEL(ic->next) == returnLabel))
1714 emit2("jp !tlabel", returnLabel->key+100);
1717 /*-----------------------------------------------------------------*/
1718 /* genLabel - generates a label */
1719 /*-----------------------------------------------------------------*/
1720 static void genLabel (iCode *ic)
1722 /* special case never generate */
1723 if (IC_LABEL(ic) == entryLabel)
1726 emitLabel(IC_LABEL(ic)->key+100);
1729 /*-----------------------------------------------------------------*/
1730 /* genGoto - generates a ljmp */
1731 /*-----------------------------------------------------------------*/
1732 static void genGoto (iCode *ic)
1734 emit2("jp !tlabel", IC_LABEL(ic)->key+100);
1737 /*-----------------------------------------------------------------*/
1738 /* genPlusIncr :- does addition with increment if possible */
1739 /*-----------------------------------------------------------------*/
1740 static bool genPlusIncr (iCode *ic)
1742 unsigned int icount ;
1743 unsigned int size = getDataSize(IC_RESULT(ic));
1744 PAIR_ID resultId = getPairId(AOP(IC_RESULT(ic)));
1746 /* will try to generate an increment */
1747 /* if the right side is not a literal
1749 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1752 emitcode("", "; genPlusIncr");
1754 icount = floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
1756 /* If result is a pair */
1757 if (resultId != PAIR_INVALID) {
1758 if (isLitWord(AOP(IC_LEFT(ic)))) {
1759 fetchLitPair(getPairId(AOP(IC_RESULT(ic))), AOP(IC_LEFT(ic)), icount);
1762 if (isPair(AOP(IC_LEFT(ic))) && resultId == PAIR_HL && icount > 2) {
1763 fetchPair(resultId, AOP(IC_RIGHT(ic)));
1764 emitcode("add", "hl,%s", getPairName(AOP(IC_LEFT(ic))));
1770 if (!sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
1773 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
1774 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
1777 emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
1782 /* if the literal value of the right hand side
1783 is greater than 4 then it is not worth it */
1787 /* if increment 16 bits in register */
1788 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1793 symbol *tlbl = NULL;
1796 emitLabel(tlbl->key+100);
1798 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)), offset++, FALSE));
1800 tlbl = newiTempLabel(NULL);
1801 emit2("!shortjp nz,!tlabel", tlbl->key+100);
1807 /* if the sizes are greater than 1 then we cannot */
1808 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
1809 AOP_SIZE(IC_LEFT(ic)) > 1 )
1812 /* we can if the aops of the left & result match or
1813 if they are in registers and the registers are the
1815 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
1817 emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0, FALSE));
1825 /*-----------------------------------------------------------------*/
1826 /* outBitAcc - output a bit in acc */
1827 /*-----------------------------------------------------------------*/
1828 void outBitAcc(operand *result)
1830 symbol *tlbl = newiTempLabel(NULL);
1831 /* if the result is a bit */
1832 if (AOP_TYPE(result) == AOP_CRY){
1836 emit2("!shortjp z,!tlabel", tlbl->key+100);
1838 emitLabel(tlbl->key+100);
1843 /*-----------------------------------------------------------------*/
1844 /* genPlus - generates code for addition */
1845 /*-----------------------------------------------------------------*/
1846 static void genPlus (iCode *ic)
1848 int size, offset = 0;
1850 /* special cases :- */
1852 aopOp (IC_LEFT(ic),ic,FALSE);
1853 aopOp (IC_RIGHT(ic),ic,FALSE);
1854 aopOp (IC_RESULT(ic),ic,TRUE);
1856 /* Swap the left and right operands if:
1858 if literal, literal on the right or
1859 if left requires ACC or right is already
1862 if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
1863 (AOP_NEEDSACC(IC_LEFT(ic))) ||
1864 AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
1865 operand *t = IC_RIGHT(ic);
1866 IC_RIGHT(ic) = IC_LEFT(ic);
1870 /* if both left & right are in bit
1872 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1873 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
1878 /* if left in bit space & right literal */
1879 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1880 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
1881 /* Can happen I guess */
1885 /* if I can do an increment instead
1886 of add then GOOD for ME */
1887 if (genPlusIncr (ic) == TRUE)
1890 size = getDataSize(IC_RESULT(ic));
1892 /* Special case when left and right are constant */
1893 if (isPair(AOP(IC_RESULT(ic)))) {
1896 left = aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE);
1897 right = aopGetLitWordLong(AOP(IC_RIGHT(ic)), 0, FALSE);
1898 if (left && right) {
1902 sprintf(buffer, "#(%s + %s)", left, right);
1903 emitcode("ld", "%s,%s", getPairName(AOP(IC_RESULT(ic))), buffer);
1908 if (isPair(AOP(IC_RIGHT(ic))) && getPairId(AOP(IC_RESULT(ic))) == PAIR_HL) {
1909 /* Fetch into HL then do the add */
1911 fetchPair(PAIR_HL, AOP(IC_LEFT(ic)));
1912 emitcode("add", "hl,%s", getPairName(AOP(IC_RIGHT(ic))));
1917 if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
1918 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1920 emitcode("add","a,%s",
1921 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1923 emitcode("adc","a,%s",
1924 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1926 MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1928 emitcode("add","a,%s",
1929 aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1931 emitcode("adc","a,%s",
1932 aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1934 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1937 /* Some kind of pointer arith. */
1938 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
1939 AOP_SIZE(IC_LEFT(ic)) == 3 &&
1940 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
1943 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
1944 AOP_SIZE(IC_RIGHT(ic)) == 3 &&
1945 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
1950 freeAsmop(IC_LEFT(ic),NULL,ic);
1951 freeAsmop(IC_RIGHT(ic),NULL,ic);
1952 freeAsmop(IC_RESULT(ic),NULL,ic);
1956 /*-----------------------------------------------------------------*/
1957 /* genMinusDec :- does subtraction with deccrement if possible */
1958 /*-----------------------------------------------------------------*/
1959 static bool genMinusDec (iCode *ic)
1961 unsigned int icount ;
1962 unsigned int size = getDataSize(IC_RESULT(ic));
1964 /* will try to generate an increment */
1965 /* if the right side is not a literal we cannot */
1966 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1969 /* if the literal value of the right hand side
1970 is greater than 4 then it is not worth it */
1971 if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
1974 size = getDataSize(IC_RESULT(ic));
1977 /* if increment 16 bits in register */
1978 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1981 symbol *tlbl = newiTempLabel(NULL);
1982 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
1983 emitcode("jp", "np," LABEL_STR ,tlbl->key+100);
1985 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
1989 emitLabel(tlbl->key+100);
1994 /* if decrement 16 bits in register */
1995 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1996 (size > 1) && isPair(AOP(IC_RESULT(ic)))) {
1998 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2002 /* If result is a pair */
2003 if (isPair(AOP(IC_RESULT(ic)))) {
2004 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
2005 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
2007 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2011 /* if the sizes are greater than 1 then we cannot */
2012 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2013 AOP_SIZE(IC_LEFT(ic)) > 1 )
2016 /* we can if the aops of the left & result match or if they are in
2017 registers and the registers are the same */
2018 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
2020 emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE));
2027 /*-----------------------------------------------------------------*/
2028 /* genMinus - generates code for subtraction */
2029 /*-----------------------------------------------------------------*/
2030 static void genMinus (iCode *ic)
2032 int size, offset = 0;
2033 unsigned long lit = 0L;
2035 aopOp (IC_LEFT(ic),ic,FALSE);
2036 aopOp (IC_RIGHT(ic),ic,FALSE);
2037 aopOp (IC_RESULT(ic),ic,TRUE);
2039 /* special cases :- */
2040 /* if both left & right are in bit space */
2041 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2042 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2047 /* if I can do an decrement instead of subtract then GOOD for ME */
2048 if (genMinusDec (ic) == TRUE)
2051 size = getDataSize(IC_RESULT(ic));
2053 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
2056 lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
2061 /* if literal, add a,#-lit, else normal subb */
2063 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2064 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) {
2066 emitcode("sub","a,%s",
2067 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2069 emitcode("sbc","a,%s",
2070 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2073 /* first add without previous c */
2075 emit2("add a,!immedbyte", (unsigned int)(lit & 0x0FFL));
2077 emit2("adc a,!immedbyte", (unsigned int)((lit >> (offset*8)) & 0x0FFL));
2079 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2082 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2083 AOP_SIZE(IC_LEFT(ic)) == 3 &&
2084 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2088 freeAsmop(IC_LEFT(ic),NULL,ic);
2089 freeAsmop(IC_RIGHT(ic),NULL,ic);
2090 freeAsmop(IC_RESULT(ic),NULL,ic);
2093 /*-----------------------------------------------------------------*/
2094 /* genMult - generates code for multiplication */
2095 /*-----------------------------------------------------------------*/
2096 static void genMult (iCode *ic)
2098 /* Shouldn't occur - all done through function calls */
2102 /*-----------------------------------------------------------------*/
2103 /* genDiv - generates code for division */
2104 /*-----------------------------------------------------------------*/
2105 static void genDiv (iCode *ic)
2107 /* Shouldn't occur - all done through function calls */
2111 /*-----------------------------------------------------------------*/
2112 /* genMod - generates code for division */
2113 /*-----------------------------------------------------------------*/
2114 static void genMod (iCode *ic)
2116 /* Shouldn't occur - all done through function calls */
2120 /*-----------------------------------------------------------------*/
2121 /* genIfxJump :- will create a jump depending on the ifx */
2122 /*-----------------------------------------------------------------*/
2123 static void genIfxJump (iCode *ic, char *jval)
2128 /* if true label then we jump if condition
2130 if ( IC_TRUE(ic) ) {
2132 if (!strcmp(jval, "a")) {
2135 else if (!strcmp(jval, "c")) {
2139 /* The buffer contains the bit on A that we should test */
2144 /* false label is present */
2145 jlbl = IC_FALSE(ic) ;
2146 if (!strcmp(jval, "a")) {
2149 else if (!strcmp(jval, "c")) {
2153 /* The buffer contains the bit on A that we should test */
2157 /* Z80 can do a conditional long jump */
2158 if (!strcmp(jval, "a")) {
2159 emitcode("or", "a,a");
2161 else if (!strcmp(jval, "c")) {
2164 emitcode("bit", "%s,a", jval);
2166 emit2("jp %s,!tlabel", inst, jlbl->key+100);
2168 /* mark the icode as generated */
2172 /** Generic compare for > or <
2174 static void genCmp (operand *left,operand *right,
2175 operand *result, iCode *ifx, int sign)
2177 int size, offset = 0 ;
2178 unsigned long lit = 0L;
2180 /* if left & right are bit variables */
2181 if (AOP_TYPE(left) == AOP_CRY &&
2182 AOP_TYPE(right) == AOP_CRY ) {
2183 /* Cant happen on the Z80 */
2186 /* subtract right from left if at the
2187 end the carry flag is set then we know that
2188 left is greater than right */
2189 size = max(AOP_SIZE(left),AOP_SIZE(right));
2191 /* if unsigned char cmp with lit, just compare */
2193 (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
2194 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2196 emit2("xor a,!immedbyte", 0x80);
2197 emit2("cp %s^!constbyte", aopGet(AOP(right), offset, FALSE), 0x80);
2200 emitcode("cp", "%s", aopGet(AOP(right), offset, FALSE));
2203 if(AOP_TYPE(right) == AOP_LIT) {
2204 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2205 /* optimize if(x < 0) or if(x >= 0) */
2208 /* No sign so it's always false */
2212 /* Just load in the top most bit */
2213 MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE));
2214 if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx) {
2215 genIfxJump (ifx,"7");
2219 emitcode("rlc","a");
2225 /* First setup h and l contaning the top most bytes XORed */
2226 bool fDidXor = FALSE;
2227 if (AOP_TYPE(left) == AOP_LIT){
2228 unsigned long lit = (unsigned long)
2229 floatFromVal(AOP(left)->aopu.aop_lit);
2230 emit2("ld %s,!immedbyte", _fTmp[0],
2231 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2234 emitcode("ld", "a,%s", aopGet(AOP(left), size-1, FALSE));
2235 emit2("xor a,!immedbyte", 0x80);
2236 emitcode("ld", "%s,a", _fTmp[0]);
2239 if (AOP_TYPE(right) == AOP_LIT) {
2240 unsigned long lit = (unsigned long)
2241 floatFromVal(AOP(right)->aopu.aop_lit);
2242 emit2("ld %s,!immedbyte", _fTmp[1],
2243 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2246 emitcode("ld", "a,%s", aopGet(AOP(right), size-1, FALSE));
2247 emit2("xor a,!immedbyte", 0x80);
2248 emitcode("ld", "%s,a", _fTmp[1]);
2258 /* Do a long subtract */
2259 if (!sign || size ) {
2260 MOVA(aopGet(AOP(left),offset,FALSE));
2262 if (sign && size == 0) {
2263 emitcode("ld", "a,%s", _fTmp[0]);
2264 emitcode("sbc", "a,%s", _fTmp[1]);
2267 /* Subtract through, propagating the carry */
2268 emitcode("sbc","a,%s ; 2",aopGet(AOP(right),offset++,FALSE));
2275 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2278 /* if the result is used in the next
2279 ifx conditional branch then generate
2280 code a little differently */
2282 genIfxJump (ifx,"c");
2285 /* leave the result in acc */
2289 /*-----------------------------------------------------------------*/
2290 /* genCmpGt :- greater than comparison */
2291 /*-----------------------------------------------------------------*/
2292 static void genCmpGt (iCode *ic, iCode *ifx)
2294 operand *left, *right, *result;
2295 link *letype , *retype;
2299 right= IC_RIGHT(ic);
2300 result = IC_RESULT(ic);
2302 letype = getSpec(operandType(left));
2303 retype =getSpec(operandType(right));
2304 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2305 /* assign the amsops */
2306 aopOp (left,ic,FALSE);
2307 aopOp (right,ic,FALSE);
2308 aopOp (result,ic,TRUE);
2310 genCmp(right, left, result, ifx, sign);
2312 freeAsmop(left,NULL,ic);
2313 freeAsmop(right,NULL,ic);
2314 freeAsmop(result,NULL,ic);
2317 /*-----------------------------------------------------------------*/
2318 /* genCmpLt - less than comparisons */
2319 /*-----------------------------------------------------------------*/
2320 static void genCmpLt (iCode *ic, iCode *ifx)
2322 operand *left, *right, *result;
2323 link *letype , *retype;
2327 right= IC_RIGHT(ic);
2328 result = IC_RESULT(ic);
2330 letype = getSpec(operandType(left));
2331 retype =getSpec(operandType(right));
2332 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2334 /* assign the amsops */
2335 aopOp (left,ic,FALSE);
2336 aopOp (right,ic,FALSE);
2337 aopOp (result,ic,TRUE);
2339 genCmp(left, right, result, ifx, sign);
2341 freeAsmop(left,NULL,ic);
2342 freeAsmop(right,NULL,ic);
2343 freeAsmop(result,NULL,ic);
2346 /*-----------------------------------------------------------------*/
2347 /* gencjneshort - compare and jump if not equal */
2348 /*-----------------------------------------------------------------*/
2349 static void gencjneshort(operand *left, operand *right, symbol *lbl)
2351 int size = max(AOP_SIZE(left),AOP_SIZE(right));
2353 unsigned long lit = 0L;
2355 /* Swap the left and right if it makes the computation easier */
2356 if (AOP_TYPE(left) == AOP_LIT) {
2362 if(AOP_TYPE(right) == AOP_LIT)
2363 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2365 /* if the right side is a literal then anything goes */
2366 if (AOP_TYPE(right) == AOP_LIT &&
2367 AOP_TYPE(left) != AOP_DIR ) {
2369 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2374 emitcode("or", "a,%s", aopGet(AOP(left), offset, FALSE));
2378 emitcode("or", "a,a");
2380 emit2("jp nz,!tlabel", lbl->key+100);
2384 emitcode("ld", "a,%s ; 2", aopGet(AOP(left),offset,FALSE));
2385 if ((AOP_TYPE(right) == AOP_LIT) && lit == 0)
2386 emitcode("or", "a,a");
2388 emitcode("cp", "a,%s", aopGet(AOP(right),offset,FALSE));
2389 emit2("jp nz,!tlabel", lbl->key+100);
2394 /* if the right side is in a register or in direct space or
2395 if the left is a pointer register & right is not */
2396 else if (AOP_TYPE(right) == AOP_REG ||
2397 AOP_TYPE(right) == AOP_DIR ||
2398 (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT)) {
2400 MOVA(aopGet(AOP(left),offset,FALSE));
2401 if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
2402 ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
2404 emit2("jp nz,!tlabel", lbl->key+100);
2406 emitcode("cp", "%s ; 4", aopGet(AOP(right),offset,FALSE));
2407 emit2("jp nz,!tlabel", lbl->key+100);
2412 /* right is a pointer reg need both a & b */
2413 /* PENDING: is this required? */
2415 MOVA(aopGet(AOP(right),offset,FALSE));
2416 emitcode("cp", "%s ; 5", aopGet(AOP(left), offset, FALSE));
2417 emit2("!shortjp nz,!tlabel", lbl->key+100);
2423 /*-----------------------------------------------------------------*/
2424 /* gencjne - compare and jump if not equal */
2425 /*-----------------------------------------------------------------*/
2426 static void gencjne(operand *left, operand *right, symbol *lbl)
2428 symbol *tlbl = newiTempLabel(NULL);
2430 gencjneshort(left, right, lbl);
2434 emit2("!shortjp !tlabel", tlbl->key+100);
2435 emitLabel(lbl->key+100);
2436 emitcode("xor","a,a");
2437 emitLabel(tlbl->key+100);
2440 /*-----------------------------------------------------------------*/
2441 /* genCmpEq - generates code for equal to */
2442 /*-----------------------------------------------------------------*/
2443 static void genCmpEq (iCode *ic, iCode *ifx)
2445 operand *left, *right, *result;
2447 aopOp((left=IC_LEFT(ic)),ic,FALSE);
2448 aopOp((right=IC_RIGHT(ic)),ic,FALSE);
2449 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2451 /* Swap operands if it makes the operation easier. ie if:
2452 1. Left is a literal.
2454 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
2455 operand *t = IC_RIGHT(ic);
2456 IC_RIGHT(ic) = IC_LEFT(ic);
2460 if (ifx && !AOP_SIZE(result)){
2462 /* if they are both bit variables */
2463 if (AOP_TYPE(left) == AOP_CRY &&
2464 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2467 tlbl = newiTempLabel(NULL);
2468 gencjneshort(left, right, tlbl);
2469 if ( IC_TRUE(ifx) ) {
2470 emit2("jp !tlabel", IC_TRUE(ifx)->key+100);
2471 emitLabel(tlbl->key+100);
2473 /* PENDING: do this better */
2474 symbol *lbl = newiTempLabel(NULL);
2475 emit2("!shortjp !tlabel", lbl->key+100);
2476 emitLabel(tlbl->key+100);
2477 emit2("jp !tlabel", IC_FALSE(ifx)->key+100);
2478 emitLabel(lbl->key+100);
2481 /* mark the icode as generated */
2486 /* if they are both bit variables */
2487 if (AOP_TYPE(left) == AOP_CRY &&
2488 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2491 gencjne(left,right,newiTempLabel(NULL));
2492 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2496 genIfxJump(ifx,"a");
2499 /* if the result is used in an arithmetic operation
2500 then put the result in place */
2501 if (AOP_TYPE(result) != AOP_CRY) {
2504 /* leave the result in acc */
2508 freeAsmop(left,NULL,ic);
2509 freeAsmop(right,NULL,ic);
2510 freeAsmop(result,NULL,ic);
2513 /*-----------------------------------------------------------------*/
2514 /* ifxForOp - returns the icode containing the ifx for operand */
2515 /*-----------------------------------------------------------------*/
2516 static iCode *ifxForOp ( operand *op, iCode *ic )
2518 /* if true symbol then needs to be assigned */
2519 if (IS_TRUE_SYMOP(op))
2522 /* if this has register type condition and
2523 the next instruction is ifx with the same operand
2524 and live to of the operand is upto the ifx only then */
2526 ic->next->op == IFX &&
2527 IC_COND(ic->next)->key == op->key &&
2528 OP_SYMBOL(op)->liveTo <= ic->next->seq )
2534 /*-----------------------------------------------------------------*/
2535 /* genAndOp - for && operation */
2536 /*-----------------------------------------------------------------*/
2537 static void genAndOp (iCode *ic)
2539 operand *left,*right, *result;
2542 /* note here that && operations that are in an if statement are
2543 taken away by backPatchLabels only those used in arthmetic
2544 operations remain */
2545 aopOp((left=IC_LEFT(ic)),ic,FALSE);
2546 aopOp((right=IC_RIGHT(ic)),ic,FALSE);
2547 aopOp((result=IC_RESULT(ic)),ic,FALSE);
2549 /* if both are bit variables */
2550 if (AOP_TYPE(left) == AOP_CRY &&
2551 AOP_TYPE(right) == AOP_CRY ) {
2554 tlbl = newiTempLabel(NULL);
2556 emit2("!shortjp z,!tlabel", tlbl->key+100);
2558 emitLabel(tlbl->key+100);
2562 freeAsmop(left,NULL,ic);
2563 freeAsmop(right,NULL,ic);
2564 freeAsmop(result,NULL,ic);
2567 /*-----------------------------------------------------------------*/
2568 /* genOrOp - for || operation */
2569 /*-----------------------------------------------------------------*/
2570 static void genOrOp (iCode *ic)
2572 operand *left,*right, *result;
2575 /* note here that || operations that are in an
2576 if statement are taken away by backPatchLabels
2577 only those used in arthmetic operations remain */
2578 aopOp((left=IC_LEFT(ic)),ic,FALSE);
2579 aopOp((right=IC_RIGHT(ic)),ic,FALSE);
2580 aopOp((result=IC_RESULT(ic)),ic,FALSE);
2582 /* if both are bit variables */
2583 if (AOP_TYPE(left) == AOP_CRY &&
2584 AOP_TYPE(right) == AOP_CRY ) {
2587 tlbl = newiTempLabel(NULL);
2589 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2591 emitLabel(tlbl->key+100);
2595 freeAsmop(left,NULL,ic);
2596 freeAsmop(right,NULL,ic);
2597 freeAsmop(result,NULL,ic);
2600 /*-----------------------------------------------------------------*/
2601 /* isLiteralBit - test if lit == 2^n */
2602 /*-----------------------------------------------------------------*/
2603 int isLiteralBit(unsigned long lit)
2605 unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
2606 0x100L,0x200L,0x400L,0x800L,
2607 0x1000L,0x2000L,0x4000L,0x8000L,
2608 0x10000L,0x20000L,0x40000L,0x80000L,
2609 0x100000L,0x200000L,0x400000L,0x800000L,
2610 0x1000000L,0x2000000L,0x4000000L,0x8000000L,
2611 0x10000000L,0x20000000L,0x40000000L,0x80000000L};
2614 for(idx = 0; idx < 32; idx++)
2620 /*-----------------------------------------------------------------*/
2621 /* jmpTrueOrFalse - */
2622 /*-----------------------------------------------------------------*/
2623 static void jmpTrueOrFalse (iCode *ic, symbol *tlbl)
2625 // ugly but optimized by peephole
2627 symbol *nlbl = newiTempLabel(NULL);
2628 emit2("jp !tlabel", nlbl->key+100);
2629 emitLabel(tlbl->key+100);
2630 emit2("jp !tlabel", IC_TRUE(ic)->key+100);
2631 emitLabel(nlbl->key+100);
2634 emit2("jp !tlabel", IC_FALSE(ic)->key+100);
2635 emitLabel(tlbl->key+100);
2640 /*-----------------------------------------------------------------*/
2641 /* genAnd - code for and */
2642 /*-----------------------------------------------------------------*/
2643 static void genAnd (iCode *ic, iCode *ifx)
2645 operand *left, *right, *result;
2647 unsigned long lit = 0L;
2650 aopOp((left = IC_LEFT(ic)),ic,FALSE);
2651 aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2652 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2655 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2657 AOP_TYPE(left), AOP_TYPE(right));
2658 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2660 AOP_SIZE(left), AOP_SIZE(right));
2663 /* if left is a literal & right is not then exchange them */
2664 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2665 AOP_NEEDSACC(left)) {
2666 operand *tmp = right ;
2671 /* if result = right then exchange them */
2672 if(sameRegs(AOP(result),AOP(right))){
2673 operand *tmp = right ;
2678 /* if right is bit then exchange them */
2679 if (AOP_TYPE(right) == AOP_CRY &&
2680 AOP_TYPE(left) != AOP_CRY){
2681 operand *tmp = right ;
2685 if(AOP_TYPE(right) == AOP_LIT)
2686 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2688 size = AOP_SIZE(result);
2690 if (AOP_TYPE(left) == AOP_CRY){
2695 // if(val & 0xZZ) - size = 0, ifx != FALSE -
2696 // bit = val & 0xZZ - size = 1, ifx = FALSE -
2697 if((AOP_TYPE(right) == AOP_LIT) &&
2698 (AOP_TYPE(result) == AOP_CRY) &&
2699 (AOP_TYPE(left) != AOP_CRY)) {
2700 int posbit = isLiteralBit(lit);
2704 MOVA(aopGet(AOP(left),posbit>>3,FALSE));
2708 emitcode("mov","c,acc.%d",posbit&0x07);
2713 sprintf(buffer, "%d", posbit&0x07);
2714 genIfxJump(ifx, buffer);
2722 symbol *tlbl = newiTempLabel(NULL);
2723 int sizel = AOP_SIZE(left);
2726 emitcode("setb","c");
2729 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
2730 MOVA( aopGet(AOP(left),offset,FALSE));
2732 if((posbit = isLiteralBit(bytelit)) != 0) {
2734 emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
2737 if(bytelit != 0x0FFL)
2738 emitcode("and","a,%s",
2739 aopGet(AOP(right),offset,FALSE));
2740 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2745 // bit = left & literal
2747 emitcode("clr","c");
2748 emit2("!tlabeldef", tlbl->key+100);
2750 // if(left & literal)
2753 jmpTrueOrFalse(ifx, tlbl);
2761 /* if left is same as result */
2762 if(sameRegs(AOP(result),AOP(left))){
2763 for(;size--; offset++) {
2764 if(AOP_TYPE(right) == AOP_LIT){
2765 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
2769 aopPut(AOP(result),zero,offset);
2771 MOVA(aopGet(AOP(left),offset,FALSE));
2772 emitcode("and","a,%s",
2773 aopGet(AOP(right),offset,FALSE));
2774 emitcode("ld", "%s,a", aopGet(AOP(left),offset,FALSE));
2779 if (AOP_TYPE(left) == AOP_ACC) {
2783 MOVA(aopGet(AOP(left),offset,FALSE));
2784 emitcode("and","a,%s",
2785 aopGet(AOP(right),offset,FALSE));
2786 emitcode("ld", "%s,a", aopGet(AOP(left),offset,FALSE));
2791 // left & result in different registers
2792 if(AOP_TYPE(result) == AOP_CRY){
2795 for(;(size--);offset++) {
2797 // result = left & right
2798 if(AOP_TYPE(right) == AOP_LIT){
2799 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
2801 aopGet(AOP(left),offset,FALSE),
2804 } else if(bytelit == 0){
2805 aopPut(AOP(result),zero,offset);
2809 // faster than result <- left, anl result,right
2810 // and better if result is SFR
2811 if (AOP_TYPE(left) == AOP_ACC)
2812 emitcode("and","a,%s",aopGet(AOP(right),offset,FALSE));
2814 MOVA(aopGet(AOP(right),offset,FALSE));
2815 emitcode("and","a,%s",
2816 aopGet(AOP(left),offset,FALSE));
2818 aopPut(AOP(result),"a",offset);
2825 freeAsmop(left,NULL,ic);
2826 freeAsmop(right,NULL,ic);
2827 freeAsmop(result,NULL,ic);
2830 /*-----------------------------------------------------------------*/
2831 /* genOr - code for or */
2832 /*-----------------------------------------------------------------*/
2833 static void genOr (iCode *ic, iCode *ifx)
2835 operand *left, *right, *result;
2837 unsigned long lit = 0L;
2839 aopOp((left = IC_LEFT(ic)),ic,FALSE);
2840 aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2841 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2844 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2846 AOP_TYPE(left), AOP_TYPE(right));
2847 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2849 AOP_SIZE(left), AOP_SIZE(right));
2852 /* if left is a literal & right is not then exchange them */
2853 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2854 AOP_NEEDSACC(left)) {
2855 operand *tmp = right ;
2860 /* if result = right then exchange them */
2861 if(sameRegs(AOP(result),AOP(right))){
2862 operand *tmp = right ;
2867 /* if right is bit then exchange them */
2868 if (AOP_TYPE(right) == AOP_CRY &&
2869 AOP_TYPE(left) != AOP_CRY){
2870 operand *tmp = right ;
2874 if(AOP_TYPE(right) == AOP_LIT)
2875 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2877 size = AOP_SIZE(result);
2879 if (AOP_TYPE(left) == AOP_CRY){
2884 if((AOP_TYPE(right) == AOP_LIT) &&
2885 (AOP_TYPE(result) == AOP_CRY) &&
2886 (AOP_TYPE(left) != AOP_CRY)){
2891 /* if left is same as result */
2892 if(sameRegs(AOP(result),AOP(left))){
2893 for(;size--; offset++) {
2894 if(AOP_TYPE(right) == AOP_LIT){
2895 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
2898 MOVA(aopGet(AOP(right),offset,FALSE));
2899 emitcode("or","a,%s; 5",
2900 aopGet(AOP(left),offset,FALSE));
2901 aopPut(AOP(result),"a ; 8", offset);
2904 if (AOP_TYPE(left) == AOP_ACC)
2905 emitcode("or","a,%s ; 6",aopGet(AOP(right),offset,FALSE));
2907 MOVA(aopGet(AOP(right),offset,FALSE));
2908 emitcode("or","a,%s ; 7",
2909 aopGet(AOP(left),offset,FALSE));
2910 aopPut(AOP(result),"a ; 8", offset);
2915 // left & result in different registers
2916 if(AOP_TYPE(result) == AOP_CRY){
2918 } else for(;(size--);offset++){
2920 // result = left & right
2921 if(AOP_TYPE(right) == AOP_LIT){
2922 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
2924 aopGet(AOP(left),offset,FALSE),
2929 // faster than result <- left, anl result,right
2930 // and better if result is SFR
2931 if (AOP_TYPE(left) == AOP_ACC)
2932 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
2934 MOVA(aopGet(AOP(right),offset,FALSE));
2935 emitcode("or","a,%s",
2936 aopGet(AOP(left),offset,FALSE));
2938 aopPut(AOP(result),"a",offset);
2939 /* PENDING: something weird is going on here. Add exception. */
2940 if (AOP_TYPE(result) == AOP_ACC)
2946 freeAsmop(left,NULL,ic);
2947 freeAsmop(right,NULL,ic);
2948 freeAsmop(result,NULL,ic);
2951 /*-----------------------------------------------------------------*/
2952 /* genXor - code for xclusive or */
2953 /*-----------------------------------------------------------------*/
2954 static void genXor (iCode *ic, iCode *ifx)
2956 operand *left, *right, *result;
2958 unsigned long lit = 0L;
2960 aopOp((left = IC_LEFT(ic)),ic,FALSE);
2961 aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2962 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2964 /* if left is a literal & right is not then exchange them */
2965 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2966 AOP_NEEDSACC(left)) {
2967 operand *tmp = right ;
2972 /* if result = right then exchange them */
2973 if(sameRegs(AOP(result),AOP(right))){
2974 operand *tmp = right ;
2979 /* if right is bit then exchange them */
2980 if (AOP_TYPE(right) == AOP_CRY &&
2981 AOP_TYPE(left) != AOP_CRY){
2982 operand *tmp = right ;
2986 if(AOP_TYPE(right) == AOP_LIT)
2987 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2989 size = AOP_SIZE(result);
2991 if (AOP_TYPE(left) == AOP_CRY){
2996 if((AOP_TYPE(right) == AOP_LIT) &&
2997 (AOP_TYPE(result) == AOP_CRY) &&
2998 (AOP_TYPE(left) != AOP_CRY)){
3003 /* if left is same as result */
3004 if(sameRegs(AOP(result),AOP(left))){
3005 for(;size--; offset++) {
3006 if(AOP_TYPE(right) == AOP_LIT){
3007 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3010 MOVA(aopGet(AOP(right),offset,FALSE));
3011 emitcode("xor","a,%s",
3012 aopGet(AOP(left),offset,FALSE));
3013 aopPut(AOP(result),"a",0);
3016 if (AOP_TYPE(left) == AOP_ACC)
3017 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3019 MOVA(aopGet(AOP(right),offset,FALSE));
3020 emitcode("xor","a,%s",
3021 aopGet(AOP(left),offset,FALSE));
3022 aopPut(AOP(result),"a",0);
3027 // left & result in different registers
3028 if(AOP_TYPE(result) == AOP_CRY){
3030 } else for(;(size--);offset++){
3032 // result = left & right
3033 if(AOP_TYPE(right) == AOP_LIT){
3034 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3036 aopGet(AOP(left),offset,FALSE),
3041 // faster than result <- left, anl result,right
3042 // and better if result is SFR
3043 if (AOP_TYPE(left) == AOP_ACC)
3044 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3046 MOVA(aopGet(AOP(right),offset,FALSE));
3047 emitcode("xor","a,%s",
3048 aopGet(AOP(left),offset,FALSE));
3049 aopPut(AOP(result),"a",0);
3051 aopPut(AOP(result),"a",offset);
3056 freeAsmop(left,NULL,ic);
3057 freeAsmop(right,NULL,ic);
3058 freeAsmop(result,NULL,ic);
3061 /*-----------------------------------------------------------------*/
3062 /* genInline - write the inline code out */
3063 /*-----------------------------------------------------------------*/
3064 static void genInline (iCode *ic)
3066 char buffer[MAX_INLINEASM];
3070 inLine += (!options.asmpeep);
3071 strcpy(buffer,IC_INLINE(ic));
3073 /* emit each line as a code */
3092 /* emitcode("",buffer); */
3093 inLine -= (!options.asmpeep);
3096 /*-----------------------------------------------------------------*/
3097 /* genRRC - rotate right with carry */
3098 /*-----------------------------------------------------------------*/
3099 static void genRRC (iCode *ic)
3104 /*-----------------------------------------------------------------*/
3105 /* genRLC - generate code for rotate left with carry */
3106 /*-----------------------------------------------------------------*/
3107 static void genRLC (iCode *ic)
3112 /*-----------------------------------------------------------------*/
3113 /* shiftR2Left2Result - shift right two bytes from left to result */
3114 /*-----------------------------------------------------------------*/
3115 static void shiftR2Left2Result (operand *left, int offl,
3116 operand *result, int offr,
3117 int shCount, int sign)
3119 if(sameRegs(AOP(result), AOP(left)) &&
3120 ((offl + MSB16) == offr)){
3123 movLeft2Result(left, offl, result, offr, 0);
3124 movLeft2Result(left, offl+1, result, offr+1, 0);
3131 /* if (AOP(result)->type == AOP_REG) {*/
3134 symbol *tlbl , *tlbl1;
3137 /* Left is already in result - so now do the shift */
3139 emit2("ld a,!immedbyte+1", shCount);
3140 tlbl = newiTempLabel(NULL);
3141 tlbl1 = newiTempLabel(NULL);
3142 emit2("!shortjp !tlabel", tlbl1->key+100);
3143 emitLabel(tlbl->key+100);
3146 emitcode("or", "a,a");
3149 l = aopGet(AOP(result), --offset, FALSE);
3150 emitcode("rr","%s", l);
3153 emitLabel(tlbl1->key+100);
3154 emitcode("dec", "a");
3155 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3160 /*-----------------------------------------------------------------*/
3161 /* shiftL2Left2Result - shift left two bytes from left to result */
3162 /*-----------------------------------------------------------------*/
3163 static void shiftL2Left2Result (operand *left, int offl,
3164 operand *result, int offr, int shCount)
3166 if(sameRegs(AOP(result), AOP(left)) &&
3167 ((offl + MSB16) == offr)){
3170 /* Copy left into result */
3171 movLeft2Result(left, offl, result, offr, 0);
3172 movLeft2Result(left, offl+1, result, offr+1, 0);
3174 /* PENDING: for now just see if it'll work. */
3175 /*if (AOP(result)->type == AOP_REG) { */
3179 symbol *tlbl , *tlbl1;
3182 /* Left is already in result - so now do the shift */
3184 emit2("ld a,!immedbyte+1", shCount);
3185 tlbl = newiTempLabel(NULL);
3186 tlbl1 = newiTempLabel(NULL);
3187 emit2("!shortjp !tlabel", tlbl1->key+100);
3188 emitLabel(tlbl->key+100);
3191 emitcode("or", "a,a");
3193 l = aopGet(AOP(result),offset++,FALSE);
3194 emitcode("rl","%s", l);
3197 emitLabel(tlbl1->key+100);
3198 emitcode("dec", "a");
3199 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3204 /*-----------------------------------------------------------------*/
3205 /* AccRol - rotate left accumulator by known count */
3206 /*-----------------------------------------------------------------*/
3207 static void AccRol (int shCount)
3209 shCount &= 0x0007; // shCount : 0..7
3246 /*-----------------------------------------------------------------*/
3247 /* AccLsh - left shift accumulator by known count */
3248 /*-----------------------------------------------------------------*/
3249 static void AccLsh (int shCount)
3253 emitcode("add","a,a");
3256 emitcode("add","a,a");
3257 emitcode("add","a,a");
3259 /* rotate left accumulator */
3261 /* and kill the lower order bits */
3262 emit2("and a,!immedbyte", SLMask[shCount]);
3267 /*-----------------------------------------------------------------*/
3268 /* shiftL1Left2Result - shift left one byte from left to result */
3269 /*-----------------------------------------------------------------*/
3270 static void shiftL1Left2Result (operand *left, int offl,
3271 operand *result, int offr, int shCount)
3274 l = aopGet(AOP(left),offl,FALSE);
3276 /* shift left accumulator */
3278 aopPut(AOP(result),"a",offr);
3282 /*-----------------------------------------------------------------*/
3283 /* genlshTwo - left shift two bytes by known amount != 0 */
3284 /*-----------------------------------------------------------------*/
3285 static void genlshTwo (operand *result,operand *left, int shCount)
3287 int size = AOP_SIZE(result);
3291 /* if shCount >= 8 */
3297 movLeft2Result(left, LSB, result, MSB16, 0);
3298 aopPut(AOP(result),zero, 0);
3299 shiftL1Left2Result(left, MSB16, result, MSB16, shCount-8);
3302 movLeft2Result(left, LSB, result, MSB16, 0);
3303 aopPut(AOP(result),zero, 0);
3306 aopPut(AOP(result),zero,LSB);
3308 /* 1 <= shCount <= 7 */
3314 shiftL2Left2Result(left, LSB, result, LSB, shCount);
3319 /*-----------------------------------------------------------------*/
3320 /* genlshOne - left shift a one byte quantity by known count */
3321 /*-----------------------------------------------------------------*/
3322 static void genlshOne (operand *result, operand *left, int shCount)
3324 shiftL1Left2Result(left, LSB, result, LSB, shCount);
3327 /*-----------------------------------------------------------------*/
3328 /* genLeftShiftLiteral - left shifting by known count */
3329 /*-----------------------------------------------------------------*/
3330 static void genLeftShiftLiteral (operand *left,
3335 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3338 freeAsmop(right,NULL,ic);
3340 aopOp(left,ic,FALSE);
3341 aopOp(result,ic,FALSE);
3343 size = getSize(operandType(result));
3346 emitcode("; shift left ","result %d, left %d",size,
3350 /* I suppose that the left size >= result size */
3355 else if(shCount >= (size * 8))
3357 aopPut(AOP(result),zero,size);
3361 genlshOne (result,left,shCount);
3364 genlshTwo (result,left,shCount);
3373 freeAsmop(left,NULL,ic);
3374 freeAsmop(result,NULL,ic);
3377 /*-----------------------------------------------------------------*/
3378 /* genLeftShift - generates code for left shifting */
3379 /*-----------------------------------------------------------------*/
3380 static void genLeftShift (iCode *ic)
3384 symbol *tlbl , *tlbl1;
3385 operand *left,*right, *result;
3387 right = IC_RIGHT(ic);
3389 result = IC_RESULT(ic);
3391 aopOp(right,ic,FALSE);
3393 /* if the shift count is known then do it
3394 as efficiently as possible */
3395 if (AOP_TYPE(right) == AOP_LIT) {
3396 genLeftShiftLiteral (left,right,result,ic);
3400 /* shift count is unknown then we have to form a loop get the loop
3401 count in B : Note: we take only the lower order byte since
3402 shifting more that 32 bits make no sense anyway, ( the largest
3403 size of an object can be only 32 bits ) */
3404 emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE));
3405 emitcode("inc","a");
3406 freeAsmop (right,NULL,ic);
3407 aopOp(left,ic,FALSE);
3408 aopOp(result,ic,FALSE);
3410 /* now move the left to the result if they are not the
3413 if (!sameRegs(AOP(left),AOP(result))) {
3415 size = AOP_SIZE(result);
3418 l = aopGet(AOP(left),offset,FALSE);
3419 aopPut(AOP(result),l,offset);
3424 size = AOP_SIZE(result);
3427 l = aopGet(AOP(left),offset,FALSE);
3428 aopPut(AOP(result),l,offset);
3434 tlbl = newiTempLabel(NULL);
3435 size = AOP_SIZE(result);
3437 tlbl1 = newiTempLabel(NULL);
3439 emit2("!shortjp !tlabel", tlbl1->key+100);
3440 emitLabel(tlbl->key+100);
3441 l = aopGet(AOP(result),offset,FALSE);
3442 emitcode("or", "a,a");
3444 l = aopGet(AOP(result),offset++,FALSE);
3445 emitcode("rl","%s", l);
3447 emitLabel(tlbl1->key+100);
3448 emitcode("dec", "a");
3449 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3451 freeAsmop(left,NULL,ic);
3452 freeAsmop(result,NULL,ic);
3455 /*-----------------------------------------------------------------*/
3456 /* genlshTwo - left shift two bytes by known amount != 0 */
3457 /*-----------------------------------------------------------------*/
3458 static void genrshOne (operand *result,operand *left, int shCount)
3461 int size = AOP_SIZE(result);
3467 l = aopGet(AOP(left),0,FALSE);
3468 if (AOP(result)->type == AOP_REG) {
3469 aopPut(AOP(result), l, 0);
3470 l = aopGet(AOP(result), 0, FALSE);
3472 emitcode("srl", "%s", l);
3477 emitcode("srl", "a");
3479 aopPut(AOP(result),"a",0);
3483 /*-----------------------------------------------------------------*/
3484 /* AccRsh - right shift accumulator by known count */
3485 /*-----------------------------------------------------------------*/
3486 static void AccRsh (int shCount)
3493 /* rotate right accumulator */
3494 AccRol(8 - shCount);
3495 /* and kill the higher order bits */
3496 emit2("and a,!immedbyte", SRMask[shCount]);
3501 /*-----------------------------------------------------------------*/
3502 /* shiftR1Left2Result - shift right one byte from left to result */
3503 /*-----------------------------------------------------------------*/
3504 static void shiftR1Left2Result (operand *left, int offl,
3505 operand *result, int offr,
3506 int shCount, int sign)
3508 MOVA(aopGet(AOP(left),offl,FALSE));
3515 aopPut(AOP(result),"a",offr);
3518 /*-----------------------------------------------------------------*/
3519 /* genrshTwo - right shift two bytes by known amount != 0 */
3520 /*-----------------------------------------------------------------*/
3521 static void genrshTwo (operand *result,operand *left,
3522 int shCount, int sign)
3524 /* if shCount >= 8 */
3529 shiftR1Left2Result(left, MSB16, result, LSB,
3533 movLeft2Result(left, MSB16, result, LSB, sign);
3534 aopPut(AOP(result),zero,1);
3537 /* 1 <= shCount <= 7 */
3539 shiftR2Left2Result(left, LSB, result, LSB, shCount, sign);
3543 /*-----------------------------------------------------------------*/
3544 /* genRightShiftLiteral - left shifting by known count */
3545 /*-----------------------------------------------------------------*/
3546 static void genRightShiftLiteral (operand *left,
3551 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3554 freeAsmop(right,NULL,ic);
3556 aopOp(left,ic,FALSE);
3557 aopOp(result,ic,FALSE);
3559 size = getSize(operandType(result));
3561 emitcode("; shift right ","result %d, left %d",size,
3564 /* I suppose that the left size >= result size */
3569 else if(shCount >= (size * 8))
3571 aopPut(AOP(result),zero,size);
3575 genrshOne(result, left, shCount);
3578 /* PENDING: sign support */
3579 genrshTwo(result, left, shCount, FALSE);
3588 freeAsmop(left,NULL,ic);
3589 freeAsmop(result,NULL,ic);
3592 /*-----------------------------------------------------------------*/
3593 /* genRightShift - generate code for right shifting */
3594 /*-----------------------------------------------------------------*/
3595 static void genRightShift (iCode *ic)
3597 operand *right, *left, *result;
3599 int size, offset, first = 1;
3603 symbol *tlbl, *tlbl1 ;
3605 /* if signed then we do it the hard way preserve the
3606 sign bit moving it inwards */
3607 retype = getSpec(operandType(IC_RESULT(ic)));
3609 is_signed = !SPEC_USIGN(retype);
3611 /* signed & unsigned types are treated the same : i.e. the
3612 signed is NOT propagated inwards : quoting from the
3613 ANSI - standard : "for E1 >> E2, is equivalent to division
3614 by 2**E2 if unsigned or if it has a non-negative value,
3615 otherwise the result is implementation defined ", MY definition
3616 is that the sign does not get propagated */
3618 right = IC_RIGHT(ic);
3620 result = IC_RESULT(ic);
3622 aopOp(right,ic,FALSE);
3624 /* if the shift count is known then do it
3625 as efficiently as possible */
3626 if (AOP_TYPE(right) == AOP_LIT) {
3627 genRightShiftLiteral(left,right,result,ic);
3631 aopOp(left,ic,FALSE);
3632 aopOp(result,ic,FALSE);
3634 /* now move the left to the result if they are not the
3636 if (!sameRegs(AOP(left),AOP(result)) &&
3637 AOP_SIZE(result) > 1) {
3639 size = AOP_SIZE(result);
3642 l = aopGet(AOP(left),offset,FALSE);
3643 aopPut(AOP(result),l,offset);
3648 emitcode("ld", "a,%s",aopGet(AOP(right),0,FALSE));
3649 emitcode("inc","a");
3650 freeAsmop (right, NULL, ic);
3652 tlbl = newiTempLabel(NULL);
3653 tlbl1= newiTempLabel(NULL);
3654 size = AOP_SIZE(result);
3657 emit2("!shortjp !tlabel", tlbl1->key+100);
3658 emitLabel(tlbl->key+100);
3660 l = aopGet(AOP(result),offset--,FALSE);
3663 emitcode("sra", "%s", l);
3665 emitcode("srl", "%s", l);
3669 emitcode("rr", "%s", l);
3671 emitLabel(tlbl1->key+100);
3672 emitcode("dec", "a");
3673 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3675 freeAsmop(left,NULL,ic);
3676 freeAsmop(result,NULL,ic);
3679 /*-----------------------------------------------------------------*/
3680 /* genGenPointerGet - gget value from generic pointer space */
3681 /*-----------------------------------------------------------------*/
3682 static void genGenPointerGet (operand *left,
3683 operand *result, iCode *ic)
3686 link *retype = getSpec(operandType(result));
3692 aopOp(left,ic,FALSE);
3693 aopOp(result,ic,FALSE);
3695 if (isPair(AOP(left)) && AOP_SIZE(result)==1) {
3697 if (isPtrPair(AOP(left)))
3699 tsprintf(buffer, "!*pair", getPairName(AOP(left)));
3700 aopPut(AOP(result), buffer, 0);
3703 emit2("ld a,!*pair", getPairName(AOP(left)));
3704 aopPut(AOP(result),"a", 0);
3706 freeAsmop(left,NULL,ic);
3710 /* For now we always load into IY */
3711 /* if this is remateriazable */
3712 fetchPair(pair, AOP(left));
3714 /* so iy now contains the address */
3715 freeAsmop(left,NULL,ic);
3717 /* if bit then unpack */
3718 if (IS_BITVAR(retype)) {
3722 size = AOP_SIZE(result);
3726 /* PENDING: make this better */
3727 if (!IS_GB && AOP(result)->type == AOP_REG) {
3728 aopPut(AOP(result), "!*hl", offset++);
3731 emit2("ld a,!*pair", _pairs[pair].name);
3732 aopPut(AOP(result),"a",offset++);
3735 emit2("inc %s", _pairs[pair].name);
3741 freeAsmop(result,NULL,ic);
3744 /*-----------------------------------------------------------------*/
3745 /* genPointerGet - generate code for pointer get */
3746 /*-----------------------------------------------------------------*/
3747 static void genPointerGet (iCode *ic)
3749 operand *left, *result ;
3753 result = IC_RESULT(ic) ;
3755 /* depending on the type of pointer we need to
3756 move it to the correct pointer register */
3757 type = operandType(left);
3758 etype = getSpec(type);
3760 genGenPointerGet (left,result,ic);
3763 bool isRegOrLit(asmop *aop)
3765 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
3770 /*-----------------------------------------------------------------*/
3771 /* genGenPointerSet - stores the value into a pointer location */
3772 /*-----------------------------------------------------------------*/
3773 static void genGenPointerSet (operand *right,
3774 operand *result, iCode *ic)
3777 link *retype = getSpec(operandType(right));
3778 PAIR_ID pairId = PAIR_HL;
3780 aopOp(result,ic,FALSE);
3781 aopOp(right,ic,FALSE);
3786 /* Handle the exceptions first */
3787 if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
3789 char *l = aopGet(AOP(right), 0, FALSE);
3790 const char *pair = getPairName(AOP(result));
3791 if (canAssignToPtr(l) && isPtr(pair)) {
3792 emit2("ld !*pair,%s", pair, l);
3796 emit2("ld !*pair,a", pair);
3801 /* if the operand is already in dptr
3802 then we do nothing else we move the value to dptr */
3803 if (AOP_TYPE(result) != AOP_STR) {
3804 fetchPair(pairId, AOP(result));
3806 /* so hl know contains the address */
3807 freeAsmop(result,NULL,ic);
3809 /* if bit then unpack */
3810 if (IS_BITVAR(retype)) {
3814 size = AOP_SIZE(right);
3818 char *l = aopGet(AOP(right),offset,FALSE);
3819 if (isRegOrLit(AOP(right)) && !IS_GB) {
3820 emit2("ld !*pair,%s", _pairs[pairId].name, l);
3824 emit2("ld !*pair,a", _pairs[pairId].name);
3827 emitcode("inc", _pairs[pairId].name);
3833 freeAsmop(right,NULL,ic);
3836 /*-----------------------------------------------------------------*/
3837 /* genPointerSet - stores the value into a pointer location */
3838 /*-----------------------------------------------------------------*/
3839 static void genPointerSet (iCode *ic)
3841 operand *right, *result ;
3844 right = IC_RIGHT(ic);
3845 result = IC_RESULT(ic) ;
3847 /* depending on the type of pointer we need to
3848 move it to the correct pointer register */
3849 type = operandType(result);
3850 etype = getSpec(type);
3852 genGenPointerSet (right,result,ic);
3855 /*-----------------------------------------------------------------*/
3856 /* genIfx - generate code for Ifx statement */
3857 /*-----------------------------------------------------------------*/
3858 static void genIfx (iCode *ic, iCode *popIc)
3860 operand *cond = IC_COND(ic);
3863 aopOp(cond,ic,FALSE);
3865 /* get the value into acc */
3866 if (AOP_TYPE(cond) != AOP_CRY)
3870 /* the result is now in the accumulator */
3871 freeAsmop(cond,NULL,ic);
3873 /* if there was something to be popped then do it */
3877 /* if the condition is a bit variable */
3878 if (isbit && IS_ITEMP(cond) &&
3880 genIfxJump(ic,SPIL_LOC(cond)->rname);
3882 if (isbit && !IS_ITEMP(cond))
3883 genIfxJump(ic,OP_SYMBOL(cond)->rname);
3890 /*-----------------------------------------------------------------*/
3891 /* genAddrOf - generates code for address of */
3892 /*-----------------------------------------------------------------*/
3893 static void genAddrOf (iCode *ic)
3895 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
3897 aopOp(IC_RESULT(ic),ic,FALSE);
3899 /* if the operand is on the stack then we
3900 need to get the stack offset of this
3905 emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
3906 emitcode("ld", "d,h");
3907 emitcode("ld", "e,l");
3910 emitcode("ld", "de,#%s", sym->rname);
3912 aopPut(AOP(IC_RESULT(ic)), "e", 0);
3913 aopPut(AOP(IC_RESULT(ic)), "d", 1);
3918 /* if it has an offset then we need to compute it */
3919 emitcode("ld", "hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
3920 emitcode("add", "hl,sp");
3923 emitcode("ld", "hl,#%s", sym->rname);
3925 aopPut(AOP(IC_RESULT(ic)), "l", 0);
3926 aopPut(AOP(IC_RESULT(ic)), "h", 1);
3928 freeAsmop(IC_RESULT(ic),NULL,ic);
3931 /*-----------------------------------------------------------------*/
3932 /* genAssign - generate code for assignment */
3933 /*-----------------------------------------------------------------*/
3934 static void genAssign (iCode *ic)
3936 operand *result, *right;
3938 unsigned long lit = 0L;
3940 result = IC_RESULT(ic);
3941 right = IC_RIGHT(ic) ;
3944 /* Dont bother assigning if they are the same */
3945 if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) {
3946 emitcode("", "; (operands are equal %u)", operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)));
3951 aopOp(right,ic,FALSE);
3952 aopOp(result,ic,TRUE);
3954 /* if they are the same registers */
3955 if (sameRegs(AOP(right),AOP(result))) {
3956 emitcode("", "; (registers are the same)");
3960 /* if the result is a bit */
3961 if (AOP_TYPE(result) == AOP_CRY) {
3966 size = AOP_SIZE(result);
3969 if(AOP_TYPE(right) == AOP_LIT)
3970 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
3971 if (isPair(AOP(result)) && isLitWord(AOP(right))) {
3972 emitcode("ld", "%s,%s", getPairName(AOP(result)), aopGetWord(AOP(right), 0));
3974 else if((size > 1) &&
3975 (AOP_TYPE(result) != AOP_REG) &&
3976 (AOP_TYPE(right) == AOP_LIT) &&
3977 !IS_FLOAT(operandType(right)) &&
3979 bool fXored = FALSE;
3981 /* Work from the top down.
3982 Done this way so that we can use the cached copy of 0
3983 in A for a fast clear */
3985 if((unsigned int)((lit >> (offset*8)) & 0x0FFL)== 0) {
3986 if (!fXored && size>1) {
3987 emitcode("xor", "a,a");
3991 aopPut(AOP(result),"a",offset);
3994 aopPut(AOP(result), zero, offset);
3999 aopGet(AOP(right),offset,FALSE),
4004 else if (size == 2 && requiresHL(AOP(right)) && requiresHL(AOP(result))) {
4005 /* Special case. Load into a and d, then load out. */
4006 MOVA(aopGet(AOP(right), 0, FALSE));
4007 emitcode("ld", "e,%s", aopGet(AOP(right), 1, FALSE));
4008 aopPut(AOP(result), "a", 0);
4009 aopPut(AOP(result), "e", 1);
4012 /* PENDING: do this check better */
4013 if (requiresHL(AOP(right)) && requiresHL(AOP(result))) {
4014 MOVA(aopGet(AOP(right), offset, FALSE));
4015 aopPut(AOP(result), "a", offset);
4019 aopGet(AOP(right),offset,FALSE),
4026 freeAsmop(right,NULL,ic);
4027 freeAsmop(result,NULL,ic);
4030 /*-----------------------------------------------------------------*/
4031 /* genJumpTab - genrates code for jump table */
4032 /*-----------------------------------------------------------------*/
4033 static void genJumpTab (iCode *ic)
4038 aopOp(IC_JTCOND(ic),ic,FALSE);
4039 /* get the condition into accumulator */
4040 l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE);
4042 emitcode("push", "de");
4043 emitcode("ld", "e,%s", l);
4044 emit2("ld d,!zero");
4045 jtab = newiTempLabel(NULL);
4047 emit2("ld hl,!immed!tlabel", jtab->key+100);
4048 emitcode("add", "hl,de");
4049 emitcode("add", "hl,de");
4050 emitcode("add", "hl,de");
4051 freeAsmop(IC_JTCOND(ic),NULL,ic);
4053 emitcode("pop", "de");
4055 emitLabel(jtab->key+100);
4056 /* now generate the jump labels */
4057 for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
4058 jtab = setNextItem(IC_JTLABELS(ic)))
4059 emit2("jp !tlabel", jtab->key+100);
4062 /*-----------------------------------------------------------------*/
4063 /* genCast - gen code for casting */
4064 /*-----------------------------------------------------------------*/
4065 static void genCast (iCode *ic)
4067 operand *result = IC_RESULT(ic);
4068 link *ctype = operandType(IC_LEFT(ic));
4069 operand *right = IC_RIGHT(ic);
4072 /* if they are equivalent then do nothing */
4073 if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
4076 aopOp(right,ic,FALSE) ;
4077 aopOp(result,ic,FALSE);
4079 /* if the result is a bit */
4080 if (AOP_TYPE(result) == AOP_CRY) {
4084 /* if they are the same size : or less */
4085 if (AOP_SIZE(result) <= AOP_SIZE(right)) {
4087 /* if they are in the same place */
4088 if (sameRegs(AOP(right),AOP(result)))
4091 /* if they in different places then copy */
4092 size = AOP_SIZE(result);
4096 aopGet(AOP(right),offset,FALSE),
4103 /* PENDING: should be OK. */
4105 /* if the result is of type pointer */
4106 if (IS_PTR(ctype)) {
4111 /* so we now know that the size of destination is greater
4112 than the size of the source */
4113 /* we move to result for the size of source */
4114 size = AOP_SIZE(right);
4118 aopGet(AOP(right),offset,FALSE),
4123 /* now depending on the sign of the destination */
4124 size = AOP_SIZE(result) - AOP_SIZE(right);
4125 /* Unsigned or not an integral type - right fill with zeros */
4126 if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) {
4128 aopPut(AOP(result),zero,offset++);
4130 /* we need to extend the sign :{ */
4131 char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
4134 emitcode("", "; genCast: sign extend untested.");
4135 emitcode("rla", "");
4136 emitcode("sbc", "a,a");
4138 aopPut(AOP(result),"a",offset++);
4142 freeAsmop(right, NULL, ic);
4143 freeAsmop(result, NULL, ic);
4146 /*-----------------------------------------------------------------*/
4147 /* genReceive - generate code for a receive iCode */
4148 /*-----------------------------------------------------------------*/
4149 static void genReceive (iCode *ic)
4151 if (isOperandInFarSpace(IC_RESULT(ic)) &&
4152 ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
4153 IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
4157 aopOp(IC_RESULT(ic),ic,FALSE);
4159 assignResultValue(IC_RESULT(ic));
4162 freeAsmop(IC_RESULT(ic),NULL,ic);
4165 /*-----------------------------------------------------------------*/
4166 /* genZ80Code - generate code for Z80 based controllers */
4167 /*-----------------------------------------------------------------*/
4168 void genZ80Code (iCode *lic)
4175 _fReturn = _gbz80_return;
4176 _fTmp = _gbz80_return;
4179 _fReturn = _z80_return;
4180 _fTmp = _z80_return;
4182 tsprintf(zero, "!zero");
4184 lineHead = lineCurr = NULL;
4186 /* if debug information required */
4187 if (options.debug && currFunc) {
4188 cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
4190 if (IS_STATIC(currFunc->etype))
4191 emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name);
4193 emitcode("","G$%s$0$0 ==.",currFunc->name);
4196 /* stack pointer name */
4200 for (ic = lic ; ic ; ic = ic->next ) {
4202 if ( cln != ic->lineno ) {
4203 if ( options.debug ) {
4205 emitcode("","C$%s$%d$%d$%d ==.",
4206 ic->filename,ic->lineno,
4207 ic->level,ic->block);
4210 emitcode(";","%s %d",ic->filename,ic->lineno);
4213 /* if the result is marked as
4214 spilt and rematerializable or code for
4215 this has already been generated then
4217 if (resultRemat(ic) || ic->generated )
4220 /* depending on the operation */
4223 emitcode("", "; genNot");
4228 emitcode("", "; genCpl");
4233 emitcode("", "; genUminus");
4238 emitcode("", "; genIpush");
4243 /* IPOP happens only when trying to restore a
4244 spilt live range, if there is an ifx statement
4245 following this pop then the if statement might
4246 be using some of the registers being popped which
4247 would destory the contents of the register so
4248 we need to check for this condition and handle it */
4250 ic->next->op == IFX &&
4251 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) {
4252 emitcode("", "; genIfx");
4253 genIfx (ic->next,ic);
4256 emitcode("", "; genIpop");
4262 emitcode("", "; genCall");
4267 emitcode("", "; genPcall");
4272 emitcode("", "; genFunction");
4277 emitcode("", "; genEndFunction");
4278 genEndFunction (ic);
4282 emitcode("", "; genRet");
4287 emitcode("", "; genLabel");
4292 emitcode("", "; genGoto");
4297 emitcode("", "; genPlus");
4302 emitcode("", "; genMinus");
4307 emitcode("", "; genMult");
4312 emitcode("", "; genDiv");
4317 emitcode("", "; genMod");
4322 emitcode("", "; genCmpGt");
4323 genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));
4327 emitcode("", "; genCmpLt");
4328 genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
4335 /* note these two are xlated by algebraic equivalence
4336 during parsing SDCC.y */
4337 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
4338 "got '>=' or '<=' shouldn't have come here");
4342 emitcode("", "; genCmpEq");
4343 genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
4347 emitcode("", "; genAndOp");
4352 emitcode("", "; genOrOp");
4357 emitcode("", "; genXor");
4358 genXor (ic,ifxForOp(IC_RESULT(ic),ic));
4362 emitcode("", "; genOr");
4363 genOr (ic,ifxForOp(IC_RESULT(ic),ic));
4367 emitcode("", "; genAnd");
4368 genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
4372 emitcode("", "; genInline");
4377 emitcode("", "; genRRC");
4382 emitcode("", "; genRLC");
4387 emitcode("", "; genHBIT");
4391 emitcode("", "; genLeftShift");
4396 emitcode("", "; genRightShift");
4400 case GET_VALUE_AT_ADDRESS:
4401 emitcode("", "; genPointerGet");
4407 if (POINTER_SET(ic)) {
4408 emitcode("", "; genAssign (pointer)");
4412 emitcode("", "; genAssign");
4418 emitcode("", "; genIfx");
4423 emitcode("", "; genAddrOf");
4428 emitcode("", "; genJumpTab");
4433 emitcode("", "; genCast");
4438 emitcode("", "; genReceive");
4443 emitcode("", "; addSet");
4444 addSet(&sendSet,ic);
4449 /* piCode(ic,stdout); */
4455 /* now we are ready to call the
4456 peep hole optimizer */
4457 if (!options.nopeep)
4458 peepHole (&lineHead);
4460 /* now do the actual printing */
4461 printLine (lineHead,codeOutFile);