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, bool requires_a)
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 emitcode("", "; AOP_STK for %s", sym->rname);
348 sym->aop = aop = newAsmop(AOP_STK);
349 aop->size = getSize(sym->type);
350 aop->aopu.aop_stk = sym->stack;
354 /* special case for a function */
355 if (IS_FUNC(sym->type)) {
356 sym->aop = aop = newAsmop(AOP_IMMD);
357 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(sym->rname)+1);
358 strcpy(aop->aopu.aop_immd,sym->rname);
364 /* if it is in direct space */
365 if (IN_REGSP(space) && !requires_a) {
366 sym->aop = aop = newAsmop (AOP_SFR);
367 aop->aopu.aop_dir = sym->rname ;
368 aop->size = getSize(sym->type);
369 emitcode("", "; AOP_SFR for %s", sym->rname);
374 /* only remaining is far space */
375 /* in which case DPTR gets the address */
377 emitcode("", "; AOP_HL for %s", sym->rname);
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 )
509 if (aop1->type == AOP_SFR ||
510 aop2->type == AOP_SFR)
516 if (aop1->type != AOP_REG ||
517 aop2->type != AOP_REG )
520 if (aop1->size != aop2->size)
523 for (i = 0 ; i < aop1->size ; i++ )
524 if (aop1->aopu.aop_reg[i] !=
525 aop2->aopu.aop_reg[i] )
531 /*-----------------------------------------------------------------*/
532 /* aopOp - allocates an asmop for an operand : */
533 /*-----------------------------------------------------------------*/
534 static void aopOp (operand *op, iCode *ic, bool result, bool requires_a)
543 /* if this a literal */
544 if (IS_OP_LITERAL(op)) {
545 op->aop = aop = newAsmop(AOP_LIT);
546 aop->aopu.aop_lit = op->operand.valOperand;
547 aop->size = getSize(operandType(op));
551 /* if already has a asmop then continue */
555 /* if the underlying symbol has a aop */
556 if (IS_SYMOP(op) && OP_SYMBOL(op)->aop) {
557 op->aop = OP_SYMBOL(op)->aop;
561 /* if this is a true symbol */
562 if (IS_TRUE_SYMOP(op)) {
563 op->aop = aopForSym(ic,OP_SYMBOL(op),result, requires_a);
567 /* this is a temporary : this has
573 e) can be a return use only */
577 /* if the type is a conditional */
578 if (sym->regType == REG_CND) {
579 aop = op->aop = sym->aop = newAsmop(AOP_CRY);
584 /* if it is spilt then two situations
586 b) has a spill location */
587 if (sym->isspilt || sym->nRegs == 0) {
588 /* rematerialize it NOW */
590 sym->aop = op->aop = aop =
592 aop->size = getSize(sym->type);
598 aop = op->aop = sym->aop = newAsmop(AOP_ACC);
599 aop->size = getSize(sym->type);
600 for ( i = 0 ; i < 2 ; i++ )
601 aop->aopu.aop_str[i] = accUse[i];
607 aop = op->aop = sym->aop = newAsmop(AOP_STR);
608 aop->size = getSize(sym->type);
609 for ( i = 0 ; i < 4 ; i++ )
610 aop->aopu.aop_str[i] = _fReturn[i];
614 /* else spill location */
615 sym->aop = op->aop = aop =
616 aopForSym(ic,sym->usl.spillLoc,result, requires_a);
617 aop->size = getSize(sym->type);
621 /* must be in a register */
622 sym->aop = op->aop = aop = newAsmop(AOP_REG);
623 aop->size = sym->nRegs;
624 for ( i = 0 ; i < sym->nRegs ;i++)
625 aop->aopu.aop_reg[i] = sym->regs[i];
628 /*-----------------------------------------------------------------*/
629 /* freeAsmop - free up the asmop given to an operand */
630 /*----------------------------------------------------------------*/
631 static void freeAsmop (operand *op, asmop *aaop, iCode *ic)
649 /* all other cases just dealloc */
653 OP_SYMBOL(op)->aop = NULL;
654 /* if the symbol has a spill */
656 SPIL_LOC(op)->aop = NULL;
661 bool isLitWord(asmop *aop)
663 /* if (aop->size != 2)
674 char *aopGetLitWordLong(asmop *aop, int offset, bool with_hash)
680 if (aop->size != 2 && aop->type != AOP_HL)
683 /* depending on type */
688 /* PENDING: for re-target */
690 tsprintf(s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
692 tsprintf(s, "%s + %d", aop->aopu.aop_immd, offset);
693 ALLOC_ATOMIC(rs,strlen(s)+1);
697 value * val = aop->aopu.aop_lit;
698 /* if it is a float then it gets tricky */
699 /* otherwise it is fairly simple */
700 if (!IS_FLOAT(val->type)) {
701 unsigned long v = floatFromVal(val);
705 tsprintf(buffer, "!immedword", v);
707 tsprintf(buffer, "!constword", v);
708 ALLOC_ATOMIC(rs,strlen(buffer)+1);
709 return strcpy (rs,buffer);
714 convertFloat(&f, floatFromVal(val));
716 tsprintf(buffer, "!immedword", f.w[offset/2]);
718 tsprintf(buffer, "!constword", f.w[offset/2]);
719 ALLOC_ATOMIC(rs,strlen(buffer)+1);
720 return strcpy (rs,buffer);
728 char *aopGetWord(asmop *aop, int offset)
730 return aopGetLitWordLong(aop, offset, TRUE);
733 bool isPtr(const char *s)
735 if (!strcmp(s, "hl"))
737 if (!strcmp(s, "ix"))
739 if (!strcmp(s, "iy"))
744 static void adjustPair(const char *pair, int *pold, int new)
748 while (*pold < new) {
749 emitcode("inc", "%s", pair);
752 while (*pold > new) {
753 emitcode("dec", "%s", pair);
758 static void spillPair(PAIR_ID pairId)
760 _G.pairs[pairId].last_type = AOP_INVALID;
761 _G.pairs[pairId].lit = NULL;
764 static void spillCached(void)
770 static bool requiresHL(asmop *aop)
781 static void fetchLitPair(PAIR_ID pairId, asmop *left, int offset)
784 const char *pair = _pairs[pairId].name;
785 l = aopGetLitWordLong(left, offset, FALSE);
789 if (pairId == PAIR_HL || pairId == PAIR_IY) {
790 if (_G.pairs[pairId].last_type == left->type) {
791 if (_G.pairs[pairId].lit && !strcmp(_G.pairs[pairId].lit, l)) {
792 if (pairId == PAIR_HL && abs(_G.pairs[pairId].offset - offset) < 3) {
793 adjustPair(pair, &_G.pairs[pairId].offset, offset);
796 if (pairId == PAIR_IY && abs(offset)<127) {
802 _G.pairs[pairId].last_type = left->type;
803 _G.pairs[pairId].lit = gc_strdup(l);
804 _G.pairs[pairId].offset = offset;
806 /* Both a lit on the right and a true symbol on the left */
807 /* PENDING: for re-target */
810 emit2("ld %s,!hashedstr + %d", pair, l, offset);
813 emit2("ld %s,!hashedstr", pair, l);
816 static void fetchPairLong(PAIR_ID pairId, asmop *aop, int offset)
818 /* if this is remateriazable */
819 if (isLitWord(aop)) {
820 fetchLitPair(pairId, aop, offset);
822 else { /* we need to get it byte by byte */
823 if (pairId == PAIR_HL && IS_GB && requiresHL(aop)) {
824 aopGet(aop, offset, FALSE);
830 emitcode("ld", "%s,%s", _pairs[pairId].l, aopGet(aop, offset, FALSE));
831 emitcode("ld", "%s,%s", _pairs[pairId].h, aopGet(aop, offset+1, FALSE));
833 /* PENDING: check? */
834 if (pairId == PAIR_HL)
839 static void fetchPair(PAIR_ID pairId, asmop *aop)
841 fetchPairLong(pairId, aop, 0);
844 static void fetchHL(asmop *aop)
846 fetchPair(PAIR_HL, aop);
849 static void setupPair(PAIR_ID pairId, asmop *aop, int offset)
851 assert(pairId == PAIR_HL || pairId == PAIR_IY);
856 fetchLitPair(pairId, aop, offset);
857 _G.pairs[pairId].offset = offset;
860 /* Doesnt include _G.stack.pushed */
861 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
862 assert(pairId == PAIR_HL);
863 /* In some cases we can still inc or dec hl */
864 if (_G.pairs[pairId].last_type == AOP_STK && abs(_G.pairs[pairId].offset - abso) < 3) {
865 adjustPair(_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
868 emit2("!ldahlsp", aop->aopu.aop_stk+offset + _G.stack.pushed + _G.stack.offset);
870 _G.pairs[pairId].offset = abso;
876 _G.pairs[pairId].last_type = aop->type;
879 static void emitLabel(int key)
881 emit2("!tlabeldef", key);
885 /*-----------------------------------------------------------------*/
886 /* aopGet - for fetching value of the aop */
887 /*-----------------------------------------------------------------*/
888 static char *aopGet(asmop *aop, int offset, bool bit16)
893 /* offset is greater than size then zero */
894 /* PENDING: this seems a bit screwed in some pointer cases. */
895 if (offset > (aop->size - 1) &&
896 aop->type != AOP_LIT)
899 /* depending on type */
902 /* PENDING: re-target */
904 tsprintf (s,"!immedwords", aop->aopu.aop_immd);
907 wassert(offset == 1);
908 tsprintf(s, "!lsbimmeds", aop->aopu.aop_immd);
911 tsprintf(s, "!msbimmeds", aop->aopu.aop_immd);
912 ALLOC_ATOMIC(rs,strlen(s)+1);
918 emitcode("ld", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
920 ALLOC_ATOMIC(rs,strlen(s)+1);
926 emitcode("ldh", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
928 ALLOC_ATOMIC(rs,strlen(s)+1);
933 return aop->aopu.aop_reg[offset]->name;
937 setupPair(PAIR_HL, aop, offset);
943 setupPair(PAIR_IY, aop, offset);
944 tsprintf(s,"!*iyx", offset);
945 ALLOC_ATOMIC(rs,strlen(s)+1);
951 setupPair(PAIR_HL, aop, offset);
955 tsprintf(s,"!*ixx", aop->aopu.aop_stk+offset);
957 ALLOC_ATOMIC(rs,strlen(s)+1);
971 return aopLiteral (aop->aopu.aop_lit,offset);
975 return aop->aopu.aop_str[offset];
979 wassertl(0, "aopget got unsupported aop->type");
983 bool isRegString(char *s)
985 if (!strcmp(s, "b") ||
996 bool isConstant(const char *s)
998 /* This is a bit of a hack... */
999 return (*s == '#' || *s == '$');
1002 bool canAssignToPtr(char *s)
1011 /*-----------------------------------------------------------------*/
1012 /* aopPut - puts a string for a aop */
1013 /*-----------------------------------------------------------------*/
1014 static void aopPut (asmop *aop, char *s, int offset)
1016 if (aop->size && offset > ( aop->size - 1)) {
1017 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1018 "aopPut got offset > aop->size");
1022 /* will assign value to value */
1023 /* depending on where it is ofcourse */
1024 switch (aop->type) {
1029 emitcode("ld", "a,%s", s);
1030 emitcode("ld", "(%s+%d),a", aop->aopu.aop_dir, offset);
1036 emitcode("ld", "a,%s", s);
1037 emitcode("ldh", "(%s+%d),a", aop->aopu.aop_dir, offset);
1041 emitcode("ld","%s,%s",
1042 aop->aopu.aop_reg[offset]->name,s);
1047 setupPair(PAIR_IY, aop, offset);
1048 if (!canAssignToPtr(s)) {
1049 emit2("ld a,%s", s);
1050 emit2("ld !*iyx,a", offset);
1053 emit2("ld !*iyx,%s", offset, s);
1058 /* PENDING: for re-target */
1059 if (!strcmp(s, "!*hl") || !strcmp(s, "(hl)") || !strcmp(s, "[hl]")) {
1063 setupPair(PAIR_HL, aop, offset);
1065 emit2("ld !*hl,%s", s);
1070 /* PENDING: re-target */
1071 if (!strcmp(s, "!*hl") || !strcmp(s, "(hl)") || !strcmp(s, "[hl]")) {
1075 setupPair(PAIR_HL, aop, offset);
1076 if (!canAssignToPtr(s)) {
1077 emit2("ld a,%s", s);
1081 emit2("ld !*hl,%s ; 3", s);
1084 if (!canAssignToPtr(s)) {
1085 emit2("ld a,%s", s);
1086 emit2("ld !*ixx,a", aop->aopu.aop_stk+offset);
1089 emit2("ld !*ixx,%s", aop->aopu.aop_stk+offset, s);
1094 /* if bit variable */
1095 if (!aop->aopu.aop_dir) {
1099 /* In bit space but not in C - cant happen */
1106 if (strcmp(aop->aopu.aop_str[offset],s)) {
1107 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1113 if (!offset && (strcmp(s,"acc") == 0))
1117 emitcode("", "; Error aopPut AOP_ACC");
1120 if (strcmp(aop->aopu.aop_str[offset],s))
1121 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1126 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1127 "aopPut got unsupported aop->type");
1132 #define AOP(op) op->aop
1133 #define AOP_TYPE(op) AOP(op)->type
1134 #define AOP_SIZE(op) AOP(op)->size
1135 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1137 /*-----------------------------------------------------------------*/
1138 /* getDataSize - get the operand data size */
1139 /*-----------------------------------------------------------------*/
1140 int getDataSize(operand *op)
1143 size = AOP_SIZE(op);
1151 /*-----------------------------------------------------------------*/
1152 /* movLeft2Result - move byte from left to result */
1153 /*-----------------------------------------------------------------*/
1154 static void movLeft2Result (operand *left, int offl,
1155 operand *result, int offr, int sign)
1158 if(!sameRegs(AOP(left),AOP(result)) || (offl != offr)){
1159 l = aopGet(AOP(left),offl,FALSE);
1162 aopPut(AOP(result),l,offr);
1171 /** Put Acc into a register set
1173 void outAcc(operand *result)
1176 size = getDataSize(result);
1178 aopPut(AOP(result),"a",0);
1181 /* unsigned or positive */
1183 aopPut(AOP(result), zero, offset++);
1188 /** Take the value in carry and put it into a register
1190 void outBitC(operand *result)
1192 /* if the result is bit */
1193 if (AOP_TYPE(result) == AOP_CRY) {
1194 emitcode("", "; Note: outBitC form 1");
1195 aopPut(AOP(result),"blah",0);
1198 emit2("ld a,!zero");
1204 /*-----------------------------------------------------------------*/
1205 /* toBoolean - emit code for orl a,operator(sizeop) */
1206 /*-----------------------------------------------------------------*/
1207 void toBoolean(operand *oper)
1209 int size = AOP_SIZE(oper);
1212 emitcode("ld", "a,%s", aopGet(AOP(oper), offset++, FALSE));
1215 emitcode("or","a,%s",aopGet(AOP(oper),offset++,FALSE));
1218 if (AOP(oper)->type != AOP_ACC) {
1220 emitcode("or","a,%s",aopGet(AOP(oper),0,FALSE));
1225 /*-----------------------------------------------------------------*/
1226 /* genNot - generate code for ! operation */
1227 /*-----------------------------------------------------------------*/
1228 static void genNot (iCode *ic)
1230 link *optype = operandType(IC_LEFT(ic));
1232 /* assign asmOps to operand & result */
1233 aopOp (IC_LEFT(ic),ic,FALSE, TRUE);
1234 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1236 /* if in bit space then a special case */
1237 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) {
1241 /* if type float then do float */
1242 if (IS_FLOAT(optype)) {
1246 toBoolean(IC_LEFT(ic));
1251 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1252 emit2("sub a,!one");
1253 outBitC(IC_RESULT(ic));
1255 /* release the aops */
1256 freeAsmop(IC_LEFT(ic),NULL,ic);
1257 freeAsmop(IC_RESULT(ic),NULL,ic);
1260 /*-----------------------------------------------------------------*/
1261 /* genCpl - generate code for complement */
1262 /*-----------------------------------------------------------------*/
1263 static void genCpl (iCode *ic)
1269 /* assign asmOps to operand & result */
1270 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
1271 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1273 /* if both are in bit space then
1275 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1276 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1280 size = AOP_SIZE(IC_RESULT(ic));
1282 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1285 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1288 /* release the aops */
1289 freeAsmop(IC_LEFT(ic),NULL,ic);
1290 freeAsmop(IC_RESULT(ic),NULL,ic);
1293 /*-----------------------------------------------------------------*/
1294 /* genUminus - unary minus code generation */
1295 /*-----------------------------------------------------------------*/
1296 static void genUminus (iCode *ic)
1299 link *optype, *rtype;
1302 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1303 aopOp(IC_RESULT(ic),ic,TRUE, FALSE);
1305 /* if both in bit space then special
1307 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1308 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1313 optype = operandType(IC_LEFT(ic));
1314 rtype = operandType(IC_RESULT(ic));
1316 /* if float then do float stuff */
1317 if (IS_FLOAT(optype)) {
1322 /* otherwise subtract from zero */
1323 size = AOP_SIZE(IC_LEFT(ic));
1327 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1328 emit2("ld a,!zero");
1329 emit2("sbc a,%s",l);
1330 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1333 /* if any remaining bytes in the result */
1334 /* we just need to propagate the sign */
1335 if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic))))) {
1339 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1343 /* release the aops */
1344 freeAsmop(IC_LEFT(ic),NULL,ic);
1345 freeAsmop(IC_RESULT(ic),NULL,ic);
1348 /*-----------------------------------------------------------------*/
1349 /* assignResultValue - */
1350 /*-----------------------------------------------------------------*/
1351 void assignResultValue(operand * oper)
1353 int size = AOP_SIZE(oper);
1357 topInA = requiresHL(AOP(oper));
1363 if (IS_GB && size == 4 && requiresHL(AOP(oper))) {
1364 /* We do it the hard way here. */
1365 emitcode("push", "hl");
1366 _G.stack.pushed += 2;
1367 aopPut(AOP(oper), _fReturn[0], 0);
1368 aopPut(AOP(oper), _fReturn[1], 1);
1369 emitcode("pop", "de");
1370 _G.stack.pushed -= 2;
1371 aopPut(AOP(oper), _fReturn[0], 2);
1372 aopPut(AOP(oper), _fReturn[1], 3);
1376 aopPut(AOP(oper), _fReturn[size], size);
1381 /*-----------------------------------------------------------------*/
1382 /* genIpush - genrate code for pushing this gets a little complex */
1383 /*-----------------------------------------------------------------*/
1384 static void genIpush (iCode *ic)
1386 int size, offset = 0 ;
1390 /* if this is not a parm push : ie. it is spill push
1391 and spill push is always done on the local stack */
1392 if (!ic->parmPush) {
1393 /* and the item is spilt then do nothing */
1394 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1397 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1398 size = AOP_SIZE(IC_LEFT(ic));
1399 /* push it on the stack */
1400 if (isPair(AOP(IC_LEFT(ic)))) {
1401 emitcode("push", getPairName(AOP(IC_LEFT(ic))));
1402 _G.stack.pushed += 2;
1407 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1408 /* Simple for now - load into A and PUSH AF */
1409 emitcode("ld", "a,%s", l);
1410 emitcode("push", "af");
1411 emitcode("inc", "sp");
1418 /* Hmmm... what about saving the currently used registers
1421 /* then do the push */
1422 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1424 size = AOP_SIZE(IC_LEFT(ic));
1426 if (isPair(AOP(IC_LEFT(ic)))) {
1428 emitcode("push", "%s", getPairName(AOP(IC_LEFT(ic))));
1432 fetchHL(AOP(IC_LEFT(ic)));
1433 emitcode("push", "hl");
1435 _G.stack.pushed += 2;
1439 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
1440 emitcode("push", "hl");
1442 _G.stack.pushed += 2;
1443 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 0);
1444 emitcode("push", "hl");
1446 _G.stack.pushed += 2;
1451 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1452 emitcode("ld", "a,%s", l);
1453 emitcode("push", "af");
1454 emitcode("inc", "sp");
1459 freeAsmop(IC_LEFT(ic),NULL,ic);
1462 /*-----------------------------------------------------------------*/
1463 /* genIpop - recover the registers: can happen only for spilling */
1464 /*-----------------------------------------------------------------*/
1465 static void genIpop (iCode *ic)
1470 /* if the temp was not pushed then */
1471 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1474 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1475 size = AOP_SIZE(IC_LEFT(ic));
1477 if (isPair(AOP(IC_LEFT(ic)))) {
1478 emitcode("pop", getPairName(AOP(IC_LEFT(ic))));
1482 emitcode("dec", "sp");
1483 emitcode("pop", "hl");
1485 aopPut(AOP(IC_LEFT(ic)), "l", offset--);
1489 freeAsmop(IC_LEFT(ic),NULL,ic);
1492 /** Emit the code for a call statement
1494 static void emitCall (iCode *ic, bool ispcall)
1496 /* if caller saves & we have not saved then */
1497 if (!ic->regsSaved) {
1501 /* if send set is not empty then assign */
1504 for (sic = setFirstItem(sendSet) ; sic ;
1505 sic = setNextItem(sendSet)) {
1506 int size, offset = 0;
1507 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1508 size = AOP_SIZE(IC_LEFT(sic));
1510 char *l = aopGet(AOP(IC_LEFT(sic)),offset,
1512 if (strcmp(l, _fReturn[offset]))
1513 emitcode("ld","%s,%s",
1518 freeAsmop (IC_LEFT(sic),NULL,sic);
1524 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1526 if (isLitWord(AOP(IC_LEFT(ic)))) {
1527 emitcode("", "; Special case where the pCall is to a constant");
1528 emitcode("call", aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE));
1531 symbol *rlbl = newiTempLabel(NULL);
1533 emit2("ld hl,#!tlabel", (rlbl->key+100));
1534 emitcode("push", "hl");
1535 _G.stack.pushed += 2;
1537 fetchHL(AOP(IC_LEFT(ic)));
1539 emit2("!tlabeldef", (rlbl->key+100));
1540 _G.stack.pushed -= 2;
1542 freeAsmop(IC_LEFT(ic),NULL,ic);
1546 char *name = OP_SYMBOL(IC_LEFT(ic))->rname[0] ?
1547 OP_SYMBOL(IC_LEFT(ic))->rname :
1548 OP_SYMBOL(IC_LEFT(ic))->name;
1549 emitcode("call", "%s", name);
1553 /* if we need assign a result value */
1554 if ((IS_ITEMP(IC_RESULT(ic)) &&
1555 (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
1556 OP_SYMBOL(IC_RESULT(ic))->spildir )) ||
1557 IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
1560 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
1563 assignResultValue(IC_RESULT(ic));
1565 freeAsmop(IC_RESULT(ic),NULL, ic);
1568 /* adjust the stack for parameters if required */
1569 if (IC_LEFT(ic)->parmBytes) {
1570 int i = IC_LEFT(ic)->parmBytes;
1571 _G.stack.pushed -= i;
1573 emit2("!ldaspsp", i);
1578 emitcode("ld", "hl,#%d", i);
1579 emitcode("add", "hl,sp");
1580 emitcode("ld", "sp,hl");
1584 emitcode("pop", "hl");
1588 emitcode("inc", "sp");
1596 /*-----------------------------------------------------------------*/
1597 /* genCall - generates a call statement */
1598 /*-----------------------------------------------------------------*/
1599 static void genCall (iCode *ic)
1601 emitCall(ic, FALSE);
1604 /*-----------------------------------------------------------------*/
1605 /* genPcall - generates a call by pointer statement */
1606 /*-----------------------------------------------------------------*/
1607 static void genPcall (iCode *ic)
1612 /*-----------------------------------------------------------------*/
1613 /* resultRemat - result is rematerializable */
1614 /*-----------------------------------------------------------------*/
1615 static int resultRemat (iCode *ic)
1617 if (SKIP_IC(ic) || ic->op == IFX)
1620 if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
1621 symbol *sym = OP_SYMBOL(IC_RESULT(ic));
1622 if (sym->remat && !POINTER_SET(ic))
1629 /*-----------------------------------------------------------------*/
1630 /* genFunction - generated code for function entry */
1631 /*-----------------------------------------------------------------*/
1632 static void genFunction (iCode *ic)
1634 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1638 /* create the function header */
1639 emit2("!functionheader", sym->name);
1640 /* PENDING: portability. */
1641 emit2("__%s_start:", sym->rname);
1642 emit2("!functionlabeldef", sym->rname);
1644 fetype = getSpec(operandType(IC_LEFT(ic)));
1646 /* if critical function then turn interrupts off */
1647 if (SPEC_CRTCL(fetype))
1650 /* if this is an interrupt service routine then
1651 save acc, b, dpl, dph */
1652 if (IS_ISR(sym->etype)) {
1655 /* PENDING: callee-save etc */
1657 /* adjust the stack for the function */
1658 _G.stack.last = sym->stack;
1661 emit2("!enterx", sym->stack);
1664 _G.stack.offset = sym->stack;
1667 /*-----------------------------------------------------------------*/
1668 /* genEndFunction - generates epilogue for functions */
1669 /*-----------------------------------------------------------------*/
1670 static void genEndFunction (iCode *ic)
1672 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1674 if (IS_ISR(sym->etype)) {
1678 if (SPEC_CRTCL(sym->etype))
1681 /* PENDING: calleeSave */
1683 /* if debug then send end of function */
1684 if (options.debug && currFunc) {
1686 emitcode("","C$%s$%d$%d$%d ==.",
1687 ic->filename,currFunc->lastLine,
1688 ic->level,ic->block);
1689 if (IS_STATIC(currFunc->etype))
1690 emitcode("","XF%s$%s$0$0 ==.",moduleName,currFunc->name);
1692 emitcode("","XG$%s$0$0 ==.",currFunc->name);
1695 if (_G.stack.offset)
1696 emit2("!leavex", _G.stack.offset);
1699 /* PENDING: portability. */
1700 emit2("__%s_end:", sym->rname);
1702 _G.stack.pushed = 0;
1703 _G.stack.offset = 0;
1706 /*-----------------------------------------------------------------*/
1707 /* genRet - generate code for return statement */
1708 /*-----------------------------------------------------------------*/
1709 static void genRet (iCode *ic)
1712 /* Errk. This is a hack until I can figure out how
1713 to cause dehl to spill on a call */
1714 int size,offset = 0;
1716 /* if we have no return value then
1717 just generate the "ret" */
1721 /* we have something to return then
1722 move the return value into place */
1723 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1724 size = AOP_SIZE(IC_LEFT(ic));
1726 if ((size == 2) && ((l = aopGetWord(AOP(IC_LEFT(ic)), 0)))) {
1728 emitcode("ld", "de,%s", l);
1731 emitcode("ld", "hl,%s", l);
1735 if (IS_GB && size == 4 && requiresHL(AOP(IC_LEFT(ic)))) {
1736 fetchPair(PAIR_DE, AOP(IC_LEFT(ic)));
1737 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
1741 l = aopGet(AOP(IC_LEFT(ic)),offset,
1743 if (strcmp(_fReturn[offset],l))
1744 emitcode("ld","%s,%s", _fReturn[offset++],l);
1748 freeAsmop (IC_LEFT(ic),NULL,ic);
1751 /* generate a jump to the return label
1752 if the next is not the return statement */
1753 if (!(ic->next && ic->next->op == LABEL &&
1754 IC_LABEL(ic->next) == returnLabel))
1756 emit2("jp !tlabel", returnLabel->key+100);
1759 /*-----------------------------------------------------------------*/
1760 /* genLabel - generates a label */
1761 /*-----------------------------------------------------------------*/
1762 static void genLabel (iCode *ic)
1764 /* special case never generate */
1765 if (IC_LABEL(ic) == entryLabel)
1768 emitLabel(IC_LABEL(ic)->key+100);
1771 /*-----------------------------------------------------------------*/
1772 /* genGoto - generates a ljmp */
1773 /*-----------------------------------------------------------------*/
1774 static void genGoto (iCode *ic)
1776 emit2("jp !tlabel", IC_LABEL(ic)->key+100);
1779 /*-----------------------------------------------------------------*/
1780 /* genPlusIncr :- does addition with increment if possible */
1781 /*-----------------------------------------------------------------*/
1782 static bool genPlusIncr (iCode *ic)
1784 unsigned int icount ;
1785 unsigned int size = getDataSize(IC_RESULT(ic));
1786 PAIR_ID resultId = getPairId(AOP(IC_RESULT(ic)));
1788 /* will try to generate an increment */
1789 /* if the right side is not a literal
1791 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1794 emitcode("", "; genPlusIncr");
1796 icount = floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
1798 /* If result is a pair */
1799 if (resultId != PAIR_INVALID) {
1800 if (isLitWord(AOP(IC_LEFT(ic)))) {
1801 fetchLitPair(getPairId(AOP(IC_RESULT(ic))), AOP(IC_LEFT(ic)), icount);
1804 if (isPair(AOP(IC_LEFT(ic))) && resultId == PAIR_HL && icount > 2) {
1805 fetchPair(resultId, AOP(IC_RIGHT(ic)));
1806 emitcode("add", "hl,%s", getPairName(AOP(IC_LEFT(ic))));
1812 if (!sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
1815 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
1816 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
1819 emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
1824 /* if the literal value of the right hand side
1825 is greater than 4 then it is not worth it */
1829 /* if increment 16 bits in register */
1830 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1835 symbol *tlbl = NULL;
1836 tlbl = newiTempLabel(NULL);
1838 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)), offset++, FALSE));
1840 emit2("!shortjp nz,!tlabel", tlbl->key+100);
1843 emitLabel(tlbl->key+100);
1847 /* if the sizes are greater than 1 then we cannot */
1848 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
1849 AOP_SIZE(IC_LEFT(ic)) > 1 )
1852 /* we can if the aops of the left & result match or
1853 if they are in registers and the registers are the
1855 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
1857 emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0, FALSE));
1864 /*-----------------------------------------------------------------*/
1865 /* outBitAcc - output a bit in acc */
1866 /*-----------------------------------------------------------------*/
1867 void outBitAcc(operand *result)
1869 symbol *tlbl = newiTempLabel(NULL);
1870 /* if the result is a bit */
1871 if (AOP_TYPE(result) == AOP_CRY){
1875 emit2("!shortjp z,!tlabel", tlbl->key+100);
1877 emitLabel(tlbl->key+100);
1882 /*-----------------------------------------------------------------*/
1883 /* genPlus - generates code for addition */
1884 /*-----------------------------------------------------------------*/
1885 static void genPlus (iCode *ic)
1887 int size, offset = 0;
1889 /* special cases :- */
1891 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
1892 aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
1893 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1895 /* Swap the left and right operands if:
1897 if literal, literal on the right or
1898 if left requires ACC or right is already
1901 if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
1902 (AOP_NEEDSACC(IC_LEFT(ic))) ||
1903 AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
1904 operand *t = IC_RIGHT(ic);
1905 IC_RIGHT(ic) = IC_LEFT(ic);
1909 /* if both left & right are in bit
1911 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1912 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
1917 /* if left in bit space & right literal */
1918 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1919 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
1920 /* Can happen I guess */
1924 /* if I can do an increment instead
1925 of add then GOOD for ME */
1926 if (genPlusIncr (ic) == TRUE)
1929 size = getDataSize(IC_RESULT(ic));
1931 /* Special case when left and right are constant */
1932 if (isPair(AOP(IC_RESULT(ic)))) {
1935 left = aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE);
1936 right = aopGetLitWordLong(AOP(IC_RIGHT(ic)), 0, FALSE);
1937 if (left && right) {
1941 sprintf(buffer, "#(%s + %s)", left, right);
1942 emitcode("ld", "%s,%s", getPairName(AOP(IC_RESULT(ic))), buffer);
1947 if (isPair(AOP(IC_RIGHT(ic))) && getPairId(AOP(IC_RESULT(ic))) == PAIR_HL) {
1948 /* Fetch into HL then do the add */
1950 fetchPair(PAIR_HL, AOP(IC_LEFT(ic)));
1951 emitcode("add", "hl,%s", getPairName(AOP(IC_RIGHT(ic))));
1956 if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
1957 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1959 emitcode("add","a,%s",
1960 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1962 emitcode("adc","a,%s",
1963 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1965 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1967 emitcode("add","a,%s",
1968 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1970 emitcode("adc","a,%s",
1971 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1973 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1976 /* Some kind of pointer arith. */
1977 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
1978 AOP_SIZE(IC_LEFT(ic)) == 3 &&
1979 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
1982 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
1983 AOP_SIZE(IC_RIGHT(ic)) == 3 &&
1984 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
1989 freeAsmop(IC_LEFT(ic),NULL,ic);
1990 freeAsmop(IC_RIGHT(ic),NULL,ic);
1991 freeAsmop(IC_RESULT(ic),NULL,ic);
1995 /*-----------------------------------------------------------------*/
1996 /* genMinusDec :- does subtraction with deccrement if possible */
1997 /*-----------------------------------------------------------------*/
1998 static bool genMinusDec (iCode *ic)
2000 unsigned int icount ;
2001 unsigned int size = getDataSize(IC_RESULT(ic));
2003 /* will try to generate an increment */
2004 /* if the right side is not a literal we cannot */
2005 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
2008 /* if the literal value of the right hand side
2009 is greater than 4 then it is not worth it */
2010 if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
2013 size = getDataSize(IC_RESULT(ic));
2016 /* if increment 16 bits in register */
2017 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2020 symbol *tlbl = newiTempLabel(NULL);
2021 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
2022 emitcode("jp", "np," LABEL_STR ,tlbl->key+100);
2024 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
2028 emitLabel(tlbl->key+100);
2033 /* if decrement 16 bits in register */
2034 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2035 (size > 1) && isPair(AOP(IC_RESULT(ic)))) {
2037 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2041 /* If result is a pair */
2042 if (isPair(AOP(IC_RESULT(ic)))) {
2043 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
2044 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
2046 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2050 /* if the sizes are greater than 1 then we cannot */
2051 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2052 AOP_SIZE(IC_LEFT(ic)) > 1 )
2055 /* we can if the aops of the left & result match or if they are in
2056 registers and the registers are the same */
2057 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
2059 emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE));
2066 /*-----------------------------------------------------------------*/
2067 /* genMinus - generates code for subtraction */
2068 /*-----------------------------------------------------------------*/
2069 static void genMinus (iCode *ic)
2071 int size, offset = 0;
2072 unsigned long lit = 0L;
2074 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
2075 aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
2076 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
2078 /* special cases :- */
2079 /* if both left & right are in bit space */
2080 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2081 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2086 /* if I can do an decrement instead of subtract then GOOD for ME */
2087 if (genMinusDec (ic) == TRUE)
2090 size = getDataSize(IC_RESULT(ic));
2092 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
2095 lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
2100 /* if literal, add a,#-lit, else normal subb */
2102 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2103 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) {
2105 emitcode("sub","a,%s",
2106 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2108 emitcode("sbc","a,%s",
2109 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2112 /* first add without previous c */
2114 emit2("add a,!immedbyte", (unsigned int)(lit & 0x0FFL));
2116 emit2("adc a,!immedbyte", (unsigned int)((lit >> (offset*8)) & 0x0FFL));
2118 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2121 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2122 AOP_SIZE(IC_LEFT(ic)) == 3 &&
2123 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2127 freeAsmop(IC_LEFT(ic),NULL,ic);
2128 freeAsmop(IC_RIGHT(ic),NULL,ic);
2129 freeAsmop(IC_RESULT(ic),NULL,ic);
2132 /*-----------------------------------------------------------------*/
2133 /* genMult - generates code for multiplication */
2134 /*-----------------------------------------------------------------*/
2135 static void genMult (iCode *ic)
2137 /* Shouldn't occur - all done through function calls */
2141 /*-----------------------------------------------------------------*/
2142 /* genDiv - generates code for division */
2143 /*-----------------------------------------------------------------*/
2144 static void genDiv (iCode *ic)
2146 /* Shouldn't occur - all done through function calls */
2150 /*-----------------------------------------------------------------*/
2151 /* genMod - generates code for division */
2152 /*-----------------------------------------------------------------*/
2153 static void genMod (iCode *ic)
2155 /* Shouldn't occur - all done through function calls */
2159 /*-----------------------------------------------------------------*/
2160 /* genIfxJump :- will create a jump depending on the ifx */
2161 /*-----------------------------------------------------------------*/
2162 static void genIfxJump (iCode *ic, char *jval)
2167 /* if true label then we jump if condition
2169 if ( IC_TRUE(ic) ) {
2171 if (!strcmp(jval, "a")) {
2174 else if (!strcmp(jval, "c")) {
2178 /* The buffer contains the bit on A that we should test */
2183 /* false label is present */
2184 jlbl = IC_FALSE(ic) ;
2185 if (!strcmp(jval, "a")) {
2188 else if (!strcmp(jval, "c")) {
2192 /* The buffer contains the bit on A that we should test */
2196 /* Z80 can do a conditional long jump */
2197 if (!strcmp(jval, "a")) {
2198 emitcode("or", "a,a");
2200 else if (!strcmp(jval, "c")) {
2203 emitcode("bit", "%s,a", jval);
2205 emit2("jp %s,!tlabel", inst, jlbl->key+100);
2207 /* mark the icode as generated */
2211 /** Generic compare for > or <
2213 static void genCmp (operand *left,operand *right,
2214 operand *result, iCode *ifx, int sign)
2216 int size, offset = 0 ;
2217 unsigned long lit = 0L;
2219 /* if left & right are bit variables */
2220 if (AOP_TYPE(left) == AOP_CRY &&
2221 AOP_TYPE(right) == AOP_CRY ) {
2222 /* Cant happen on the Z80 */
2225 /* subtract right from left if at the
2226 end the carry flag is set then we know that
2227 left is greater than right */
2228 size = max(AOP_SIZE(left),AOP_SIZE(right));
2230 /* if unsigned char cmp with lit, just compare */
2232 (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
2233 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2235 emit2("xor a,!immedbyte", 0x80);
2236 emit2("cp %s^!constbyte", aopGet(AOP(right), offset, FALSE), 0x80);
2239 emitcode("cp", "%s", aopGet(AOP(right), offset, FALSE));
2242 if(AOP_TYPE(right) == AOP_LIT) {
2243 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2244 /* optimize if(x < 0) or if(x >= 0) */
2247 /* No sign so it's always false */
2251 /* Just load in the top most bit */
2252 MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE));
2253 if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx) {
2254 genIfxJump (ifx,"7");
2258 emitcode("rlc","a");
2264 /* First setup h and l contaning the top most bytes XORed */
2265 bool fDidXor = FALSE;
2266 if (AOP_TYPE(left) == AOP_LIT){
2267 unsigned long lit = (unsigned long)
2268 floatFromVal(AOP(left)->aopu.aop_lit);
2269 emit2("ld %s,!immedbyte", _fTmp[0],
2270 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2273 emitcode("ld", "a,%s", aopGet(AOP(left), size-1, FALSE));
2274 emit2("xor a,!immedbyte", 0x80);
2275 emitcode("ld", "%s,a", _fTmp[0]);
2278 if (AOP_TYPE(right) == AOP_LIT) {
2279 unsigned long lit = (unsigned long)
2280 floatFromVal(AOP(right)->aopu.aop_lit);
2281 emit2("ld %s,!immedbyte", _fTmp[1],
2282 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2285 emitcode("ld", "a,%s", aopGet(AOP(right), size-1, FALSE));
2286 emit2("xor a,!immedbyte", 0x80);
2287 emitcode("ld", "%s,a", _fTmp[1]);
2297 /* Do a long subtract */
2298 if (!sign || size ) {
2299 MOVA(aopGet(AOP(left),offset,FALSE));
2301 if (sign && size == 0) {
2302 emitcode("ld", "a,%s", _fTmp[0]);
2303 emitcode("sbc", "a,%s", _fTmp[1]);
2306 /* Subtract through, propagating the carry */
2307 emitcode("sbc","a,%s ; 2",aopGet(AOP(right),offset++,FALSE));
2314 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2317 /* if the result is used in the next
2318 ifx conditional branch then generate
2319 code a little differently */
2321 genIfxJump (ifx,"c");
2324 /* leave the result in acc */
2328 /*-----------------------------------------------------------------*/
2329 /* genCmpGt :- greater than comparison */
2330 /*-----------------------------------------------------------------*/
2331 static void genCmpGt (iCode *ic, iCode *ifx)
2333 operand *left, *right, *result;
2334 link *letype , *retype;
2338 right= IC_RIGHT(ic);
2339 result = IC_RESULT(ic);
2341 letype = getSpec(operandType(left));
2342 retype =getSpec(operandType(right));
2343 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2344 /* assign the amsops */
2345 aopOp (left,ic,FALSE, FALSE);
2346 aopOp (right,ic,FALSE, FALSE);
2347 aopOp (result,ic,TRUE, FALSE);
2349 genCmp(right, left, result, ifx, sign);
2351 freeAsmop(left,NULL,ic);
2352 freeAsmop(right,NULL,ic);
2353 freeAsmop(result,NULL,ic);
2356 /*-----------------------------------------------------------------*/
2357 /* genCmpLt - less than comparisons */
2358 /*-----------------------------------------------------------------*/
2359 static void genCmpLt (iCode *ic, iCode *ifx)
2361 operand *left, *right, *result;
2362 link *letype , *retype;
2366 right= IC_RIGHT(ic);
2367 result = IC_RESULT(ic);
2369 letype = getSpec(operandType(left));
2370 retype =getSpec(operandType(right));
2371 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2373 /* assign the amsops */
2374 aopOp (left,ic,FALSE, FALSE);
2375 aopOp (right,ic,FALSE, FALSE);
2376 aopOp (result,ic,TRUE, FALSE);
2378 genCmp(left, right, result, ifx, sign);
2380 freeAsmop(left,NULL,ic);
2381 freeAsmop(right,NULL,ic);
2382 freeAsmop(result,NULL,ic);
2385 /*-----------------------------------------------------------------*/
2386 /* gencjneshort - compare and jump if not equal */
2387 /*-----------------------------------------------------------------*/
2388 static void gencjneshort(operand *left, operand *right, symbol *lbl)
2390 int size = max(AOP_SIZE(left),AOP_SIZE(right));
2392 unsigned long lit = 0L;
2394 /* Swap the left and right if it makes the computation easier */
2395 if (AOP_TYPE(left) == AOP_LIT) {
2401 if(AOP_TYPE(right) == AOP_LIT)
2402 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2404 /* if the right side is a literal then anything goes */
2405 if (AOP_TYPE(right) == AOP_LIT &&
2406 AOP_TYPE(left) != AOP_DIR ) {
2408 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2413 emitcode("or", "a,%s", aopGet(AOP(left), offset, FALSE));
2417 emitcode("or", "a,a");
2419 emit2("jp nz,!tlabel", lbl->key+100);
2423 emitcode("ld", "a,%s ; 2", aopGet(AOP(left),offset,FALSE));
2424 if ((AOP_TYPE(right) == AOP_LIT) && lit == 0)
2425 emitcode("or", "a,a");
2427 emitcode("cp", "a,%s", aopGet(AOP(right),offset,FALSE));
2428 emit2("jp nz,!tlabel", lbl->key+100);
2433 /* if the right side is in a register or in direct space or
2434 if the left is a pointer register & right is not */
2435 else if (AOP_TYPE(right) == AOP_REG ||
2436 AOP_TYPE(right) == AOP_DIR ||
2437 (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT)) {
2439 MOVA(aopGet(AOP(left),offset,FALSE));
2440 if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
2441 ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
2443 emit2("jp nz,!tlabel", lbl->key+100);
2445 emitcode("cp", "%s ; 4", aopGet(AOP(right),offset,FALSE));
2446 emit2("jp nz,!tlabel", lbl->key+100);
2451 /* right is a pointer reg need both a & b */
2452 /* PENDING: is this required? */
2454 MOVA(aopGet(AOP(right),offset,FALSE));
2455 emitcode("cp", "%s ; 5", aopGet(AOP(left), offset, FALSE));
2456 emit2("!shortjp nz,!tlabel", lbl->key+100);
2462 /*-----------------------------------------------------------------*/
2463 /* gencjne - compare and jump if not equal */
2464 /*-----------------------------------------------------------------*/
2465 static void gencjne(operand *left, operand *right, symbol *lbl)
2467 symbol *tlbl = newiTempLabel(NULL);
2469 gencjneshort(left, right, lbl);
2473 emit2("!shortjp !tlabel", tlbl->key+100);
2474 emitLabel(lbl->key+100);
2475 emitcode("xor","a,a");
2476 emitLabel(tlbl->key+100);
2479 /*-----------------------------------------------------------------*/
2480 /* genCmpEq - generates code for equal to */
2481 /*-----------------------------------------------------------------*/
2482 static void genCmpEq (iCode *ic, iCode *ifx)
2484 operand *left, *right, *result;
2486 aopOp((left=IC_LEFT(ic)),ic,FALSE, FALSE);
2487 aopOp((right=IC_RIGHT(ic)),ic,FALSE, FALSE);
2488 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2490 /* Swap operands if it makes the operation easier. ie if:
2491 1. Left is a literal.
2493 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
2494 operand *t = IC_RIGHT(ic);
2495 IC_RIGHT(ic) = IC_LEFT(ic);
2499 if (ifx && !AOP_SIZE(result)){
2501 /* if they are both bit variables */
2502 if (AOP_TYPE(left) == AOP_CRY &&
2503 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2506 tlbl = newiTempLabel(NULL);
2507 gencjneshort(left, right, tlbl);
2508 if ( IC_TRUE(ifx) ) {
2509 emit2("jp !tlabel", IC_TRUE(ifx)->key+100);
2510 emitLabel(tlbl->key+100);
2512 /* PENDING: do this better */
2513 symbol *lbl = newiTempLabel(NULL);
2514 emit2("!shortjp !tlabel", lbl->key+100);
2515 emitLabel(tlbl->key+100);
2516 emit2("jp !tlabel", IC_FALSE(ifx)->key+100);
2517 emitLabel(lbl->key+100);
2520 /* mark the icode as generated */
2525 /* if they are both bit variables */
2526 if (AOP_TYPE(left) == AOP_CRY &&
2527 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2530 gencjne(left,right,newiTempLabel(NULL));
2531 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2535 genIfxJump(ifx,"a");
2538 /* if the result is used in an arithmetic operation
2539 then put the result in place */
2540 if (AOP_TYPE(result) != AOP_CRY) {
2543 /* leave the result in acc */
2547 freeAsmop(left,NULL,ic);
2548 freeAsmop(right,NULL,ic);
2549 freeAsmop(result,NULL,ic);
2552 /*-----------------------------------------------------------------*/
2553 /* ifxForOp - returns the icode containing the ifx for operand */
2554 /*-----------------------------------------------------------------*/
2555 static iCode *ifxForOp ( operand *op, iCode *ic )
2557 /* if true symbol then needs to be assigned */
2558 if (IS_TRUE_SYMOP(op))
2561 /* if this has register type condition and
2562 the next instruction is ifx with the same operand
2563 and live to of the operand is upto the ifx only then */
2565 ic->next->op == IFX &&
2566 IC_COND(ic->next)->key == op->key &&
2567 OP_SYMBOL(op)->liveTo <= ic->next->seq )
2573 /*-----------------------------------------------------------------*/
2574 /* genAndOp - for && operation */
2575 /*-----------------------------------------------------------------*/
2576 static void genAndOp (iCode *ic)
2578 operand *left,*right, *result;
2581 /* note here that && operations that are in an if statement are
2582 taken away by backPatchLabels only those used in arthmetic
2583 operations remain */
2584 aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2585 aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2586 aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2588 /* if both are bit variables */
2589 if (AOP_TYPE(left) == AOP_CRY &&
2590 AOP_TYPE(right) == AOP_CRY ) {
2593 tlbl = newiTempLabel(NULL);
2595 emit2("!shortjp z,!tlabel", tlbl->key+100);
2597 emitLabel(tlbl->key+100);
2601 freeAsmop(left,NULL,ic);
2602 freeAsmop(right,NULL,ic);
2603 freeAsmop(result,NULL,ic);
2606 /*-----------------------------------------------------------------*/
2607 /* genOrOp - for || operation */
2608 /*-----------------------------------------------------------------*/
2609 static void genOrOp (iCode *ic)
2611 operand *left,*right, *result;
2614 /* note here that || operations that are in an
2615 if statement are taken away by backPatchLabels
2616 only those used in arthmetic operations remain */
2617 aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2618 aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2619 aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2621 /* if both are bit variables */
2622 if (AOP_TYPE(left) == AOP_CRY &&
2623 AOP_TYPE(right) == AOP_CRY ) {
2626 tlbl = newiTempLabel(NULL);
2628 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2630 emitLabel(tlbl->key+100);
2634 freeAsmop(left,NULL,ic);
2635 freeAsmop(right,NULL,ic);
2636 freeAsmop(result,NULL,ic);
2639 /*-----------------------------------------------------------------*/
2640 /* isLiteralBit - test if lit == 2^n */
2641 /*-----------------------------------------------------------------*/
2642 int isLiteralBit(unsigned long lit)
2644 unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
2645 0x100L,0x200L,0x400L,0x800L,
2646 0x1000L,0x2000L,0x4000L,0x8000L,
2647 0x10000L,0x20000L,0x40000L,0x80000L,
2648 0x100000L,0x200000L,0x400000L,0x800000L,
2649 0x1000000L,0x2000000L,0x4000000L,0x8000000L,
2650 0x10000000L,0x20000000L,0x40000000L,0x80000000L};
2653 for(idx = 0; idx < 32; idx++)
2659 /*-----------------------------------------------------------------*/
2660 /* jmpTrueOrFalse - */
2661 /*-----------------------------------------------------------------*/
2662 static void jmpTrueOrFalse (iCode *ic, symbol *tlbl)
2664 // ugly but optimized by peephole
2666 symbol *nlbl = newiTempLabel(NULL);
2667 emit2("jp !tlabel", nlbl->key+100);
2668 emitLabel(tlbl->key+100);
2669 emit2("jp !tlabel", IC_TRUE(ic)->key+100);
2670 emitLabel(nlbl->key+100);
2673 emit2("jp !tlabel", IC_FALSE(ic)->key+100);
2674 emitLabel(tlbl->key+100);
2679 /*-----------------------------------------------------------------*/
2680 /* genAnd - code for and */
2681 /*-----------------------------------------------------------------*/
2682 static void genAnd (iCode *ic, iCode *ifx)
2684 operand *left, *right, *result;
2686 unsigned long lit = 0L;
2689 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
2690 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
2691 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2694 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2696 AOP_TYPE(left), AOP_TYPE(right));
2697 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2699 AOP_SIZE(left), AOP_SIZE(right));
2702 /* if left is a literal & right is not then exchange them */
2703 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2704 AOP_NEEDSACC(left)) {
2705 operand *tmp = right ;
2710 /* if result = right then exchange them */
2711 if(sameRegs(AOP(result),AOP(right))){
2712 operand *tmp = right ;
2717 /* if right is bit then exchange them */
2718 if (AOP_TYPE(right) == AOP_CRY &&
2719 AOP_TYPE(left) != AOP_CRY){
2720 operand *tmp = right ;
2724 if(AOP_TYPE(right) == AOP_LIT)
2725 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2727 size = AOP_SIZE(result);
2729 if (AOP_TYPE(left) == AOP_CRY){
2734 // if(val & 0xZZ) - size = 0, ifx != FALSE -
2735 // bit = val & 0xZZ - size = 1, ifx = FALSE -
2736 if((AOP_TYPE(right) == AOP_LIT) &&
2737 (AOP_TYPE(result) == AOP_CRY) &&
2738 (AOP_TYPE(left) != AOP_CRY)) {
2739 int posbit = isLiteralBit(lit);
2743 MOVA(aopGet(AOP(left),posbit>>3,FALSE));
2747 emitcode("mov","c,acc.%d",posbit&0x07);
2752 sprintf(buffer, "%d", posbit&0x07);
2753 genIfxJump(ifx, buffer);
2761 symbol *tlbl = newiTempLabel(NULL);
2762 int sizel = AOP_SIZE(left);
2765 emitcode("setb","c");
2768 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
2769 MOVA( aopGet(AOP(left),offset,FALSE));
2771 if((posbit = isLiteralBit(bytelit)) != 0) {
2773 emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
2776 if(bytelit != 0x0FFL)
2777 emitcode("and","a,%s",
2778 aopGet(AOP(right),offset,FALSE));
2779 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2784 // bit = left & literal
2786 emitcode("clr","c");
2787 emit2("!tlabeldef", tlbl->key+100);
2789 // if(left & literal)
2792 jmpTrueOrFalse(ifx, tlbl);
2800 /* if left is same as result */
2801 if(sameRegs(AOP(result),AOP(left))){
2802 for(;size--; offset++) {
2803 if(AOP_TYPE(right) == AOP_LIT){
2804 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
2808 aopPut(AOP(result),zero,offset);
2810 MOVA(aopGet(AOP(left),offset,FALSE));
2811 emitcode("and","a,%s",
2812 aopGet(AOP(right),offset,FALSE));
2813 aopPut(AOP(left), "a", offset);
2818 if (AOP_TYPE(left) == AOP_ACC) {
2822 MOVA(aopGet(AOP(left),offset,FALSE));
2823 emitcode("and","a,%s",
2824 aopGet(AOP(right),offset,FALSE));
2825 aopPut(AOP(left), "a", offset);
2830 // left & result in different registers
2831 if(AOP_TYPE(result) == AOP_CRY){
2834 for(;(size--);offset++) {
2836 // result = left & right
2837 if(AOP_TYPE(right) == AOP_LIT){
2838 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
2840 aopGet(AOP(left),offset,FALSE),
2843 } else if(bytelit == 0){
2844 aopPut(AOP(result),zero,offset);
2848 // faster than result <- left, anl result,right
2849 // and better if result is SFR
2850 if (AOP_TYPE(left) == AOP_ACC)
2851 emitcode("and","a,%s",aopGet(AOP(right),offset,FALSE));
2853 MOVA(aopGet(AOP(left),offset,FALSE));
2854 emitcode("and","a,%s",
2855 aopGet(AOP(right),offset,FALSE));
2857 aopPut(AOP(result),"a",offset);
2864 freeAsmop(left,NULL,ic);
2865 freeAsmop(right,NULL,ic);
2866 freeAsmop(result,NULL,ic);
2869 /*-----------------------------------------------------------------*/
2870 /* genOr - code for or */
2871 /*-----------------------------------------------------------------*/
2872 static void genOr (iCode *ic, iCode *ifx)
2874 operand *left, *right, *result;
2876 unsigned long lit = 0L;
2878 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
2879 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
2880 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2883 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2885 AOP_TYPE(left), AOP_TYPE(right));
2886 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2888 AOP_SIZE(left), AOP_SIZE(right));
2891 /* if left is a literal & right is not then exchange them */
2892 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2893 AOP_NEEDSACC(left)) {
2894 operand *tmp = right ;
2899 /* if result = right then exchange them */
2900 if(sameRegs(AOP(result),AOP(right))){
2901 operand *tmp = right ;
2906 /* if right is bit then exchange them */
2907 if (AOP_TYPE(right) == AOP_CRY &&
2908 AOP_TYPE(left) != AOP_CRY){
2909 operand *tmp = right ;
2913 if(AOP_TYPE(right) == AOP_LIT)
2914 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2916 size = AOP_SIZE(result);
2918 if (AOP_TYPE(left) == AOP_CRY){
2923 if((AOP_TYPE(right) == AOP_LIT) &&
2924 (AOP_TYPE(result) == AOP_CRY) &&
2925 (AOP_TYPE(left) != AOP_CRY)){
2930 /* if left is same as result */
2931 if(sameRegs(AOP(result),AOP(left))){
2932 for(;size--; offset++) {
2933 if(AOP_TYPE(right) == AOP_LIT){
2934 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
2937 MOVA(aopGet(AOP(left),offset,FALSE));
2938 emitcode("or","a,%s",
2939 aopGet(AOP(right),offset,FALSE));
2940 aopPut(AOP(result),"a", offset);
2943 if (AOP_TYPE(left) == AOP_ACC)
2944 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
2946 MOVA(aopGet(AOP(left),offset,FALSE));
2947 emitcode("or","a,%s",
2948 aopGet(AOP(right),offset,FALSE));
2949 aopPut(AOP(result),"a", offset);
2954 // left & result in different registers
2955 if(AOP_TYPE(result) == AOP_CRY){
2957 } else for(;(size--);offset++){
2959 // result = left & right
2960 if(AOP_TYPE(right) == AOP_LIT){
2961 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
2963 aopGet(AOP(left),offset,FALSE),
2968 // faster than result <- left, anl result,right
2969 // and better if result is SFR
2970 if (AOP_TYPE(left) == AOP_ACC)
2971 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
2973 MOVA(aopGet(AOP(left),offset,FALSE));
2974 emitcode("or","a,%s",
2975 aopGet(AOP(right),offset,FALSE));
2977 aopPut(AOP(result),"a",offset);
2978 /* PENDING: something weird is going on here. Add exception. */
2979 if (AOP_TYPE(result) == AOP_ACC)
2985 freeAsmop(left,NULL,ic);
2986 freeAsmop(right,NULL,ic);
2987 freeAsmop(result,NULL,ic);
2990 /*-----------------------------------------------------------------*/
2991 /* genXor - code for xclusive or */
2992 /*-----------------------------------------------------------------*/
2993 static void genXor (iCode *ic, iCode *ifx)
2995 operand *left, *right, *result;
2997 unsigned long lit = 0L;
2999 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3000 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3001 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3003 /* if left is a literal & right is not then exchange them */
3004 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3005 AOP_NEEDSACC(left)) {
3006 operand *tmp = right ;
3011 /* if result = right then exchange them */
3012 if(sameRegs(AOP(result),AOP(right))){
3013 operand *tmp = right ;
3018 /* if right is bit then exchange them */
3019 if (AOP_TYPE(right) == AOP_CRY &&
3020 AOP_TYPE(left) != AOP_CRY){
3021 operand *tmp = right ;
3025 if(AOP_TYPE(right) == AOP_LIT)
3026 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3028 size = AOP_SIZE(result);
3030 if (AOP_TYPE(left) == AOP_CRY){
3035 if((AOP_TYPE(right) == AOP_LIT) &&
3036 (AOP_TYPE(result) == AOP_CRY) &&
3037 (AOP_TYPE(left) != AOP_CRY)){
3042 /* if left is same as result */
3043 if(sameRegs(AOP(result),AOP(left))){
3044 for(;size--; offset++) {
3045 if(AOP_TYPE(right) == AOP_LIT){
3046 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3049 MOVA(aopGet(AOP(right),offset,FALSE));
3050 emitcode("xor","a,%s",
3051 aopGet(AOP(left),offset,FALSE));
3052 aopPut(AOP(result),"a",0);
3055 if (AOP_TYPE(left) == AOP_ACC)
3056 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3058 MOVA(aopGet(AOP(right),offset,FALSE));
3059 emitcode("xor","a,%s",
3060 aopGet(AOP(left),offset,FALSE));
3061 aopPut(AOP(result),"a",0);
3066 // left & result in different registers
3067 if(AOP_TYPE(result) == AOP_CRY){
3069 } else for(;(size--);offset++){
3071 // result = left & right
3072 if(AOP_TYPE(right) == AOP_LIT){
3073 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3075 aopGet(AOP(left),offset,FALSE),
3080 // faster than result <- left, anl result,right
3081 // and better if result is SFR
3082 if (AOP_TYPE(left) == AOP_ACC)
3083 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3085 MOVA(aopGet(AOP(right),offset,FALSE));
3086 emitcode("xor","a,%s",
3087 aopGet(AOP(left),offset,FALSE));
3088 aopPut(AOP(result),"a",0);
3090 aopPut(AOP(result),"a",offset);
3095 freeAsmop(left,NULL,ic);
3096 freeAsmop(right,NULL,ic);
3097 freeAsmop(result,NULL,ic);
3100 /*-----------------------------------------------------------------*/
3101 /* genInline - write the inline code out */
3102 /*-----------------------------------------------------------------*/
3103 static void genInline (iCode *ic)
3105 char buffer[MAX_INLINEASM];
3109 inLine += (!options.asmpeep);
3110 strcpy(buffer,IC_INLINE(ic));
3112 /* emit each line as a code */
3131 /* emitcode("",buffer); */
3132 inLine -= (!options.asmpeep);
3135 /*-----------------------------------------------------------------*/
3136 /* genRRC - rotate right with carry */
3137 /*-----------------------------------------------------------------*/
3138 static void genRRC (iCode *ic)
3143 /*-----------------------------------------------------------------*/
3144 /* genRLC - generate code for rotate left with carry */
3145 /*-----------------------------------------------------------------*/
3146 static void genRLC (iCode *ic)
3151 /*-----------------------------------------------------------------*/
3152 /* shiftR2Left2Result - shift right two bytes from left to result */
3153 /*-----------------------------------------------------------------*/
3154 static void shiftR2Left2Result (operand *left, int offl,
3155 operand *result, int offr,
3156 int shCount, int sign)
3158 if(sameRegs(AOP(result), AOP(left)) &&
3159 ((offl + MSB16) == offr)){
3162 movLeft2Result(left, offl, result, offr, 0);
3163 movLeft2Result(left, offl+1, result, offr+1, 0);
3170 /* if (AOP(result)->type == AOP_REG) {*/
3173 symbol *tlbl , *tlbl1;
3176 /* Left is already in result - so now do the shift */
3178 emit2("ld a,!immedbyte+1", shCount);
3179 tlbl = newiTempLabel(NULL);
3180 tlbl1 = newiTempLabel(NULL);
3181 emit2("!shortjp !tlabel", tlbl1->key+100);
3182 emitLabel(tlbl->key+100);
3185 emitcode("or", "a,a");
3188 l = aopGet(AOP(result), --offset, FALSE);
3189 emitcode("rr","%s", l);
3192 emitLabel(tlbl1->key+100);
3193 emitcode("dec", "a");
3194 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3199 /*-----------------------------------------------------------------*/
3200 /* shiftL2Left2Result - shift left two bytes from left to result */
3201 /*-----------------------------------------------------------------*/
3202 static void shiftL2Left2Result (operand *left, int offl,
3203 operand *result, int offr, int shCount)
3205 if(sameRegs(AOP(result), AOP(left)) &&
3206 ((offl + MSB16) == offr)){
3209 /* Copy left into result */
3210 movLeft2Result(left, offl, result, offr, 0);
3211 movLeft2Result(left, offl+1, result, offr+1, 0);
3213 /* PENDING: for now just see if it'll work. */
3214 /*if (AOP(result)->type == AOP_REG) { */
3218 symbol *tlbl , *tlbl1;
3221 /* Left is already in result - so now do the shift */
3223 emit2("ld a,!immedbyte+1", shCount);
3224 tlbl = newiTempLabel(NULL);
3225 tlbl1 = newiTempLabel(NULL);
3226 emit2("!shortjp !tlabel", tlbl1->key+100);
3227 emitLabel(tlbl->key+100);
3230 emitcode("or", "a,a");
3232 l = aopGet(AOP(result),offset++,FALSE);
3233 emitcode("rl","%s", l);
3236 emitLabel(tlbl1->key+100);
3237 emitcode("dec", "a");
3238 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3243 /*-----------------------------------------------------------------*/
3244 /* AccRol - rotate left accumulator by known count */
3245 /*-----------------------------------------------------------------*/
3246 static void AccRol (int shCount)
3248 shCount &= 0x0007; // shCount : 0..7
3285 /*-----------------------------------------------------------------*/
3286 /* AccLsh - left shift accumulator by known count */
3287 /*-----------------------------------------------------------------*/
3288 static void AccLsh (int shCount)
3292 emitcode("add","a,a");
3295 emitcode("add","a,a");
3296 emitcode("add","a,a");
3298 /* rotate left accumulator */
3300 /* and kill the lower order bits */
3301 emit2("and a,!immedbyte", SLMask[shCount]);
3306 /*-----------------------------------------------------------------*/
3307 /* shiftL1Left2Result - shift left one byte from left to result */
3308 /*-----------------------------------------------------------------*/
3309 static void shiftL1Left2Result (operand *left, int offl,
3310 operand *result, int offr, int shCount)
3313 l = aopGet(AOP(left),offl,FALSE);
3315 /* shift left accumulator */
3317 aopPut(AOP(result),"a",offr);
3321 /*-----------------------------------------------------------------*/
3322 /* genlshTwo - left shift two bytes by known amount != 0 */
3323 /*-----------------------------------------------------------------*/
3324 static void genlshTwo (operand *result,operand *left, int shCount)
3326 int size = AOP_SIZE(result);
3330 /* if shCount >= 8 */
3336 movLeft2Result(left, LSB, result, MSB16, 0);
3337 aopPut(AOP(result),zero, 0);
3338 shiftL1Left2Result(left, MSB16, result, MSB16, shCount-8);
3341 movLeft2Result(left, LSB, result, MSB16, 0);
3342 aopPut(AOP(result),zero, 0);
3345 aopPut(AOP(result),zero,LSB);
3347 /* 1 <= shCount <= 7 */
3353 shiftL2Left2Result(left, LSB, result, LSB, shCount);
3358 /*-----------------------------------------------------------------*/
3359 /* genlshOne - left shift a one byte quantity by known count */
3360 /*-----------------------------------------------------------------*/
3361 static void genlshOne (operand *result, operand *left, int shCount)
3363 shiftL1Left2Result(left, LSB, result, LSB, shCount);
3366 /*-----------------------------------------------------------------*/
3367 /* genLeftShiftLiteral - left shifting by known count */
3368 /*-----------------------------------------------------------------*/
3369 static void genLeftShiftLiteral (operand *left,
3374 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3377 freeAsmop(right,NULL,ic);
3379 aopOp(left,ic,FALSE, FALSE);
3380 aopOp(result,ic,FALSE, FALSE);
3382 size = getSize(operandType(result));
3385 emitcode("; shift left ","result %d, left %d",size,
3389 /* I suppose that the left size >= result size */
3394 else if(shCount >= (size * 8))
3396 aopPut(AOP(result),zero,size);
3400 genlshOne (result,left,shCount);
3403 genlshTwo (result,left,shCount);
3412 freeAsmop(left,NULL,ic);
3413 freeAsmop(result,NULL,ic);
3416 /*-----------------------------------------------------------------*/
3417 /* genLeftShift - generates code for left shifting */
3418 /*-----------------------------------------------------------------*/
3419 static void genLeftShift (iCode *ic)
3423 symbol *tlbl , *tlbl1;
3424 operand *left,*right, *result;
3426 right = IC_RIGHT(ic);
3428 result = IC_RESULT(ic);
3430 aopOp(right,ic,FALSE, FALSE);
3432 /* if the shift count is known then do it
3433 as efficiently as possible */
3434 if (AOP_TYPE(right) == AOP_LIT) {
3435 genLeftShiftLiteral (left,right,result,ic);
3439 /* shift count is unknown then we have to form a loop get the loop
3440 count in B : Note: we take only the lower order byte since
3441 shifting more that 32 bits make no sense anyway, ( the largest
3442 size of an object can be only 32 bits ) */
3443 emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE));
3444 emitcode("inc","a");
3445 freeAsmop (right,NULL,ic);
3446 aopOp(left,ic,FALSE, FALSE);
3447 aopOp(result,ic,FALSE, FALSE);
3449 /* now move the left to the result if they are not the
3452 if (!sameRegs(AOP(left),AOP(result))) {
3454 size = AOP_SIZE(result);
3457 l = aopGet(AOP(left),offset,FALSE);
3458 aopPut(AOP(result),l,offset);
3463 size = AOP_SIZE(result);
3466 l = aopGet(AOP(left),offset,FALSE);
3467 aopPut(AOP(result),l,offset);
3473 tlbl = newiTempLabel(NULL);
3474 size = AOP_SIZE(result);
3476 tlbl1 = newiTempLabel(NULL);
3478 emit2("!shortjp !tlabel", tlbl1->key+100);
3479 emitLabel(tlbl->key+100);
3480 l = aopGet(AOP(result),offset,FALSE);
3481 emitcode("or", "a,a");
3483 l = aopGet(AOP(result),offset++,FALSE);
3484 emitcode("rl","%s", l);
3486 emitLabel(tlbl1->key+100);
3487 emitcode("dec", "a");
3488 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3490 freeAsmop(left,NULL,ic);
3491 freeAsmop(result,NULL,ic);
3494 /*-----------------------------------------------------------------*/
3495 /* genlshTwo - left shift two bytes by known amount != 0 */
3496 /*-----------------------------------------------------------------*/
3497 static void genrshOne (operand *result,operand *left, int shCount)
3500 int size = AOP_SIZE(result);
3506 l = aopGet(AOP(left),0,FALSE);
3507 if (AOP(result)->type == AOP_REG) {
3508 aopPut(AOP(result), l, 0);
3509 l = aopGet(AOP(result), 0, FALSE);
3511 emitcode("srl", "%s", l);
3516 emitcode("srl", "a");
3518 aopPut(AOP(result),"a",0);
3522 /*-----------------------------------------------------------------*/
3523 /* AccRsh - right shift accumulator by known count */
3524 /*-----------------------------------------------------------------*/
3525 static void AccRsh (int shCount)
3532 /* rotate right accumulator */
3533 AccRol(8 - shCount);
3534 /* and kill the higher order bits */
3535 emit2("and a,!immedbyte", SRMask[shCount]);
3540 /*-----------------------------------------------------------------*/
3541 /* shiftR1Left2Result - shift right one byte from left to result */
3542 /*-----------------------------------------------------------------*/
3543 static void shiftR1Left2Result (operand *left, int offl,
3544 operand *result, int offr,
3545 int shCount, int sign)
3547 MOVA(aopGet(AOP(left),offl,FALSE));
3554 aopPut(AOP(result),"a",offr);
3557 /*-----------------------------------------------------------------*/
3558 /* genrshTwo - right shift two bytes by known amount != 0 */
3559 /*-----------------------------------------------------------------*/
3560 static void genrshTwo (operand *result,operand *left,
3561 int shCount, int sign)
3563 /* if shCount >= 8 */
3568 shiftR1Left2Result(left, MSB16, result, LSB,
3572 movLeft2Result(left, MSB16, result, LSB, sign);
3573 aopPut(AOP(result),zero,1);
3576 /* 1 <= shCount <= 7 */
3578 shiftR2Left2Result(left, LSB, result, LSB, shCount, sign);
3582 /*-----------------------------------------------------------------*/
3583 /* genRightShiftLiteral - left shifting by known count */
3584 /*-----------------------------------------------------------------*/
3585 static void genRightShiftLiteral (operand *left,
3590 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3593 freeAsmop(right,NULL,ic);
3595 aopOp(left,ic,FALSE, FALSE);
3596 aopOp(result,ic,FALSE, FALSE);
3598 size = getSize(operandType(result));
3600 emitcode("; shift right ","result %d, left %d",size,
3603 /* I suppose that the left size >= result size */
3608 else if(shCount >= (size * 8))
3610 aopPut(AOP(result),zero,size);
3614 genrshOne(result, left, shCount);
3617 /* PENDING: sign support */
3618 genrshTwo(result, left, shCount, FALSE);
3627 freeAsmop(left,NULL,ic);
3628 freeAsmop(result,NULL,ic);
3631 /*-----------------------------------------------------------------*/
3632 /* genRightShift - generate code for right shifting */
3633 /*-----------------------------------------------------------------*/
3634 static void genRightShift (iCode *ic)
3636 operand *right, *left, *result;
3638 int size, offset, first = 1;
3642 symbol *tlbl, *tlbl1 ;
3644 /* if signed then we do it the hard way preserve the
3645 sign bit moving it inwards */
3646 retype = getSpec(operandType(IC_RESULT(ic)));
3648 is_signed = !SPEC_USIGN(retype);
3650 /* signed & unsigned types are treated the same : i.e. the
3651 signed is NOT propagated inwards : quoting from the
3652 ANSI - standard : "for E1 >> E2, is equivalent to division
3653 by 2**E2 if unsigned or if it has a non-negative value,
3654 otherwise the result is implementation defined ", MY definition
3655 is that the sign does not get propagated */
3657 right = IC_RIGHT(ic);
3659 result = IC_RESULT(ic);
3661 aopOp(right,ic,FALSE, FALSE);
3663 /* if the shift count is known then do it
3664 as efficiently as possible */
3665 if (AOP_TYPE(right) == AOP_LIT) {
3666 genRightShiftLiteral(left,right,result,ic);
3670 aopOp(left,ic,FALSE, FALSE);
3671 aopOp(result,ic,FALSE, FALSE);
3673 /* now move the left to the result if they are not the
3675 if (!sameRegs(AOP(left),AOP(result)) &&
3676 AOP_SIZE(result) > 1) {
3678 size = AOP_SIZE(result);
3681 l = aopGet(AOP(left),offset,FALSE);
3682 aopPut(AOP(result),l,offset);
3687 emitcode("ld", "a,%s",aopGet(AOP(right),0,FALSE));
3688 emitcode("inc","a");
3689 freeAsmop (right, NULL, ic);
3691 tlbl = newiTempLabel(NULL);
3692 tlbl1= newiTempLabel(NULL);
3693 size = AOP_SIZE(result);
3696 emit2("!shortjp !tlabel", tlbl1->key+100);
3697 emitLabel(tlbl->key+100);
3699 l = aopGet(AOP(result),offset--,FALSE);
3702 emitcode("sra", "%s", l);
3704 emitcode("srl", "%s", l);
3708 emitcode("rr", "%s", l);
3710 emitLabel(tlbl1->key+100);
3711 emitcode("dec", "a");
3712 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3714 freeAsmop(left,NULL,ic);
3715 freeAsmop(result,NULL,ic);
3718 /*-----------------------------------------------------------------*/
3719 /* genGenPointerGet - gget value from generic pointer space */
3720 /*-----------------------------------------------------------------*/
3721 static void genGenPointerGet (operand *left,
3722 operand *result, iCode *ic)
3725 link *retype = getSpec(operandType(result));
3731 aopOp(left,ic,FALSE, FALSE);
3732 aopOp(result,ic,FALSE, FALSE);
3734 if (isPair(AOP(left)) && AOP_SIZE(result)==1) {
3736 if (isPtrPair(AOP(left)))
3738 tsprintf(buffer, "!*pair", getPairName(AOP(left)));
3739 aopPut(AOP(result), buffer, 0);
3742 emit2("ld a,!*pair", getPairName(AOP(left)));
3743 aopPut(AOP(result),"a", 0);
3745 freeAsmop(left,NULL,ic);
3749 /* For now we always load into IY */
3750 /* if this is remateriazable */
3751 fetchPair(pair, AOP(left));
3753 /* so iy now contains the address */
3754 freeAsmop(left,NULL,ic);
3756 /* if bit then unpack */
3757 if (IS_BITVAR(retype)) {
3761 size = AOP_SIZE(result);
3765 /* PENDING: make this better */
3766 if (!IS_GB && AOP(result)->type == AOP_REG) {
3767 aopPut(AOP(result), "!*hl", offset++);
3770 emit2("ld a,!*pair", _pairs[pair].name);
3771 aopPut(AOP(result),"a",offset++);
3774 emit2("inc %s", _pairs[pair].name);
3780 freeAsmop(result,NULL,ic);
3783 /*-----------------------------------------------------------------*/
3784 /* genPointerGet - generate code for pointer get */
3785 /*-----------------------------------------------------------------*/
3786 static void genPointerGet (iCode *ic)
3788 operand *left, *result ;
3792 result = IC_RESULT(ic) ;
3794 /* depending on the type of pointer we need to
3795 move it to the correct pointer register */
3796 type = operandType(left);
3797 etype = getSpec(type);
3799 genGenPointerGet (left,result,ic);
3802 bool isRegOrLit(asmop *aop)
3804 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
3809 /*-----------------------------------------------------------------*/
3810 /* genGenPointerSet - stores the value into a pointer location */
3811 /*-----------------------------------------------------------------*/
3812 static void genGenPointerSet (operand *right,
3813 operand *result, iCode *ic)
3816 link *retype = getSpec(operandType(right));
3817 PAIR_ID pairId = PAIR_HL;
3819 aopOp(result,ic,FALSE, FALSE);
3820 aopOp(right,ic,FALSE, FALSE);
3825 /* Handle the exceptions first */
3826 if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
3828 char *l = aopGet(AOP(right), 0, FALSE);
3829 const char *pair = getPairName(AOP(result));
3830 if (canAssignToPtr(l) && isPtr(pair)) {
3831 emit2("ld !*pair,%s", pair, l);
3835 emit2("ld !*pair,a", pair);
3840 /* if the operand is already in dptr
3841 then we do nothing else we move the value to dptr */
3842 if (AOP_TYPE(result) != AOP_STR) {
3843 fetchPair(pairId, AOP(result));
3845 /* so hl know contains the address */
3846 freeAsmop(result,NULL,ic);
3848 /* if bit then unpack */
3849 if (IS_BITVAR(retype)) {
3853 size = AOP_SIZE(right);
3857 char *l = aopGet(AOP(right),offset,FALSE);
3858 if (isRegOrLit(AOP(right)) && !IS_GB) {
3859 emit2("ld !*pair,%s", _pairs[pairId].name, l);
3863 emit2("ld !*pair,a", _pairs[pairId].name);
3866 emitcode("inc", _pairs[pairId].name);
3872 freeAsmop(right,NULL,ic);
3875 /*-----------------------------------------------------------------*/
3876 /* genPointerSet - stores the value into a pointer location */
3877 /*-----------------------------------------------------------------*/
3878 static void genPointerSet (iCode *ic)
3880 operand *right, *result ;
3883 right = IC_RIGHT(ic);
3884 result = IC_RESULT(ic) ;
3886 /* depending on the type of pointer we need to
3887 move it to the correct pointer register */
3888 type = operandType(result);
3889 etype = getSpec(type);
3891 genGenPointerSet (right,result,ic);
3894 /*-----------------------------------------------------------------*/
3895 /* genIfx - generate code for Ifx statement */
3896 /*-----------------------------------------------------------------*/
3897 static void genIfx (iCode *ic, iCode *popIc)
3899 operand *cond = IC_COND(ic);
3902 aopOp(cond,ic,FALSE, TRUE);
3904 /* get the value into acc */
3905 if (AOP_TYPE(cond) != AOP_CRY)
3909 /* the result is now in the accumulator */
3910 freeAsmop(cond,NULL,ic);
3912 /* if there was something to be popped then do it */
3916 /* if the condition is a bit variable */
3917 if (isbit && IS_ITEMP(cond) &&
3919 genIfxJump(ic,SPIL_LOC(cond)->rname);
3921 if (isbit && !IS_ITEMP(cond))
3922 genIfxJump(ic,OP_SYMBOL(cond)->rname);
3929 /*-----------------------------------------------------------------*/
3930 /* genAddrOf - generates code for address of */
3931 /*-----------------------------------------------------------------*/
3932 static void genAddrOf (iCode *ic)
3934 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
3936 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
3938 /* if the operand is on the stack then we
3939 need to get the stack offset of this
3944 emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
3945 emitcode("ld", "d,h");
3946 emitcode("ld", "e,l");
3949 emitcode("ld", "de,#%s", sym->rname);
3951 aopPut(AOP(IC_RESULT(ic)), "e", 0);
3952 aopPut(AOP(IC_RESULT(ic)), "d", 1);
3957 /* if it has an offset then we need to compute it */
3958 emitcode("ld", "hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
3959 emitcode("add", "hl,sp");
3962 emitcode("ld", "hl,#%s", sym->rname);
3964 aopPut(AOP(IC_RESULT(ic)), "l", 0);
3965 aopPut(AOP(IC_RESULT(ic)), "h", 1);
3967 freeAsmop(IC_RESULT(ic),NULL,ic);
3970 /*-----------------------------------------------------------------*/
3971 /* genAssign - generate code for assignment */
3972 /*-----------------------------------------------------------------*/
3973 static void genAssign (iCode *ic)
3975 operand *result, *right;
3977 unsigned long lit = 0L;
3979 result = IC_RESULT(ic);
3980 right = IC_RIGHT(ic) ;
3983 /* Dont bother assigning if they are the same */
3984 if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) {
3985 emitcode("", "; (operands are equal %u)", operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)));
3990 aopOp(right,ic,FALSE, FALSE);
3991 aopOp(result,ic,TRUE, FALSE);
3993 /* if they are the same registers */
3994 if (sameRegs(AOP(right),AOP(result))) {
3995 emitcode("", "; (registers are the same)");
3999 /* if the result is a bit */
4000 if (AOP_TYPE(result) == AOP_CRY) {
4005 size = AOP_SIZE(result);
4008 if(AOP_TYPE(right) == AOP_LIT)
4009 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
4010 if (isPair(AOP(result)) && isLitWord(AOP(right))) {
4011 emitcode("ld", "%s,%s", getPairName(AOP(result)), aopGetWord(AOP(right), 0));
4013 else if((size > 1) &&
4014 (AOP_TYPE(result) != AOP_REG) &&
4015 (AOP_TYPE(right) == AOP_LIT) &&
4016 !IS_FLOAT(operandType(right)) &&
4018 bool fXored = FALSE;
4020 /* Work from the top down.
4021 Done this way so that we can use the cached copy of 0
4022 in A for a fast clear */
4024 if((unsigned int)((lit >> (offset*8)) & 0x0FFL)== 0) {
4025 if (!fXored && size>1) {
4026 emitcode("xor", "a,a");
4030 aopPut(AOP(result),"a",offset);
4033 aopPut(AOP(result), zero, offset);
4038 aopGet(AOP(right),offset,FALSE),
4043 else if (size == 2 && requiresHL(AOP(right)) && requiresHL(AOP(result))) {
4044 /* Special case. Load into a and d, then load out. */
4045 MOVA(aopGet(AOP(right), 0, FALSE));
4046 emitcode("ld", "e,%s", aopGet(AOP(right), 1, FALSE));
4047 aopPut(AOP(result), "a", 0);
4048 aopPut(AOP(result), "e", 1);
4051 /* PENDING: do this check better */
4052 if (requiresHL(AOP(right)) && requiresHL(AOP(result))) {
4053 MOVA(aopGet(AOP(right), offset, FALSE));
4054 aopPut(AOP(result), "a", offset);
4058 aopGet(AOP(right),offset,FALSE),
4065 freeAsmop(right,NULL,ic);
4066 freeAsmop(result,NULL,ic);
4069 /*-----------------------------------------------------------------*/
4070 /* genJumpTab - genrates code for jump table */
4071 /*-----------------------------------------------------------------*/
4072 static void genJumpTab (iCode *ic)
4077 aopOp(IC_JTCOND(ic),ic,FALSE, FALSE);
4078 /* get the condition into accumulator */
4079 l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE);
4081 emitcode("push", "de");
4082 emitcode("ld", "e,%s", l);
4083 emit2("ld d,!zero");
4084 jtab = newiTempLabel(NULL);
4086 emit2("ld hl,!immed!tlabel", jtab->key+100);
4087 emitcode("add", "hl,de");
4088 emitcode("add", "hl,de");
4089 emitcode("add", "hl,de");
4090 freeAsmop(IC_JTCOND(ic),NULL,ic);
4092 emitcode("pop", "de");
4094 emitLabel(jtab->key+100);
4095 /* now generate the jump labels */
4096 for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
4097 jtab = setNextItem(IC_JTLABELS(ic)))
4098 emit2("jp !tlabel", jtab->key+100);
4101 /*-----------------------------------------------------------------*/
4102 /* genCast - gen code for casting */
4103 /*-----------------------------------------------------------------*/
4104 static void genCast (iCode *ic)
4106 operand *result = IC_RESULT(ic);
4107 link *ctype = operandType(IC_LEFT(ic));
4108 operand *right = IC_RIGHT(ic);
4111 /* if they are equivalent then do nothing */
4112 if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
4115 aopOp(right,ic,FALSE, FALSE);
4116 aopOp(result,ic,FALSE, FALSE);
4118 /* if the result is a bit */
4119 if (AOP_TYPE(result) == AOP_CRY) {
4123 /* if they are the same size : or less */
4124 if (AOP_SIZE(result) <= AOP_SIZE(right)) {
4126 /* if they are in the same place */
4127 if (sameRegs(AOP(right),AOP(result)))
4130 /* if they in different places then copy */
4131 size = AOP_SIZE(result);
4135 aopGet(AOP(right),offset,FALSE),
4142 /* PENDING: should be OK. */
4144 /* if the result is of type pointer */
4145 if (IS_PTR(ctype)) {
4150 /* so we now know that the size of destination is greater
4151 than the size of the source */
4152 /* we move to result for the size of source */
4153 size = AOP_SIZE(right);
4157 aopGet(AOP(right),offset,FALSE),
4162 /* now depending on the sign of the destination */
4163 size = AOP_SIZE(result) - AOP_SIZE(right);
4164 /* Unsigned or not an integral type - right fill with zeros */
4165 if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) {
4167 aopPut(AOP(result),zero,offset++);
4169 /* we need to extend the sign :{ */
4170 char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
4173 emitcode("", "; genCast: sign extend untested.");
4174 emitcode("rla", "");
4175 emitcode("sbc", "a,a");
4177 aopPut(AOP(result),"a",offset++);
4181 freeAsmop(right, NULL, ic);
4182 freeAsmop(result, NULL, ic);
4185 /*-----------------------------------------------------------------*/
4186 /* genReceive - generate code for a receive iCode */
4187 /*-----------------------------------------------------------------*/
4188 static void genReceive (iCode *ic)
4190 if (isOperandInFarSpace(IC_RESULT(ic)) &&
4191 ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
4192 IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
4196 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
4198 assignResultValue(IC_RESULT(ic));
4201 freeAsmop(IC_RESULT(ic),NULL,ic);
4204 /*-----------------------------------------------------------------*/
4205 /* genZ80Code - generate code for Z80 based controllers */
4206 /*-----------------------------------------------------------------*/
4207 void genZ80Code (iCode *lic)
4214 _fReturn = _gbz80_return;
4215 _fTmp = _gbz80_return;
4218 _fReturn = _z80_return;
4219 _fTmp = _z80_return;
4221 tsprintf(zero, "!zero");
4223 lineHead = lineCurr = NULL;
4225 /* if debug information required */
4226 if (options.debug && currFunc) {
4227 cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
4229 if (IS_STATIC(currFunc->etype))
4230 emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name);
4232 emitcode("","G$%s$0$0 ==.",currFunc->name);
4235 /* stack pointer name */
4239 for (ic = lic ; ic ; ic = ic->next ) {
4241 if ( cln != ic->lineno ) {
4242 if ( options.debug ) {
4244 emitcode("","C$%s$%d$%d$%d ==.",
4245 ic->filename,ic->lineno,
4246 ic->level,ic->block);
4249 emitcode(";","%s %d",ic->filename,ic->lineno);
4252 /* if the result is marked as
4253 spilt and rematerializable or code for
4254 this has already been generated then
4256 if (resultRemat(ic) || ic->generated )
4259 /* depending on the operation */
4262 emitcode("", "; genNot");
4267 emitcode("", "; genCpl");
4272 emitcode("", "; genUminus");
4277 emitcode("", "; genIpush");
4282 /* IPOP happens only when trying to restore a
4283 spilt live range, if there is an ifx statement
4284 following this pop then the if statement might
4285 be using some of the registers being popped which
4286 would destory the contents of the register so
4287 we need to check for this condition and handle it */
4289 ic->next->op == IFX &&
4290 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) {
4291 emitcode("", "; genIfx");
4292 genIfx (ic->next,ic);
4295 emitcode("", "; genIpop");
4301 emitcode("", "; genCall");
4306 emitcode("", "; genPcall");
4311 emitcode("", "; genFunction");
4316 emitcode("", "; genEndFunction");
4317 genEndFunction (ic);
4321 emitcode("", "; genRet");
4326 emitcode("", "; genLabel");
4331 emitcode("", "; genGoto");
4336 emitcode("", "; genPlus");
4341 emitcode("", "; genMinus");
4346 emitcode("", "; genMult");
4351 emitcode("", "; genDiv");
4356 emitcode("", "; genMod");
4361 emitcode("", "; genCmpGt");
4362 genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));
4366 emitcode("", "; genCmpLt");
4367 genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
4374 /* note these two are xlated by algebraic equivalence
4375 during parsing SDCC.y */
4376 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
4377 "got '>=' or '<=' shouldn't have come here");
4381 emitcode("", "; genCmpEq");
4382 genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
4386 emitcode("", "; genAndOp");
4391 emitcode("", "; genOrOp");
4396 emitcode("", "; genXor");
4397 genXor (ic,ifxForOp(IC_RESULT(ic),ic));
4401 emitcode("", "; genOr");
4402 genOr (ic,ifxForOp(IC_RESULT(ic),ic));
4406 emitcode("", "; genAnd");
4407 genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
4411 emitcode("", "; genInline");
4416 emitcode("", "; genRRC");
4421 emitcode("", "; genRLC");
4426 emitcode("", "; genHBIT");
4430 emitcode("", "; genLeftShift");
4435 emitcode("", "; genRightShift");
4439 case GET_VALUE_AT_ADDRESS:
4440 emitcode("", "; genPointerGet");
4446 if (POINTER_SET(ic)) {
4447 emitcode("", "; genAssign (pointer)");
4451 emitcode("", "; genAssign");
4457 emitcode("", "; genIfx");
4462 emitcode("", "; genAddrOf");
4467 emitcode("", "; genJumpTab");
4472 emitcode("", "; genCast");
4477 emitcode("", "; genReceive");
4482 emitcode("", "; addSet");
4483 addSet(&sendSet,ic);
4488 /* piCode(ic,stdout); */
4494 /* now we are ready to call the
4495 peep hole optimizer */
4496 if (!options.nopeep)
4497 peepHole (&lineHead);
4499 /* now do the actual printing */
4500 printLine (lineHead,codeOutFile);