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))) &&
1791 symbol *tlbl = newiTempLabel(NULL);
1792 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
1793 emit2("!shortjp nz,!tlabel", tlbl->key+100);
1795 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
1799 emitLabel(tlbl->key+100);
1803 /* if the sizes are greater than 1 then we cannot */
1804 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
1805 AOP_SIZE(IC_LEFT(ic)) > 1 )
1808 /* we can if the aops of the left & result match or
1809 if they are in registers and the registers are the
1811 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
1813 emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0, FALSE));
1821 /*-----------------------------------------------------------------*/
1822 /* outBitAcc - output a bit in acc */
1823 /*-----------------------------------------------------------------*/
1824 void outBitAcc(operand *result)
1826 symbol *tlbl = newiTempLabel(NULL);
1827 /* if the result is a bit */
1828 if (AOP_TYPE(result) == AOP_CRY){
1832 emit2("!shortjp z,!tlabel", tlbl->key+100);
1834 emitLabel(tlbl->key+100);
1839 /*-----------------------------------------------------------------*/
1840 /* genPlus - generates code for addition */
1841 /*-----------------------------------------------------------------*/
1842 static void genPlus (iCode *ic)
1844 int size, offset = 0;
1846 /* special cases :- */
1848 aopOp (IC_LEFT(ic),ic,FALSE);
1849 aopOp (IC_RIGHT(ic),ic,FALSE);
1850 aopOp (IC_RESULT(ic),ic,TRUE);
1852 /* Swap the left and right operands if:
1854 if literal, literal on the right or
1855 if left requires ACC or right is already
1858 if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
1859 (AOP_NEEDSACC(IC_LEFT(ic))) ||
1860 AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
1861 operand *t = IC_RIGHT(ic);
1862 IC_RIGHT(ic) = IC_LEFT(ic);
1866 /* if both left & right are in bit
1868 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1869 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
1874 /* if left in bit space & right literal */
1875 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1876 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
1877 /* Can happen I guess */
1881 /* if I can do an increment instead
1882 of add then GOOD for ME */
1883 if (genPlusIncr (ic) == TRUE)
1886 size = getDataSize(IC_RESULT(ic));
1888 /* Special case when left and right are constant */
1889 if (isPair(AOP(IC_RESULT(ic)))) {
1892 left = aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE);
1893 right = aopGetLitWordLong(AOP(IC_RIGHT(ic)), 0, FALSE);
1894 if (left && right) {
1898 sprintf(buffer, "#(%s + %s)", left, right);
1899 emitcode("ld", "%s,%s", getPairName(AOP(IC_RESULT(ic))), buffer);
1904 if (isPair(AOP(IC_RIGHT(ic))) && getPairId(AOP(IC_RESULT(ic))) == PAIR_HL) {
1905 /* Fetch into HL then do the add */
1907 fetchPair(PAIR_HL, AOP(IC_LEFT(ic)));
1908 emitcode("add", "hl,%s", getPairName(AOP(IC_RIGHT(ic))));
1913 if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
1914 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1916 emitcode("add","a,%s",
1917 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1919 emitcode("adc","a,%s",
1920 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1922 MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1924 emitcode("add","a,%s",
1925 aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1927 emitcode("adc","a,%s",
1928 aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1930 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1933 /* Some kind of pointer arith. */
1934 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
1935 AOP_SIZE(IC_LEFT(ic)) == 3 &&
1936 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
1939 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
1940 AOP_SIZE(IC_RIGHT(ic)) == 3 &&
1941 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
1946 freeAsmop(IC_LEFT(ic),NULL,ic);
1947 freeAsmop(IC_RIGHT(ic),NULL,ic);
1948 freeAsmop(IC_RESULT(ic),NULL,ic);
1952 /*-----------------------------------------------------------------*/
1953 /* genMinusDec :- does subtraction with deccrement if possible */
1954 /*-----------------------------------------------------------------*/
1955 static bool genMinusDec (iCode *ic)
1957 unsigned int icount ;
1958 unsigned int size = getDataSize(IC_RESULT(ic));
1960 /* will try to generate an increment */
1961 /* if the right side is not a literal we cannot */
1962 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1965 /* if the literal value of the right hand side
1966 is greater than 4 then it is not worth it */
1967 if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
1970 size = getDataSize(IC_RESULT(ic));
1973 /* if increment 16 bits in register */
1974 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1977 symbol *tlbl = newiTempLabel(NULL);
1978 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
1979 emitcode("jp", "np," LABEL_STR ,tlbl->key+100);
1981 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
1985 emitLabel(tlbl->key+100);
1990 /* if decrement 16 bits in register */
1991 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1992 (size > 1) && isPair(AOP(IC_RESULT(ic)))) {
1994 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
1998 /* If result is a pair */
1999 if (isPair(AOP(IC_RESULT(ic)))) {
2000 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
2001 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
2003 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2007 /* if the sizes are greater than 1 then we cannot */
2008 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2009 AOP_SIZE(IC_LEFT(ic)) > 1 )
2012 /* we can if the aops of the left & result match or if they are in
2013 registers and the registers are the same */
2014 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
2016 emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE));
2023 /*-----------------------------------------------------------------*/
2024 /* genMinus - generates code for subtraction */
2025 /*-----------------------------------------------------------------*/
2026 static void genMinus (iCode *ic)
2028 int size, offset = 0;
2029 unsigned long lit = 0L;
2031 aopOp (IC_LEFT(ic),ic,FALSE);
2032 aopOp (IC_RIGHT(ic),ic,FALSE);
2033 aopOp (IC_RESULT(ic),ic,TRUE);
2035 /* special cases :- */
2036 /* if both left & right are in bit space */
2037 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2038 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2043 /* if I can do an decrement instead of subtract then GOOD for ME */
2044 if (genMinusDec (ic) == TRUE)
2047 size = getDataSize(IC_RESULT(ic));
2049 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
2052 lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
2057 /* if literal, add a,#-lit, else normal subb */
2059 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2060 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) {
2062 emitcode("sub","a,%s",
2063 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2065 emitcode("sbc","a,%s",
2066 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2069 /* first add without previous c */
2071 emit2("add a,!immedbyte", (unsigned int)(lit & 0x0FFL));
2073 emit2("adc a,!immedbyte", (unsigned int)((lit >> (offset*8)) & 0x0FFL));
2075 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2078 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2079 AOP_SIZE(IC_LEFT(ic)) == 3 &&
2080 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2084 freeAsmop(IC_LEFT(ic),NULL,ic);
2085 freeAsmop(IC_RIGHT(ic),NULL,ic);
2086 freeAsmop(IC_RESULT(ic),NULL,ic);
2089 /*-----------------------------------------------------------------*/
2090 /* genMult - generates code for multiplication */
2091 /*-----------------------------------------------------------------*/
2092 static void genMult (iCode *ic)
2094 /* Shouldn't occur - all done through function calls */
2098 /*-----------------------------------------------------------------*/
2099 /* genDiv - generates code for division */
2100 /*-----------------------------------------------------------------*/
2101 static void genDiv (iCode *ic)
2103 /* Shouldn't occur - all done through function calls */
2107 /*-----------------------------------------------------------------*/
2108 /* genMod - generates code for division */
2109 /*-----------------------------------------------------------------*/
2110 static void genMod (iCode *ic)
2112 /* Shouldn't occur - all done through function calls */
2116 /*-----------------------------------------------------------------*/
2117 /* genIfxJump :- will create a jump depending on the ifx */
2118 /*-----------------------------------------------------------------*/
2119 static void genIfxJump (iCode *ic, char *jval)
2124 /* if true label then we jump if condition
2126 if ( IC_TRUE(ic) ) {
2128 if (!strcmp(jval, "a")) {
2131 else if (!strcmp(jval, "c")) {
2135 /* The buffer contains the bit on A that we should test */
2140 /* false label is present */
2141 jlbl = IC_FALSE(ic) ;
2142 if (!strcmp(jval, "a")) {
2145 else if (!strcmp(jval, "c")) {
2149 /* The buffer contains the bit on A that we should test */
2153 /* Z80 can do a conditional long jump */
2154 if (!strcmp(jval, "a")) {
2155 emitcode("or", "a,a");
2157 else if (!strcmp(jval, "c")) {
2160 emitcode("bit", "%s,a", jval);
2162 emit2("jp %s,!tlabel", inst, jlbl->key+100);
2164 /* mark the icode as generated */
2168 /** Generic compare for > or <
2170 static void genCmp (operand *left,operand *right,
2171 operand *result, iCode *ifx, int sign)
2173 int size, offset = 0 ;
2174 unsigned long lit = 0L;
2176 /* if left & right are bit variables */
2177 if (AOP_TYPE(left) == AOP_CRY &&
2178 AOP_TYPE(right) == AOP_CRY ) {
2179 /* Cant happen on the Z80 */
2182 /* subtract right from left if at the
2183 end the carry flag is set then we know that
2184 left is greater than right */
2185 size = max(AOP_SIZE(left),AOP_SIZE(right));
2187 /* if unsigned char cmp with lit, just compare */
2189 (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
2190 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2192 emit2("xor a,!immedbyte", 0x80);
2193 emit2("cp %s^!constbyte", aopGet(AOP(right), offset, FALSE), 0x80);
2196 emitcode("cp", "%s", aopGet(AOP(right), offset, FALSE));
2199 if(AOP_TYPE(right) == AOP_LIT) {
2200 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2201 /* optimize if(x < 0) or if(x >= 0) */
2204 /* No sign so it's always false */
2208 /* Just load in the top most bit */
2209 MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE));
2210 if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx) {
2211 genIfxJump (ifx,"7");
2215 emitcode("rlc","a");
2221 /* First setup h and l contaning the top most bytes XORed */
2222 bool fDidXor = FALSE;
2223 if (AOP_TYPE(left) == AOP_LIT){
2224 unsigned long lit = (unsigned long)
2225 floatFromVal(AOP(left)->aopu.aop_lit);
2226 emit2("ld %s,!immedbyte", _fTmp[0],
2227 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2230 emitcode("ld", "a,%s", aopGet(AOP(left), size-1, FALSE));
2231 emit2("xor a,!immedbyte", 0x80);
2232 emitcode("ld", "%s,a", _fTmp[0]);
2235 if (AOP_TYPE(right) == AOP_LIT) {
2236 unsigned long lit = (unsigned long)
2237 floatFromVal(AOP(right)->aopu.aop_lit);
2238 emit2("ld %s,!immedbyte", _fTmp[1],
2239 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2242 emitcode("ld", "a,%s", aopGet(AOP(right), size-1, FALSE));
2243 emit2("xor a,!immedbyte", 0x80);
2244 emitcode("ld", "%s,a", _fTmp[1]);
2254 /* Do a long subtract */
2255 if (!sign || size ) {
2256 MOVA(aopGet(AOP(left),offset,FALSE));
2258 if (sign && size == 0) {
2259 emitcode("ld", "a,%s", _fTmp[0]);
2260 emitcode("sbc", "a,%s", _fTmp[1]);
2263 /* Subtract through, propagating the carry */
2264 emitcode("sbc","a,%s ; 2",aopGet(AOP(right),offset++,FALSE));
2271 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2274 /* if the result is used in the next
2275 ifx conditional branch then generate
2276 code a little differently */
2278 genIfxJump (ifx,"c");
2281 /* leave the result in acc */
2285 /*-----------------------------------------------------------------*/
2286 /* genCmpGt :- greater than comparison */
2287 /*-----------------------------------------------------------------*/
2288 static void genCmpGt (iCode *ic, iCode *ifx)
2290 operand *left, *right, *result;
2291 link *letype , *retype;
2295 right= IC_RIGHT(ic);
2296 result = IC_RESULT(ic);
2298 letype = getSpec(operandType(left));
2299 retype =getSpec(operandType(right));
2300 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2301 /* assign the amsops */
2302 aopOp (left,ic,FALSE);
2303 aopOp (right,ic,FALSE);
2304 aopOp (result,ic,TRUE);
2306 genCmp(right, left, result, ifx, sign);
2308 freeAsmop(left,NULL,ic);
2309 freeAsmop(right,NULL,ic);
2310 freeAsmop(result,NULL,ic);
2313 /*-----------------------------------------------------------------*/
2314 /* genCmpLt - less than comparisons */
2315 /*-----------------------------------------------------------------*/
2316 static void genCmpLt (iCode *ic, iCode *ifx)
2318 operand *left, *right, *result;
2319 link *letype , *retype;
2323 right= IC_RIGHT(ic);
2324 result = IC_RESULT(ic);
2326 letype = getSpec(operandType(left));
2327 retype =getSpec(operandType(right));
2328 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2330 /* assign the amsops */
2331 aopOp (left,ic,FALSE);
2332 aopOp (right,ic,FALSE);
2333 aopOp (result,ic,TRUE);
2335 genCmp(left, right, result, ifx, sign);
2337 freeAsmop(left,NULL,ic);
2338 freeAsmop(right,NULL,ic);
2339 freeAsmop(result,NULL,ic);
2342 /*-----------------------------------------------------------------*/
2343 /* gencjneshort - compare and jump if not equal */
2344 /*-----------------------------------------------------------------*/
2345 static void gencjneshort(operand *left, operand *right, symbol *lbl)
2347 int size = max(AOP_SIZE(left),AOP_SIZE(right));
2349 unsigned long lit = 0L;
2351 /* Swap the left and right if it makes the computation easier */
2352 if (AOP_TYPE(left) == AOP_LIT) {
2358 if(AOP_TYPE(right) == AOP_LIT)
2359 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2361 /* if the right side is a literal then anything goes */
2362 if (AOP_TYPE(right) == AOP_LIT &&
2363 AOP_TYPE(left) != AOP_DIR ) {
2365 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2370 emitcode("or", "a,%s", aopGet(AOP(left), offset, FALSE));
2374 emitcode("or", "a,a");
2376 emit2("jp nz,!tlabel", lbl->key+100);
2380 emitcode("ld", "a,%s ; 2", aopGet(AOP(left),offset,FALSE));
2381 if ((AOP_TYPE(right) == AOP_LIT) && lit == 0)
2382 emitcode("or", "a,a");
2384 emitcode("cp", "a,%s", aopGet(AOP(right),offset,FALSE));
2385 emit2("jp nz,!tlabel", lbl->key+100);
2390 /* if the right side is in a register or in direct space or
2391 if the left is a pointer register & right is not */
2392 else if (AOP_TYPE(right) == AOP_REG ||
2393 AOP_TYPE(right) == AOP_DIR ||
2394 (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT)) {
2396 MOVA(aopGet(AOP(left),offset,FALSE));
2397 if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
2398 ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
2400 emit2("jp nz,!tlabel", lbl->key+100);
2402 emitcode("cp", "%s ; 4", aopGet(AOP(right),offset,FALSE));
2403 emit2("jp nz,!tlabel", lbl->key+100);
2408 /* right is a pointer reg need both a & b */
2409 /* PENDING: is this required? */
2411 MOVA(aopGet(AOP(right),offset,FALSE));
2412 emitcode("cp", "%s ; 5", aopGet(AOP(left), offset, FALSE));
2413 emit2("!shortjp nz,!tlabel", lbl->key+100);
2419 /*-----------------------------------------------------------------*/
2420 /* gencjne - compare and jump if not equal */
2421 /*-----------------------------------------------------------------*/
2422 static void gencjne(operand *left, operand *right, symbol *lbl)
2424 symbol *tlbl = newiTempLabel(NULL);
2426 gencjneshort(left, right, lbl);
2430 emit2("!shortjp !tlabel", tlbl->key+100);
2431 emitLabel(lbl->key+100);
2432 emitcode("xor","a,a");
2433 emitLabel(tlbl->key+100);
2436 /*-----------------------------------------------------------------*/
2437 /* genCmpEq - generates code for equal to */
2438 /*-----------------------------------------------------------------*/
2439 static void genCmpEq (iCode *ic, iCode *ifx)
2441 operand *left, *right, *result;
2443 aopOp((left=IC_LEFT(ic)),ic,FALSE);
2444 aopOp((right=IC_RIGHT(ic)),ic,FALSE);
2445 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2447 /* Swap operands if it makes the operation easier. ie if:
2448 1. Left is a literal.
2450 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
2451 operand *t = IC_RIGHT(ic);
2452 IC_RIGHT(ic) = IC_LEFT(ic);
2456 if (ifx && !AOP_SIZE(result)){
2458 /* if they are both bit variables */
2459 if (AOP_TYPE(left) == AOP_CRY &&
2460 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2463 tlbl = newiTempLabel(NULL);
2464 gencjneshort(left, right, tlbl);
2465 if ( IC_TRUE(ifx) ) {
2466 emit2("jp !tlabel", IC_TRUE(ifx)->key+100);
2467 emitLabel(tlbl->key+100);
2469 /* PENDING: do this better */
2470 symbol *lbl = newiTempLabel(NULL);
2471 emit2("!shortjp !tlabel", lbl->key+100);
2472 emitLabel(tlbl->key+100);
2473 emit2("jp !tlabel", IC_FALSE(ifx)->key+100);
2474 emitLabel(lbl->key+100);
2477 /* mark the icode as generated */
2482 /* if they are both bit variables */
2483 if (AOP_TYPE(left) == AOP_CRY &&
2484 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2487 gencjne(left,right,newiTempLabel(NULL));
2488 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2492 genIfxJump(ifx,"a");
2495 /* if the result is used in an arithmetic operation
2496 then put the result in place */
2497 if (AOP_TYPE(result) != AOP_CRY) {
2500 /* leave the result in acc */
2504 freeAsmop(left,NULL,ic);
2505 freeAsmop(right,NULL,ic);
2506 freeAsmop(result,NULL,ic);
2509 /*-----------------------------------------------------------------*/
2510 /* ifxForOp - returns the icode containing the ifx for operand */
2511 /*-----------------------------------------------------------------*/
2512 static iCode *ifxForOp ( operand *op, iCode *ic )
2514 /* if true symbol then needs to be assigned */
2515 if (IS_TRUE_SYMOP(op))
2518 /* if this has register type condition and
2519 the next instruction is ifx with the same operand
2520 and live to of the operand is upto the ifx only then */
2522 ic->next->op == IFX &&
2523 IC_COND(ic->next)->key == op->key &&
2524 OP_SYMBOL(op)->liveTo <= ic->next->seq )
2530 /*-----------------------------------------------------------------*/
2531 /* genAndOp - for && operation */
2532 /*-----------------------------------------------------------------*/
2533 static void genAndOp (iCode *ic)
2535 operand *left,*right, *result;
2538 /* note here that && operations that are in an if statement are
2539 taken away by backPatchLabels only those used in arthmetic
2540 operations remain */
2541 aopOp((left=IC_LEFT(ic)),ic,FALSE);
2542 aopOp((right=IC_RIGHT(ic)),ic,FALSE);
2543 aopOp((result=IC_RESULT(ic)),ic,FALSE);
2545 /* if both are bit variables */
2546 if (AOP_TYPE(left) == AOP_CRY &&
2547 AOP_TYPE(right) == AOP_CRY ) {
2550 tlbl = newiTempLabel(NULL);
2552 emit2("!shortjp z,!tlabel", tlbl->key+100);
2554 emitLabel(tlbl->key+100);
2558 freeAsmop(left,NULL,ic);
2559 freeAsmop(right,NULL,ic);
2560 freeAsmop(result,NULL,ic);
2563 /*-----------------------------------------------------------------*/
2564 /* genOrOp - for || operation */
2565 /*-----------------------------------------------------------------*/
2566 static void genOrOp (iCode *ic)
2568 operand *left,*right, *result;
2571 /* note here that || operations that are in an
2572 if statement are taken away by backPatchLabels
2573 only those used in arthmetic operations remain */
2574 aopOp((left=IC_LEFT(ic)),ic,FALSE);
2575 aopOp((right=IC_RIGHT(ic)),ic,FALSE);
2576 aopOp((result=IC_RESULT(ic)),ic,FALSE);
2578 /* if both are bit variables */
2579 if (AOP_TYPE(left) == AOP_CRY &&
2580 AOP_TYPE(right) == AOP_CRY ) {
2583 tlbl = newiTempLabel(NULL);
2585 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2587 emitLabel(tlbl->key+100);
2591 freeAsmop(left,NULL,ic);
2592 freeAsmop(right,NULL,ic);
2593 freeAsmop(result,NULL,ic);
2596 /*-----------------------------------------------------------------*/
2597 /* isLiteralBit - test if lit == 2^n */
2598 /*-----------------------------------------------------------------*/
2599 int isLiteralBit(unsigned long lit)
2601 unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
2602 0x100L,0x200L,0x400L,0x800L,
2603 0x1000L,0x2000L,0x4000L,0x8000L,
2604 0x10000L,0x20000L,0x40000L,0x80000L,
2605 0x100000L,0x200000L,0x400000L,0x800000L,
2606 0x1000000L,0x2000000L,0x4000000L,0x8000000L,
2607 0x10000000L,0x20000000L,0x40000000L,0x80000000L};
2610 for(idx = 0; idx < 32; idx++)
2616 /*-----------------------------------------------------------------*/
2617 /* jmpTrueOrFalse - */
2618 /*-----------------------------------------------------------------*/
2619 static void jmpTrueOrFalse (iCode *ic, symbol *tlbl)
2621 // ugly but optimized by peephole
2623 symbol *nlbl = newiTempLabel(NULL);
2624 emit2("jp !tlabel", nlbl->key+100);
2625 emitLabel(tlbl->key+100);
2626 emit2("jp !tlabel", IC_TRUE(ic)->key+100);
2627 emitLabel(nlbl->key+100);
2630 emit2("jp !tlabel", IC_FALSE(ic)->key+100);
2631 emitLabel(tlbl->key+100);
2636 /*-----------------------------------------------------------------*/
2637 /* genAnd - code for and */
2638 /*-----------------------------------------------------------------*/
2639 static void genAnd (iCode *ic, iCode *ifx)
2641 operand *left, *right, *result;
2643 unsigned long lit = 0L;
2646 aopOp((left = IC_LEFT(ic)),ic,FALSE);
2647 aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2648 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2651 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2653 AOP_TYPE(left), AOP_TYPE(right));
2654 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2656 AOP_SIZE(left), AOP_SIZE(right));
2659 /* if left is a literal & right is not then exchange them */
2660 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2661 AOP_NEEDSACC(left)) {
2662 operand *tmp = right ;
2667 /* if result = right then exchange them */
2668 if(sameRegs(AOP(result),AOP(right))){
2669 operand *tmp = right ;
2674 /* if right is bit then exchange them */
2675 if (AOP_TYPE(right) == AOP_CRY &&
2676 AOP_TYPE(left) != AOP_CRY){
2677 operand *tmp = right ;
2681 if(AOP_TYPE(right) == AOP_LIT)
2682 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2684 size = AOP_SIZE(result);
2686 if (AOP_TYPE(left) == AOP_CRY){
2691 // if(val & 0xZZ) - size = 0, ifx != FALSE -
2692 // bit = val & 0xZZ - size = 1, ifx = FALSE -
2693 if((AOP_TYPE(right) == AOP_LIT) &&
2694 (AOP_TYPE(result) == AOP_CRY) &&
2695 (AOP_TYPE(left) != AOP_CRY)) {
2696 int posbit = isLiteralBit(lit);
2700 MOVA(aopGet(AOP(left),posbit>>3,FALSE));
2704 emitcode("mov","c,acc.%d",posbit&0x07);
2709 sprintf(buffer, "%d", posbit&0x07);
2710 genIfxJump(ifx, buffer);
2718 symbol *tlbl = newiTempLabel(NULL);
2719 int sizel = AOP_SIZE(left);
2722 emitcode("setb","c");
2725 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
2726 MOVA( aopGet(AOP(left),offset,FALSE));
2728 if((posbit = isLiteralBit(bytelit)) != 0) {
2730 emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
2733 if(bytelit != 0x0FFL)
2734 emitcode("and","a,%s",
2735 aopGet(AOP(right),offset,FALSE));
2736 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2741 // bit = left & literal
2743 emitcode("clr","c");
2744 emit2("!tlabeldef", tlbl->key+100);
2746 // if(left & literal)
2749 jmpTrueOrFalse(ifx, tlbl);
2757 /* if left is same as result */
2758 if(sameRegs(AOP(result),AOP(left))){
2759 for(;size--; offset++) {
2760 if(AOP_TYPE(right) == AOP_LIT){
2761 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
2765 aopPut(AOP(result),zero,offset);
2767 MOVA(aopGet(AOP(left),offset,FALSE));
2768 emitcode("and","a,%s",
2769 aopGet(AOP(right),offset,FALSE));
2770 emitcode("ld", "%s,a", aopGet(AOP(left),offset,FALSE));
2775 if (AOP_TYPE(left) == AOP_ACC) {
2779 MOVA(aopGet(AOP(left),offset,FALSE));
2780 emitcode("and","a,%s",
2781 aopGet(AOP(right),offset,FALSE));
2782 emitcode("ld", "%s,a", aopGet(AOP(left),offset,FALSE));
2787 // left & result in different registers
2788 if(AOP_TYPE(result) == AOP_CRY){
2791 for(;(size--);offset++) {
2793 // result = left & right
2794 if(AOP_TYPE(right) == AOP_LIT){
2795 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
2797 aopGet(AOP(left),offset,FALSE),
2800 } else if(bytelit == 0){
2801 aopPut(AOP(result),zero,offset);
2805 // faster than result <- left, anl result,right
2806 // and better if result is SFR
2807 if (AOP_TYPE(left) == AOP_ACC)
2808 emitcode("and","a,%s",aopGet(AOP(right),offset,FALSE));
2810 MOVA(aopGet(AOP(right),offset,FALSE));
2811 emitcode("and","a,%s",
2812 aopGet(AOP(left),offset,FALSE));
2814 aopPut(AOP(result),"a",offset);
2821 freeAsmop(left,NULL,ic);
2822 freeAsmop(right,NULL,ic);
2823 freeAsmop(result,NULL,ic);
2826 /*-----------------------------------------------------------------*/
2827 /* genOr - code for or */
2828 /*-----------------------------------------------------------------*/
2829 static void genOr (iCode *ic, iCode *ifx)
2831 operand *left, *right, *result;
2833 unsigned long lit = 0L;
2835 aopOp((left = IC_LEFT(ic)),ic,FALSE);
2836 aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2837 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2840 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2842 AOP_TYPE(left), AOP_TYPE(right));
2843 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2845 AOP_SIZE(left), AOP_SIZE(right));
2848 /* if left is a literal & right is not then exchange them */
2849 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2850 AOP_NEEDSACC(left)) {
2851 operand *tmp = right ;
2856 /* if result = right then exchange them */
2857 if(sameRegs(AOP(result),AOP(right))){
2858 operand *tmp = right ;
2863 /* if right is bit then exchange them */
2864 if (AOP_TYPE(right) == AOP_CRY &&
2865 AOP_TYPE(left) != AOP_CRY){
2866 operand *tmp = right ;
2870 if(AOP_TYPE(right) == AOP_LIT)
2871 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2873 size = AOP_SIZE(result);
2875 if (AOP_TYPE(left) == AOP_CRY){
2880 if((AOP_TYPE(right) == AOP_LIT) &&
2881 (AOP_TYPE(result) == AOP_CRY) &&
2882 (AOP_TYPE(left) != AOP_CRY)){
2887 /* if left is same as result */
2888 if(sameRegs(AOP(result),AOP(left))){
2889 for(;size--; offset++) {
2890 if(AOP_TYPE(right) == AOP_LIT){
2891 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
2894 MOVA(aopGet(AOP(right),offset,FALSE));
2895 emitcode("or","a,%s; 5",
2896 aopGet(AOP(left),offset,FALSE));
2897 aopPut(AOP(result),"a ; 8", offset);
2900 if (AOP_TYPE(left) == AOP_ACC)
2901 emitcode("or","a,%s ; 6",aopGet(AOP(right),offset,FALSE));
2903 MOVA(aopGet(AOP(right),offset,FALSE));
2904 emitcode("or","a,%s ; 7",
2905 aopGet(AOP(left),offset,FALSE));
2906 aopPut(AOP(result),"a ; 8", offset);
2911 // left & result in different registers
2912 if(AOP_TYPE(result) == AOP_CRY){
2914 } else for(;(size--);offset++){
2916 // result = left & right
2917 if(AOP_TYPE(right) == AOP_LIT){
2918 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
2920 aopGet(AOP(left),offset,FALSE),
2925 // faster than result <- left, anl result,right
2926 // and better if result is SFR
2927 if (AOP_TYPE(left) == AOP_ACC)
2928 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
2930 MOVA(aopGet(AOP(right),offset,FALSE));
2931 emitcode("or","a,%s",
2932 aopGet(AOP(left),offset,FALSE));
2934 aopPut(AOP(result),"a",offset);
2935 /* PENDING: something weird is going on here. Add exception. */
2936 if (AOP_TYPE(result) == AOP_ACC)
2942 freeAsmop(left,NULL,ic);
2943 freeAsmop(right,NULL,ic);
2944 freeAsmop(result,NULL,ic);
2947 /*-----------------------------------------------------------------*/
2948 /* genXor - code for xclusive or */
2949 /*-----------------------------------------------------------------*/
2950 static void genXor (iCode *ic, iCode *ifx)
2952 operand *left, *right, *result;
2954 unsigned long lit = 0L;
2956 aopOp((left = IC_LEFT(ic)),ic,FALSE);
2957 aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2958 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2960 /* if left is a literal & right is not then exchange them */
2961 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2962 AOP_NEEDSACC(left)) {
2963 operand *tmp = right ;
2968 /* if result = right then exchange them */
2969 if(sameRegs(AOP(result),AOP(right))){
2970 operand *tmp = right ;
2975 /* if right is bit then exchange them */
2976 if (AOP_TYPE(right) == AOP_CRY &&
2977 AOP_TYPE(left) != AOP_CRY){
2978 operand *tmp = right ;
2982 if(AOP_TYPE(right) == AOP_LIT)
2983 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2985 size = AOP_SIZE(result);
2987 if (AOP_TYPE(left) == AOP_CRY){
2992 if((AOP_TYPE(right) == AOP_LIT) &&
2993 (AOP_TYPE(result) == AOP_CRY) &&
2994 (AOP_TYPE(left) != AOP_CRY)){
2999 /* if left is same as result */
3000 if(sameRegs(AOP(result),AOP(left))){
3001 for(;size--; offset++) {
3002 if(AOP_TYPE(right) == AOP_LIT){
3003 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3006 MOVA(aopGet(AOP(right),offset,FALSE));
3007 emitcode("xor","a,%s",
3008 aopGet(AOP(left),offset,FALSE));
3009 aopPut(AOP(result),"a",0);
3012 if (AOP_TYPE(left) == AOP_ACC)
3013 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3015 MOVA(aopGet(AOP(right),offset,FALSE));
3016 emitcode("xor","a,%s",
3017 aopGet(AOP(left),offset,FALSE));
3018 aopPut(AOP(result),"a",0);
3023 // left & result in different registers
3024 if(AOP_TYPE(result) == AOP_CRY){
3026 } else for(;(size--);offset++){
3028 // result = left & right
3029 if(AOP_TYPE(right) == AOP_LIT){
3030 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3032 aopGet(AOP(left),offset,FALSE),
3037 // faster than result <- left, anl result,right
3038 // and better if result is SFR
3039 if (AOP_TYPE(left) == AOP_ACC)
3040 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3042 MOVA(aopGet(AOP(right),offset,FALSE));
3043 emitcode("xor","a,%s",
3044 aopGet(AOP(left),offset,FALSE));
3045 aopPut(AOP(result),"a",0);
3047 aopPut(AOP(result),"a",offset);
3052 freeAsmop(left,NULL,ic);
3053 freeAsmop(right,NULL,ic);
3054 freeAsmop(result,NULL,ic);
3057 /*-----------------------------------------------------------------*/
3058 /* genInline - write the inline code out */
3059 /*-----------------------------------------------------------------*/
3060 static void genInline (iCode *ic)
3062 char buffer[MAX_INLINEASM];
3066 inLine += (!options.asmpeep);
3067 strcpy(buffer,IC_INLINE(ic));
3069 /* emit each line as a code */
3088 /* emitcode("",buffer); */
3089 inLine -= (!options.asmpeep);
3092 /*-----------------------------------------------------------------*/
3093 /* genRRC - rotate right with carry */
3094 /*-----------------------------------------------------------------*/
3095 static void genRRC (iCode *ic)
3100 /*-----------------------------------------------------------------*/
3101 /* genRLC - generate code for rotate left with carry */
3102 /*-----------------------------------------------------------------*/
3103 static void genRLC (iCode *ic)
3108 /*-----------------------------------------------------------------*/
3109 /* shiftR2Left2Result - shift right two bytes from left to result */
3110 /*-----------------------------------------------------------------*/
3111 static void shiftR2Left2Result (operand *left, int offl,
3112 operand *result, int offr,
3113 int shCount, int sign)
3115 if(sameRegs(AOP(result), AOP(left)) &&
3116 ((offl + MSB16) == offr)){
3119 movLeft2Result(left, offl, result, offr, 0);
3120 movLeft2Result(left, offl+1, result, offr+1, 0);
3127 /* if (AOP(result)->type == AOP_REG) {*/
3130 symbol *tlbl , *tlbl1;
3133 /* Left is already in result - so now do the shift */
3135 emit2("ld a,!immedbyte+1", shCount);
3136 tlbl = newiTempLabel(NULL);
3137 tlbl1 = newiTempLabel(NULL);
3138 emit2("!shortjp !tlabel", tlbl1->key+100);
3139 emitLabel(tlbl->key+100);
3142 emitcode("or", "a,a");
3145 l = aopGet(AOP(result), --offset, FALSE);
3146 emitcode("rr","%s", l);
3149 emitLabel(tlbl1->key+100);
3150 emitcode("dec", "a");
3151 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3156 /*-----------------------------------------------------------------*/
3157 /* shiftL2Left2Result - shift left two bytes from left to result */
3158 /*-----------------------------------------------------------------*/
3159 static void shiftL2Left2Result (operand *left, int offl,
3160 operand *result, int offr, int shCount)
3162 if(sameRegs(AOP(result), AOP(left)) &&
3163 ((offl + MSB16) == offr)){
3166 /* Copy left into result */
3167 movLeft2Result(left, offl, result, offr, 0);
3168 movLeft2Result(left, offl+1, result, offr+1, 0);
3170 /* PENDING: for now just see if it'll work. */
3171 /*if (AOP(result)->type == AOP_REG) { */
3175 symbol *tlbl , *tlbl1;
3178 /* Left is already in result - so now do the shift */
3180 emit2("ld a,!immedbyte+1", shCount);
3181 tlbl = newiTempLabel(NULL);
3182 tlbl1 = newiTempLabel(NULL);
3183 emit2("!shortjp !tlabel", tlbl1->key+100);
3184 emitLabel(tlbl->key+100);
3187 emitcode("or", "a,a");
3189 l = aopGet(AOP(result),offset++,FALSE);
3190 emitcode("rl","%s", l);
3193 emitLabel(tlbl1->key+100);
3194 emitcode("dec", "a");
3195 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3200 /*-----------------------------------------------------------------*/
3201 /* AccRol - rotate left accumulator by known count */
3202 /*-----------------------------------------------------------------*/
3203 static void AccRol (int shCount)
3205 shCount &= 0x0007; // shCount : 0..7
3242 /*-----------------------------------------------------------------*/
3243 /* AccLsh - left shift accumulator by known count */
3244 /*-----------------------------------------------------------------*/
3245 static void AccLsh (int shCount)
3249 emitcode("add","a,a");
3252 emitcode("add","a,a");
3253 emitcode("add","a,a");
3255 /* rotate left accumulator */
3257 /* and kill the lower order bits */
3258 emit2("and a,!immedbyte", SLMask[shCount]);
3263 /*-----------------------------------------------------------------*/
3264 /* shiftL1Left2Result - shift left one byte from left to result */
3265 /*-----------------------------------------------------------------*/
3266 static void shiftL1Left2Result (operand *left, int offl,
3267 operand *result, int offr, int shCount)
3270 l = aopGet(AOP(left),offl,FALSE);
3272 /* shift left accumulator */
3274 aopPut(AOP(result),"a",offr);
3278 /*-----------------------------------------------------------------*/
3279 /* genlshTwo - left shift two bytes by known amount != 0 */
3280 /*-----------------------------------------------------------------*/
3281 static void genlshTwo (operand *result,operand *left, int shCount)
3283 int size = AOP_SIZE(result);
3287 /* if shCount >= 8 */
3293 movLeft2Result(left, LSB, result, MSB16, 0);
3294 aopPut(AOP(result),zero, 0);
3295 shiftL1Left2Result(left, MSB16, result, MSB16, shCount-8);
3298 movLeft2Result(left, LSB, result, MSB16, 0);
3299 aopPut(AOP(result),zero, 0);
3302 aopPut(AOP(result),zero,LSB);
3304 /* 1 <= shCount <= 7 */
3310 shiftL2Left2Result(left, LSB, result, LSB, shCount);
3315 /*-----------------------------------------------------------------*/
3316 /* genlshOne - left shift a one byte quantity by known count */
3317 /*-----------------------------------------------------------------*/
3318 static void genlshOne (operand *result, operand *left, int shCount)
3320 shiftL1Left2Result(left, LSB, result, LSB, shCount);
3323 /*-----------------------------------------------------------------*/
3324 /* genLeftShiftLiteral - left shifting by known count */
3325 /*-----------------------------------------------------------------*/
3326 static void genLeftShiftLiteral (operand *left,
3331 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3334 freeAsmop(right,NULL,ic);
3336 aopOp(left,ic,FALSE);
3337 aopOp(result,ic,FALSE);
3339 size = getSize(operandType(result));
3342 emitcode("; shift left ","result %d, left %d",size,
3346 /* I suppose that the left size >= result size */
3351 else if(shCount >= (size * 8))
3353 aopPut(AOP(result),zero,size);
3357 genlshOne (result,left,shCount);
3360 genlshTwo (result,left,shCount);
3369 freeAsmop(left,NULL,ic);
3370 freeAsmop(result,NULL,ic);
3373 /*-----------------------------------------------------------------*/
3374 /* genLeftShift - generates code for left shifting */
3375 /*-----------------------------------------------------------------*/
3376 static void genLeftShift (iCode *ic)
3380 symbol *tlbl , *tlbl1;
3381 operand *left,*right, *result;
3383 right = IC_RIGHT(ic);
3385 result = IC_RESULT(ic);
3387 aopOp(right,ic,FALSE);
3389 /* if the shift count is known then do it
3390 as efficiently as possible */
3391 if (AOP_TYPE(right) == AOP_LIT) {
3392 genLeftShiftLiteral (left,right,result,ic);
3396 /* shift count is unknown then we have to form a loop get the loop
3397 count in B : Note: we take only the lower order byte since
3398 shifting more that 32 bits make no sense anyway, ( the largest
3399 size of an object can be only 32 bits ) */
3400 emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE));
3401 emitcode("inc","a");
3402 freeAsmop (right,NULL,ic);
3403 aopOp(left,ic,FALSE);
3404 aopOp(result,ic,FALSE);
3406 /* now move the left to the result if they are not the
3409 if (!sameRegs(AOP(left),AOP(result))) {
3411 size = AOP_SIZE(result);
3414 l = aopGet(AOP(left),offset,FALSE);
3415 aopPut(AOP(result),l,offset);
3420 size = AOP_SIZE(result);
3423 l = aopGet(AOP(left),offset,FALSE);
3424 aopPut(AOP(result),l,offset);
3430 tlbl = newiTempLabel(NULL);
3431 size = AOP_SIZE(result);
3433 tlbl1 = newiTempLabel(NULL);
3435 emit2("!shortjp !tlabel", tlbl1->key+100);
3436 emitLabel(tlbl->key+100);
3437 l = aopGet(AOP(result),offset,FALSE);
3438 emitcode("or", "a,a");
3440 l = aopGet(AOP(result),offset++,FALSE);
3441 emitcode("rl","%s", l);
3443 emitLabel(tlbl1->key+100);
3444 emitcode("dec", "a");
3445 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3447 freeAsmop(left,NULL,ic);
3448 freeAsmop(result,NULL,ic);
3451 /*-----------------------------------------------------------------*/
3452 /* genlshTwo - left shift two bytes by known amount != 0 */
3453 /*-----------------------------------------------------------------*/
3454 static void genrshOne (operand *result,operand *left, int shCount)
3457 int size = AOP_SIZE(result);
3463 l = aopGet(AOP(left),0,FALSE);
3464 if (AOP(result)->type == AOP_REG) {
3465 aopPut(AOP(result), l, 0);
3466 l = aopGet(AOP(result), 0, FALSE);
3468 emitcode("srl", "%s", l);
3473 emitcode("srl", "a");
3475 aopPut(AOP(result),"a",0);
3479 /*-----------------------------------------------------------------*/
3480 /* AccRsh - right shift accumulator by known count */
3481 /*-----------------------------------------------------------------*/
3482 static void AccRsh (int shCount)
3489 /* rotate right accumulator */
3490 AccRol(8 - shCount);
3491 /* and kill the higher order bits */
3492 emit2("and a,!immedbyte", SRMask[shCount]);
3497 /*-----------------------------------------------------------------*/
3498 /* shiftR1Left2Result - shift right one byte from left to result */
3499 /*-----------------------------------------------------------------*/
3500 static void shiftR1Left2Result (operand *left, int offl,
3501 operand *result, int offr,
3502 int shCount, int sign)
3504 MOVA(aopGet(AOP(left),offl,FALSE));
3511 aopPut(AOP(result),"a",offr);
3514 /*-----------------------------------------------------------------*/
3515 /* genrshTwo - right shift two bytes by known amount != 0 */
3516 /*-----------------------------------------------------------------*/
3517 static void genrshTwo (operand *result,operand *left,
3518 int shCount, int sign)
3520 /* if shCount >= 8 */
3525 shiftR1Left2Result(left, MSB16, result, LSB,
3529 movLeft2Result(left, MSB16, result, LSB, sign);
3530 aopPut(AOP(result),zero,1);
3533 /* 1 <= shCount <= 7 */
3535 shiftR2Left2Result(left, LSB, result, LSB, shCount, sign);
3539 /*-----------------------------------------------------------------*/
3540 /* genRightShiftLiteral - left shifting by known count */
3541 /*-----------------------------------------------------------------*/
3542 static void genRightShiftLiteral (operand *left,
3547 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3550 freeAsmop(right,NULL,ic);
3552 aopOp(left,ic,FALSE);
3553 aopOp(result,ic,FALSE);
3555 size = getSize(operandType(result));
3557 emitcode("; shift right ","result %d, left %d",size,
3560 /* I suppose that the left size >= result size */
3565 else if(shCount >= (size * 8))
3567 aopPut(AOP(result),zero,size);
3571 genrshOne(result, left, shCount);
3574 /* PENDING: sign support */
3575 genrshTwo(result, left, shCount, FALSE);
3584 freeAsmop(left,NULL,ic);
3585 freeAsmop(result,NULL,ic);
3588 /*-----------------------------------------------------------------*/
3589 /* genRightShift - generate code for right shifting */
3590 /*-----------------------------------------------------------------*/
3591 static void genRightShift (iCode *ic)
3593 operand *right, *left, *result;
3595 int size, offset, first = 1;
3599 symbol *tlbl, *tlbl1 ;
3601 /* if signed then we do it the hard way preserve the
3602 sign bit moving it inwards */
3603 retype = getSpec(operandType(IC_RESULT(ic)));
3605 is_signed = !SPEC_USIGN(retype);
3607 /* signed & unsigned types are treated the same : i.e. the
3608 signed is NOT propagated inwards : quoting from the
3609 ANSI - standard : "for E1 >> E2, is equivalent to division
3610 by 2**E2 if unsigned or if it has a non-negative value,
3611 otherwise the result is implementation defined ", MY definition
3612 is that the sign does not get propagated */
3614 right = IC_RIGHT(ic);
3616 result = IC_RESULT(ic);
3618 aopOp(right,ic,FALSE);
3620 /* if the shift count is known then do it
3621 as efficiently as possible */
3622 if (AOP_TYPE(right) == AOP_LIT) {
3623 genRightShiftLiteral(left,right,result,ic);
3627 aopOp(left,ic,FALSE);
3628 aopOp(result,ic,FALSE);
3630 /* now move the left to the result if they are not the
3632 if (!sameRegs(AOP(left),AOP(result)) &&
3633 AOP_SIZE(result) > 1) {
3635 size = AOP_SIZE(result);
3638 l = aopGet(AOP(left),offset,FALSE);
3639 aopPut(AOP(result),l,offset);
3644 emitcode("ld", "a,%s",aopGet(AOP(right),0,FALSE));
3645 emitcode("inc","a");
3646 freeAsmop (right, NULL, ic);
3648 tlbl = newiTempLabel(NULL);
3649 tlbl1= newiTempLabel(NULL);
3650 size = AOP_SIZE(result);
3653 emit2("!shortjp !tlabel", tlbl1->key+100);
3654 emitLabel(tlbl->key+100);
3656 l = aopGet(AOP(result),offset--,FALSE);
3659 emitcode("sra", "%s", l);
3661 emitcode("srl", "%s", l);
3665 emitcode("rr", "%s", l);
3667 emitLabel(tlbl1->key+100);
3668 emitcode("dec", "a");
3669 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3671 freeAsmop(left,NULL,ic);
3672 freeAsmop(result,NULL,ic);
3675 /*-----------------------------------------------------------------*/
3676 /* genGenPointerGet - gget value from generic pointer space */
3677 /*-----------------------------------------------------------------*/
3678 static void genGenPointerGet (operand *left,
3679 operand *result, iCode *ic)
3682 link *retype = getSpec(operandType(result));
3688 aopOp(left,ic,FALSE);
3689 aopOp(result,ic,FALSE);
3691 if (isPair(AOP(left)) && AOP_SIZE(result)==1) {
3693 if (isPtrPair(AOP(left)))
3695 tsprintf(buffer, "!*pair", getPairName(AOP(left)));
3696 aopPut(AOP(result), buffer, 0);
3699 emit2("ld a,!*pair", getPairName(AOP(left)));
3700 aopPut(AOP(result),"a", 0);
3702 freeAsmop(left,NULL,ic);
3706 /* For now we always load into IY */
3707 /* if this is remateriazable */
3708 fetchPair(pair, AOP(left));
3710 /* so iy now contains the address */
3711 freeAsmop(left,NULL,ic);
3713 /* if bit then unpack */
3714 if (IS_BITVAR(retype)) {
3718 size = AOP_SIZE(result);
3722 /* PENDING: make this better */
3723 if (!IS_GB && AOP(result)->type == AOP_REG) {
3724 aopPut(AOP(result), "!*hl", offset++);
3727 emit2("ld a,!*pair", _pairs[pair].name);
3728 aopPut(AOP(result),"a",offset++);
3731 emit2("inc %s", _pairs[pair].name);
3737 freeAsmop(result,NULL,ic);
3740 /*-----------------------------------------------------------------*/
3741 /* genPointerGet - generate code for pointer get */
3742 /*-----------------------------------------------------------------*/
3743 static void genPointerGet (iCode *ic)
3745 operand *left, *result ;
3749 result = IC_RESULT(ic) ;
3751 /* depending on the type of pointer we need to
3752 move it to the correct pointer register */
3753 type = operandType(left);
3754 etype = getSpec(type);
3756 genGenPointerGet (left,result,ic);
3759 bool isRegOrLit(asmop *aop)
3761 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
3766 /*-----------------------------------------------------------------*/
3767 /* genGenPointerSet - stores the value into a pointer location */
3768 /*-----------------------------------------------------------------*/
3769 static void genGenPointerSet (operand *right,
3770 operand *result, iCode *ic)
3773 link *retype = getSpec(operandType(right));
3774 PAIR_ID pairId = PAIR_HL;
3776 aopOp(result,ic,FALSE);
3777 aopOp(right,ic,FALSE);
3782 /* Handle the exceptions first */
3783 if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
3785 char *l = aopGet(AOP(right), 0, FALSE);
3786 const char *pair = getPairName(AOP(result));
3787 if (canAssignToPtr(l) && isPtr(pair)) {
3788 emit2("ld !*pair,%s", pair, l);
3792 emit2("ld !*pair,a", pair);
3797 /* if the operand is already in dptr
3798 then we do nothing else we move the value to dptr */
3799 if (AOP_TYPE(result) != AOP_STR) {
3800 fetchPair(pairId, AOP(result));
3802 /* so hl know contains the address */
3803 freeAsmop(result,NULL,ic);
3805 /* if bit then unpack */
3806 if (IS_BITVAR(retype)) {
3810 size = AOP_SIZE(right);
3814 char *l = aopGet(AOP(right),offset,FALSE);
3815 if (isRegOrLit(AOP(right)) && !IS_GB) {
3816 emit2("ld !*pair,%s", _pairs[pairId].name, l);
3820 emit2("ld !*pair,a", _pairs[pairId].name);
3823 emitcode("inc", _pairs[pairId].name);
3829 freeAsmop(right,NULL,ic);
3832 /*-----------------------------------------------------------------*/
3833 /* genPointerSet - stores the value into a pointer location */
3834 /*-----------------------------------------------------------------*/
3835 static void genPointerSet (iCode *ic)
3837 operand *right, *result ;
3840 right = IC_RIGHT(ic);
3841 result = IC_RESULT(ic) ;
3843 /* depending on the type of pointer we need to
3844 move it to the correct pointer register */
3845 type = operandType(result);
3846 etype = getSpec(type);
3848 genGenPointerSet (right,result,ic);
3851 /*-----------------------------------------------------------------*/
3852 /* genIfx - generate code for Ifx statement */
3853 /*-----------------------------------------------------------------*/
3854 static void genIfx (iCode *ic, iCode *popIc)
3856 operand *cond = IC_COND(ic);
3859 aopOp(cond,ic,FALSE);
3861 /* get the value into acc */
3862 if (AOP_TYPE(cond) != AOP_CRY)
3866 /* the result is now in the accumulator */
3867 freeAsmop(cond,NULL,ic);
3869 /* if there was something to be popped then do it */
3873 /* if the condition is a bit variable */
3874 if (isbit && IS_ITEMP(cond) &&
3876 genIfxJump(ic,SPIL_LOC(cond)->rname);
3878 if (isbit && !IS_ITEMP(cond))
3879 genIfxJump(ic,OP_SYMBOL(cond)->rname);
3886 /*-----------------------------------------------------------------*/
3887 /* genAddrOf - generates code for address of */
3888 /*-----------------------------------------------------------------*/
3889 static void genAddrOf (iCode *ic)
3891 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
3893 aopOp(IC_RESULT(ic),ic,FALSE);
3895 /* if the operand is on the stack then we
3896 need to get the stack offset of this
3901 emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
3902 emitcode("ld", "d,h");
3903 emitcode("ld", "e,l");
3906 emitcode("ld", "de,#%s", sym->rname);
3908 aopPut(AOP(IC_RESULT(ic)), "e", 0);
3909 aopPut(AOP(IC_RESULT(ic)), "d", 1);
3914 /* if it has an offset then we need to compute it */
3915 emitcode("ld", "hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
3916 emitcode("add", "hl,sp");
3919 emitcode("ld", "hl,#%s", sym->rname);
3921 aopPut(AOP(IC_RESULT(ic)), "l", 0);
3922 aopPut(AOP(IC_RESULT(ic)), "h", 1);
3924 freeAsmop(IC_RESULT(ic),NULL,ic);
3927 /*-----------------------------------------------------------------*/
3928 /* genAssign - generate code for assignment */
3929 /*-----------------------------------------------------------------*/
3930 static void genAssign (iCode *ic)
3932 operand *result, *right;
3934 unsigned long lit = 0L;
3936 result = IC_RESULT(ic);
3937 right = IC_RIGHT(ic) ;
3940 /* Dont bother assigning if they are the same */
3941 if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) {
3942 emitcode("", "; (operands are equal %u)", operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)));
3947 aopOp(right,ic,FALSE);
3948 aopOp(result,ic,TRUE);
3950 /* if they are the same registers */
3951 if (sameRegs(AOP(right),AOP(result))) {
3952 emitcode("", "; (registers are the same)");
3956 /* if the result is a bit */
3957 if (AOP_TYPE(result) == AOP_CRY) {
3962 size = AOP_SIZE(result);
3965 if(AOP_TYPE(right) == AOP_LIT)
3966 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
3967 if (isPair(AOP(result)) && isLitWord(AOP(right))) {
3968 emitcode("ld", "%s,%s", getPairName(AOP(result)), aopGetWord(AOP(right), 0));
3970 else if((size > 1) &&
3971 (AOP_TYPE(result) != AOP_REG) &&
3972 (AOP_TYPE(right) == AOP_LIT) &&
3973 !IS_FLOAT(operandType(right)) &&
3975 bool fXored = FALSE;
3977 /* Work from the top down.
3978 Done this way so that we can use the cached copy of 0
3979 in A for a fast clear */
3981 if((unsigned int)((lit >> (offset*8)) & 0x0FFL)== 0) {
3982 if (!fXored && size>1) {
3983 emitcode("xor", "a,a");
3987 aopPut(AOP(result),"a",offset);
3990 aopPut(AOP(result), zero, offset);
3995 aopGet(AOP(right),offset,FALSE),
4000 else if (size == 2 && requiresHL(AOP(right)) && requiresHL(AOP(result))) {
4001 /* Special case. Load into a and d, then load out. */
4002 MOVA(aopGet(AOP(right), 0, FALSE));
4003 emitcode("ld", "e,%s", aopGet(AOP(right), 1, FALSE));
4004 aopPut(AOP(result), "a", 0);
4005 aopPut(AOP(result), "e", 1);
4008 /* PENDING: do this check better */
4009 if (requiresHL(AOP(right)) && requiresHL(AOP(result))) {
4010 MOVA(aopGet(AOP(right), offset, FALSE));
4011 aopPut(AOP(result), "a", offset);
4015 aopGet(AOP(right),offset,FALSE),
4022 freeAsmop(right,NULL,ic);
4023 freeAsmop(result,NULL,ic);
4026 /*-----------------------------------------------------------------*/
4027 /* genJumpTab - genrates code for jump table */
4028 /*-----------------------------------------------------------------*/
4029 static void genJumpTab (iCode *ic)
4034 aopOp(IC_JTCOND(ic),ic,FALSE);
4035 /* get the condition into accumulator */
4036 l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE);
4038 emitcode("push", "de");
4039 emitcode("ld", "e,%s", l);
4040 emit2("ld d,!zero");
4041 jtab = newiTempLabel(NULL);
4043 emit2("ld hl,!immed!tlabel", jtab->key+100);
4044 emitcode("add", "hl,de");
4045 emitcode("add", "hl,de");
4046 emitcode("add", "hl,de");
4047 freeAsmop(IC_JTCOND(ic),NULL,ic);
4049 emitcode("pop", "de");
4051 emitLabel(jtab->key+100);
4052 /* now generate the jump labels */
4053 for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
4054 jtab = setNextItem(IC_JTLABELS(ic)))
4055 emit2("jp !tlabel", jtab->key+100);
4058 /*-----------------------------------------------------------------*/
4059 /* genCast - gen code for casting */
4060 /*-----------------------------------------------------------------*/
4061 static void genCast (iCode *ic)
4063 operand *result = IC_RESULT(ic);
4064 link *ctype = operandType(IC_LEFT(ic));
4065 operand *right = IC_RIGHT(ic);
4068 /* if they are equivalent then do nothing */
4069 if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
4072 aopOp(right,ic,FALSE) ;
4073 aopOp(result,ic,FALSE);
4075 /* if the result is a bit */
4076 if (AOP_TYPE(result) == AOP_CRY) {
4080 /* if they are the same size : or less */
4081 if (AOP_SIZE(result) <= AOP_SIZE(right)) {
4083 /* if they are in the same place */
4084 if (sameRegs(AOP(right),AOP(result)))
4087 /* if they in different places then copy */
4088 size = AOP_SIZE(result);
4092 aopGet(AOP(right),offset,FALSE),
4099 /* PENDING: should be OK. */
4101 /* if the result is of type pointer */
4102 if (IS_PTR(ctype)) {
4107 /* so we now know that the size of destination is greater
4108 than the size of the source */
4109 /* we move to result for the size of source */
4110 size = AOP_SIZE(right);
4114 aopGet(AOP(right),offset,FALSE),
4119 /* now depending on the sign of the destination */
4120 size = AOP_SIZE(result) - AOP_SIZE(right);
4121 /* Unsigned or not an integral type - right fill with zeros */
4122 if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) {
4124 aopPut(AOP(result),zero,offset++);
4126 /* we need to extend the sign :{ */
4127 char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
4130 emitcode("", "; genCast: sign extend untested.");
4131 emitcode("rla", "");
4132 emitcode("sbc", "a,a");
4134 aopPut(AOP(result),"a",offset++);
4138 freeAsmop(right, NULL, ic);
4139 freeAsmop(result, NULL, ic);
4142 /*-----------------------------------------------------------------*/
4143 /* genReceive - generate code for a receive iCode */
4144 /*-----------------------------------------------------------------*/
4145 static void genReceive (iCode *ic)
4147 if (isOperandInFarSpace(IC_RESULT(ic)) &&
4148 ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
4149 IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
4153 aopOp(IC_RESULT(ic),ic,FALSE);
4155 assignResultValue(IC_RESULT(ic));
4158 freeAsmop(IC_RESULT(ic),NULL,ic);
4161 /*-----------------------------------------------------------------*/
4162 /* genZ80Code - generate code for Z80 based controllers */
4163 /*-----------------------------------------------------------------*/
4164 void genZ80Code (iCode *lic)
4171 _fReturn = _gbz80_return;
4172 _fTmp = _gbz80_return;
4175 _fReturn = _z80_return;
4176 _fTmp = _z80_return;
4178 tsprintf(zero, "!zero");
4180 lineHead = lineCurr = NULL;
4182 /* if debug information required */
4183 if (options.debug && currFunc) {
4184 cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
4186 if (IS_STATIC(currFunc->etype))
4187 emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name);
4189 emitcode("","G$%s$0$0 ==.",currFunc->name);
4192 /* stack pointer name */
4196 for (ic = lic ; ic ; ic = ic->next ) {
4198 if ( cln != ic->lineno ) {
4199 if ( options.debug ) {
4201 emitcode("","C$%s$%d$%d$%d ==.",
4202 ic->filename,ic->lineno,
4203 ic->level,ic->block);
4206 emitcode(";","%s %d",ic->filename,ic->lineno);
4209 /* if the result is marked as
4210 spilt and rematerializable or code for
4211 this has already been generated then
4213 if (resultRemat(ic) || ic->generated )
4216 /* depending on the operation */
4219 emitcode("", "; genNot");
4224 emitcode("", "; genCpl");
4229 emitcode("", "; genUminus");
4234 emitcode("", "; genIpush");
4239 /* IPOP happens only when trying to restore a
4240 spilt live range, if there is an ifx statement
4241 following this pop then the if statement might
4242 be using some of the registers being popped which
4243 would destory the contents of the register so
4244 we need to check for this condition and handle it */
4246 ic->next->op == IFX &&
4247 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) {
4248 emitcode("", "; genIfx");
4249 genIfx (ic->next,ic);
4252 emitcode("", "; genIpop");
4258 emitcode("", "; genCall");
4263 emitcode("", "; genPcall");
4268 emitcode("", "; genFunction");
4273 emitcode("", "; genEndFunction");
4274 genEndFunction (ic);
4278 emitcode("", "; genRet");
4283 emitcode("", "; genLabel");
4288 emitcode("", "; genGoto");
4293 emitcode("", "; genPlus");
4298 emitcode("", "; genMinus");
4303 emitcode("", "; genMult");
4308 emitcode("", "; genDiv");
4313 emitcode("", "; genMod");
4318 emitcode("", "; genCmpGt");
4319 genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));
4323 emitcode("", "; genCmpLt");
4324 genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
4331 /* note these two are xlated by algebraic equivalence
4332 during parsing SDCC.y */
4333 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
4334 "got '>=' or '<=' shouldn't have come here");
4338 emitcode("", "; genCmpEq");
4339 genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
4343 emitcode("", "; genAndOp");
4348 emitcode("", "; genOrOp");
4353 emitcode("", "; genXor");
4354 genXor (ic,ifxForOp(IC_RESULT(ic),ic));
4358 emitcode("", "; genOr");
4359 genOr (ic,ifxForOp(IC_RESULT(ic),ic));
4363 emitcode("", "; genAnd");
4364 genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
4368 emitcode("", "; genInline");
4373 emitcode("", "; genRRC");
4378 emitcode("", "; genRLC");
4383 emitcode("", "; genHBIT");
4387 emitcode("", "; genLeftShift");
4392 emitcode("", "; genRightShift");
4396 case GET_VALUE_AT_ADDRESS:
4397 emitcode("", "; genPointerGet");
4403 if (POINTER_SET(ic)) {
4404 emitcode("", "; genAssign (pointer)");
4408 emitcode("", "; genAssign");
4414 emitcode("", "; genIfx");
4419 emitcode("", "; genAddrOf");
4424 emitcode("", "; genJumpTab");
4429 emitcode("", "; genCast");
4434 emitcode("", "; genReceive");
4439 emitcode("", "; addSet");
4440 addSet(&sendSet,ic);
4445 /* piCode(ic,stdout); */
4451 /* now we are ready to call the
4452 peep hole optimizer */
4453 if (!options.nopeep)
4454 peepHole (&lineHead);
4456 /* now do the actual printing */
4457 printLine (lineHead,codeOutFile);