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" };
74 static char *hlUse[] = { "l", "h" };
80 extern int ptrRegReq ;
82 extern FILE *codeOutFile;
99 } _pairs[NUM_PAIRS] = {
104 { "iy", "iy.l?", "iy.h?" },
105 { "ix", "ix.l?", "ix.h?" }
108 #define RESULTONSTACK(x) \
109 (IC_RESULT(x) && IC_RESULT(x)->aop && \
110 IC_RESULT(x)->aop->type == AOP_STK )
112 #define MOVA(x) if (strcmp(x,"a")) emitcode("ld","a,%s",x);
113 #define CLRC emitcode("xor","a,a");
115 lineNode *lineHead = NULL;
116 lineNode *lineCurr = NULL;
118 static const unsigned char SLMask[] =
119 {0xFF ,0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00};
120 static const unsigned char SRMask[] =
121 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00};
149 static char *aopGet(asmop *aop, int offset, bool bit16);
151 static void _tidyUp(char *buf)
153 /* Clean up the line so that it is 'prettier' */
154 if (strchr(buf, ':')) {
155 /* Is a label - cant do anything */
158 /* Change the first (and probably only) ' ' to a tab so
170 static void emit2(const char *szFormat, ...)
175 va_start(ap, szFormat);
177 tvsprintf(buffer, szFormat, ap);
180 lineCurr = (lineCurr ?
181 connectLine(lineCurr,newLineNode(buffer)) :
182 (lineHead = newLineNode(buffer)));
184 lineCurr->isInline = inLine;
185 lineCurr->isDebug = debugLine;
188 /*-----------------------------------------------------------------*/
189 /* emitcode - writes the code into a file : for now it is simple */
190 /*-----------------------------------------------------------------*/
191 void emitcode (const char *inst, const char *fmt, ...)
194 char lb[MAX_INLINEASM];
200 sprintf(lb,"%s\t",inst);
201 vsprintf(lb+(strlen(lb)),fmt,ap);
205 while (isspace(*lbp)) lbp++;
208 lineCurr = (lineCurr ?
209 connectLine(lineCurr,newLineNode(lb)) :
210 (lineHead = newLineNode(lb)));
211 lineCurr->isInline = inLine;
212 lineCurr->isDebug = debugLine;
229 emitcode("ld", "sp,ix");
230 emitcode("pop", "ix");
231 emitcode("pop", "de");
236 const char *getPairName(asmop *aop)
238 if (aop->type == AOP_REG) {
239 switch (aop->aopu.aop_reg[0]->rIdx) {
251 else if (aop->type == AOP_STR) {
252 switch (*aop->aopu.aop_str[0]) {
268 static PAIR_ID getPairId(asmop *aop)
270 if (aop->size == 2) {
271 if (aop->type == AOP_REG) {
272 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX)&&(aop->aopu.aop_reg[1]->rIdx == B_IDX)) {
275 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX)&&(aop->aopu.aop_reg[1]->rIdx == D_IDX)) {
278 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX)&&(aop->aopu.aop_reg[1]->rIdx == H_IDX)) {
282 if (aop->type == AOP_STR) {
283 if (!strcmp(aop->aopu.aop_str[0], "c")&&!strcmp(aop->aopu.aop_str[1], "b")) {
286 if (!strcmp(aop->aopu.aop_str[0], "e")&&!strcmp(aop->aopu.aop_str[1], "d")) {
289 if (!strcmp(aop->aopu.aop_str[0], "l")&&!strcmp(aop->aopu.aop_str[1], "h")) {
297 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
298 bool isPair(asmop *aop)
300 return (getPairId(aop) != PAIR_INVALID);
303 bool isPtrPair(asmop *aop)
305 PAIR_ID pairId = getPairId(aop);
315 /** Push a register pair onto the stack */
316 void genPairPush(asmop *aop)
318 emitcode("push", "%s", getPairName(aop));
322 /*-----------------------------------------------------------------*/
323 /* newAsmop - creates a new asmOp */
324 /*-----------------------------------------------------------------*/
325 static asmop *newAsmop (short type)
329 ALLOC(aop,sizeof(asmop));
334 /*-----------------------------------------------------------------*/
335 /* aopForSym - for a true symbol */
336 /*-----------------------------------------------------------------*/
337 static asmop *aopForSym (iCode *ic,symbol *sym,bool result, bool requires_a)
340 memmap *space= SPEC_OCLS(sym->etype);
342 /* if already has one */
346 /* Assign depending on the storage class */
347 if (sym->onStack || sym->iaccess) {
348 emitcode("", "; AOP_STK for %s", sym->rname);
349 sym->aop = aop = newAsmop(AOP_STK);
350 aop->size = getSize(sym->type);
351 aop->aopu.aop_stk = sym->stack;
355 /* special case for a function */
356 if (IS_FUNC(sym->type)) {
357 sym->aop = aop = newAsmop(AOP_IMMD);
358 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(sym->rname)+1);
359 strcpy(aop->aopu.aop_immd,sym->rname);
365 /* if it is in direct space */
366 if (IN_REGSP(space) && !requires_a) {
367 sym->aop = aop = newAsmop (AOP_SFR);
368 aop->aopu.aop_dir = sym->rname ;
369 aop->size = getSize(sym->type);
370 emitcode("", "; AOP_SFR for %s", sym->rname);
375 /* only remaining is far space */
376 /* in which case DPTR gets the address */
378 emitcode("", "; AOP_HL for %s", sym->rname);
379 sym->aop = aop = newAsmop(AOP_HL);
382 sym->aop = aop = newAsmop(AOP_IY);
384 aop->size = getSize(sym->type);
385 aop->aopu.aop_dir = sym->rname;
387 /* if it is in code space */
388 if (IN_CODESPACE(space))
394 /*-----------------------------------------------------------------*/
395 /* aopForRemat - rematerialzes an object */
396 /*-----------------------------------------------------------------*/
397 static asmop *aopForRemat (symbol *sym)
400 iCode *ic = sym->rematiCode;
401 asmop *aop = newAsmop(AOP_IMMD);
404 /* if plus or minus print the right hand side */
405 if (ic->op == '+' || ic->op == '-') {
406 /* PENDING: for re-target */
407 sprintf(s,"0x%04x %c ",(int) operandLitValue(IC_RIGHT(ic)),
410 ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode;
413 /* we reached the end */
414 sprintf(s,"%s",OP_SYMBOL(IC_LEFT(ic))->rname);
418 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(buffer)+1);
419 strcpy(aop->aopu.aop_immd,buffer);
423 /*-----------------------------------------------------------------*/
424 /* regsInCommon - two operands have some registers in common */
425 /*-----------------------------------------------------------------*/
426 bool regsInCommon (operand *op1, operand *op2)
431 /* if they have registers in common */
432 if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
435 sym1 = OP_SYMBOL(op1);
436 sym2 = OP_SYMBOL(op2);
438 if (sym1->nRegs == 0 || sym2->nRegs == 0)
441 for (i = 0 ; i < sym1->nRegs ; i++) {
446 for (j = 0 ; j < sym2->nRegs ;j++ ) {
450 if (sym2->regs[j] == sym1->regs[i])
458 /*-----------------------------------------------------------------*/
459 /* operandsEqu - equivalent */
460 /*-----------------------------------------------------------------*/
461 bool operandsEqu ( operand *op1, operand *op2)
465 /* if they not symbols */
466 if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
469 sym1 = OP_SYMBOL(op1);
470 sym2 = OP_SYMBOL(op2);
472 /* if both are itemps & one is spilt
473 and the other is not then false */
474 if (IS_ITEMP(op1) && IS_ITEMP(op2) &&
475 sym1->isspilt != sym2->isspilt )
478 /* if they are the same */
482 if (strcmp(sym1->rname,sym2->rname) == 0)
486 /* if left is a tmp & right is not */
490 (sym1->usl.spillLoc == sym2))
497 (sym2->usl.spillLoc == sym1))
503 /*-----------------------------------------------------------------*/
504 /* sameRegs - two asmops have the same registers */
505 /*-----------------------------------------------------------------*/
506 bool sameRegs (asmop *aop1, asmop *aop2 )
510 if (aop1->type == AOP_SFR ||
511 aop2->type == AOP_SFR)
517 if (aop1->type != AOP_REG ||
518 aop2->type != AOP_REG )
521 if (aop1->size != aop2->size)
524 for (i = 0 ; i < aop1->size ; i++ )
525 if (aop1->aopu.aop_reg[i] !=
526 aop2->aopu.aop_reg[i] )
532 /*-----------------------------------------------------------------*/
533 /* aopOp - allocates an asmop for an operand : */
534 /*-----------------------------------------------------------------*/
535 static void aopOp (operand *op, iCode *ic, bool result, bool requires_a)
544 /* if this a literal */
545 if (IS_OP_LITERAL(op)) {
546 op->aop = aop = newAsmop(AOP_LIT);
547 aop->aopu.aop_lit = op->operand.valOperand;
548 aop->size = getSize(operandType(op));
552 /* if already has a asmop then continue */
556 /* if the underlying symbol has a aop */
557 if (IS_SYMOP(op) && OP_SYMBOL(op)->aop) {
558 op->aop = OP_SYMBOL(op)->aop;
562 /* if this is a true symbol */
563 if (IS_TRUE_SYMOP(op)) {
564 op->aop = aopForSym(ic,OP_SYMBOL(op),result, requires_a);
568 /* this is a temporary : this has
574 e) can be a return use only */
578 /* if the type is a conditional */
579 if (sym->regType == REG_CND) {
580 aop = op->aop = sym->aop = newAsmop(AOP_CRY);
585 /* if it is spilt then two situations
587 b) has a spill location */
588 if (sym->isspilt || sym->nRegs == 0) {
589 /* rematerialize it NOW */
591 sym->aop = op->aop = aop =
593 aop->size = getSize(sym->type);
599 if (sym->accuse == ACCUSE_A) {
600 aop = op->aop = sym->aop = newAsmop(AOP_ACC);
601 aop->size = getSize(sym->type);
602 for ( i = 0 ; i < 2 ; i++ )
603 aop->aopu.aop_str[i] = accUse[i];
605 else if (sym->accuse == ACCUSE_HL) {
607 aop = op->aop = sym->aop = newAsmop(AOP_HLREG);
608 aop->size = getSize(sym->type);
609 for ( i = 0 ; i < 2 ; i++ )
610 aop->aopu.aop_str[i] = hlUse[i];
619 aop = op->aop = sym->aop = newAsmop(AOP_STR);
620 aop->size = getSize(sym->type);
621 for ( i = 0 ; i < 4 ; i++ )
622 aop->aopu.aop_str[i] = _fReturn[i];
626 /* else spill location */
627 sym->aop = op->aop = aop =
628 aopForSym(ic,sym->usl.spillLoc,result, requires_a);
629 aop->size = getSize(sym->type);
633 /* must be in a register */
634 sym->aop = op->aop = aop = newAsmop(AOP_REG);
635 aop->size = sym->nRegs;
636 for ( i = 0 ; i < sym->nRegs ;i++)
637 aop->aopu.aop_reg[i] = sym->regs[i];
640 /*-----------------------------------------------------------------*/
641 /* freeAsmop - free up the asmop given to an operand */
642 /*----------------------------------------------------------------*/
643 static void freeAsmop (operand *op, asmop *aaop, iCode *ic)
661 /* all other cases just dealloc */
665 OP_SYMBOL(op)->aop = NULL;
666 /* if the symbol has a spill */
668 SPIL_LOC(op)->aop = NULL;
673 bool isLitWord(asmop *aop)
675 /* if (aop->size != 2)
686 char *aopGetLitWordLong(asmop *aop, int offset, bool with_hash)
692 if (aop->size != 2 && aop->type != AOP_HL)
695 /* depending on type */
700 /* PENDING: for re-target */
702 tsprintf(s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
704 tsprintf(s, "%s + %d", aop->aopu.aop_immd, offset);
705 ALLOC_ATOMIC(rs,strlen(s)+1);
709 value * val = aop->aopu.aop_lit;
710 /* if it is a float then it gets tricky */
711 /* otherwise it is fairly simple */
712 if (!IS_FLOAT(val->type)) {
713 unsigned long v = floatFromVal(val);
717 tsprintf(buffer, "!immedword", v);
719 tsprintf(buffer, "!constword", v);
720 ALLOC_ATOMIC(rs,strlen(buffer)+1);
721 return strcpy (rs,buffer);
726 convertFloat(&f, floatFromVal(val));
728 tsprintf(buffer, "!immedword", f.w[offset/2]);
730 tsprintf(buffer, "!constword", f.w[offset/2]);
731 ALLOC_ATOMIC(rs,strlen(buffer)+1);
732 return strcpy (rs,buffer);
740 char *aopGetWord(asmop *aop, int offset)
742 return aopGetLitWordLong(aop, offset, TRUE);
745 bool isPtr(const char *s)
747 if (!strcmp(s, "hl"))
749 if (!strcmp(s, "ix"))
751 if (!strcmp(s, "iy"))
756 static void adjustPair(const char *pair, int *pold, int new)
760 while (*pold < new) {
761 emitcode("inc", "%s", pair);
764 while (*pold > new) {
765 emitcode("dec", "%s", pair);
770 static void spillPair(PAIR_ID pairId)
772 _G.pairs[pairId].last_type = AOP_INVALID;
773 _G.pairs[pairId].lit = NULL;
776 static void spillCached(void)
782 static bool requiresHL(asmop *aop)
793 static void fetchLitPair(PAIR_ID pairId, asmop *left, int offset)
796 const char *pair = _pairs[pairId].name;
797 l = aopGetLitWordLong(left, offset, FALSE);
801 if (pairId == PAIR_HL || pairId == PAIR_IY) {
802 if (_G.pairs[pairId].last_type == left->type) {
803 if (_G.pairs[pairId].lit && !strcmp(_G.pairs[pairId].lit, l)) {
804 if (pairId == PAIR_HL && abs(_G.pairs[pairId].offset - offset) < 3) {
805 adjustPair(pair, &_G.pairs[pairId].offset, offset);
808 if (pairId == PAIR_IY && abs(offset)<127) {
814 _G.pairs[pairId].last_type = left->type;
815 _G.pairs[pairId].lit = gc_strdup(l);
816 _G.pairs[pairId].offset = offset;
818 /* Both a lit on the right and a true symbol on the left */
819 /* PENDING: for re-target */
822 emit2("ld %s,!hashedstr + %d", pair, l, offset);
825 emit2("ld %s,!hashedstr", pair, l);
828 static void fetchPairLong(PAIR_ID pairId, asmop *aop, int offset)
830 /* if this is remateriazable */
831 if (isLitWord(aop)) {
832 fetchLitPair(pairId, aop, offset);
834 else { /* we need to get it byte by byte */
835 if (pairId == PAIR_HL && IS_GB && requiresHL(aop)) {
836 aopGet(aop, offset, FALSE);
841 else if (IS_Z80 && aop->type == AOP_IY) {
842 /* Instead of fetching relative to IY, just grab directly
843 from the address IY refers to */
844 char *l = aopGetLitWordLong(aop, offset, FALSE);
846 emit2("ld %s,(%s)", _pairs[pairId].name, l);
849 emitcode("ld", "%s,%s", _pairs[pairId].l, aopGet(aop, offset, FALSE));
850 emitcode("ld", "%s,%s", _pairs[pairId].h, aopGet(aop, offset+1, FALSE));
852 /* PENDING: check? */
853 if (pairId == PAIR_HL)
858 static void fetchPair(PAIR_ID pairId, asmop *aop)
860 fetchPairLong(pairId, aop, 0);
863 static void fetchHL(asmop *aop)
865 fetchPair(PAIR_HL, aop);
868 static void setupPair(PAIR_ID pairId, asmop *aop, int offset)
870 assert(pairId == PAIR_HL || pairId == PAIR_IY);
874 fetchLitPair(pairId, aop, 0);
877 fetchLitPair(pairId, aop, offset);
878 _G.pairs[pairId].offset = offset;
881 /* Doesnt include _G.stack.pushed */
882 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
883 assert(pairId == PAIR_HL);
884 /* In some cases we can still inc or dec hl */
885 if (_G.pairs[pairId].last_type == AOP_STK && abs(_G.pairs[pairId].offset - abso) < 3) {
886 adjustPair(_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
889 emit2("!ldahlsp", aop->aopu.aop_stk+offset + _G.stack.pushed + _G.stack.offset);
891 _G.pairs[pairId].offset = abso;
897 _G.pairs[pairId].last_type = aop->type;
900 static void emitLabel(int key)
902 emit2("!tlabeldef", key);
906 /*-----------------------------------------------------------------*/
907 /* aopGet - for fetching value of the aop */
908 /*-----------------------------------------------------------------*/
909 static char *aopGet(asmop *aop, int offset, bool bit16)
914 /* offset is greater than size then zero */
915 /* PENDING: this seems a bit screwed in some pointer cases. */
916 if (offset > (aop->size - 1) &&
917 aop->type != AOP_LIT)
920 /* depending on type */
923 /* PENDING: re-target */
925 tsprintf (s,"!immedwords", aop->aopu.aop_immd);
928 wassert(offset == 1);
929 tsprintf(s, "!lsbimmeds", aop->aopu.aop_immd);
932 tsprintf(s, "!msbimmeds", aop->aopu.aop_immd);
933 ALLOC_ATOMIC(rs,strlen(s)+1);
939 emitcode("ld", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
941 ALLOC_ATOMIC(rs,strlen(s)+1);
947 emitcode("ldh", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
949 ALLOC_ATOMIC(rs,strlen(s)+1);
954 return aop->aopu.aop_reg[offset]->name;
958 setupPair(PAIR_HL, aop, offset);
964 setupPair(PAIR_IY, aop, offset);
965 tsprintf(s,"!*iyx", offset);
966 ALLOC_ATOMIC(rs,strlen(s)+1);
972 setupPair(PAIR_HL, aop, offset);
976 tsprintf(s,"!*ixx", aop->aopu.aop_stk+offset);
978 ALLOC_ATOMIC(rs,strlen(s)+1);
993 return aop->aopu.aop_str[offset];
996 return aopLiteral (aop->aopu.aop_lit,offset);
1000 return aop->aopu.aop_str[offset];
1004 wassertl(0, "aopget got unsupported aop->type");
1008 bool isRegString(char *s)
1010 if (!strcmp(s, "b") ||
1021 bool isConstant(const char *s)
1023 /* This is a bit of a hack... */
1024 return (*s == '#' || *s == '$');
1027 bool canAssignToPtr(char *s)
1036 /*-----------------------------------------------------------------*/
1037 /* aopPut - puts a string for a aop */
1038 /*-----------------------------------------------------------------*/
1039 static void aopPut (asmop *aop, char *s, int offset)
1041 if (aop->size && offset > ( aop->size - 1)) {
1042 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1043 "aopPut got offset > aop->size");
1047 /* will assign value to value */
1048 /* depending on where it is ofcourse */
1049 switch (aop->type) {
1054 emitcode("ld", "a,%s", s);
1055 emitcode("ld", "(%s+%d),a", aop->aopu.aop_dir, offset);
1061 emitcode("ld", "a,%s", s);
1062 emitcode("ldh", "(%s+%d),a", aop->aopu.aop_dir, offset);
1066 if (!strcmp(s, "!*hl"))
1067 emit2("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1070 aop->aopu.aop_reg[offset]->name, s);
1075 setupPair(PAIR_IY, aop, offset);
1076 if (!canAssignToPtr(s)) {
1077 emit2("ld a,%s", s);
1078 emit2("ld !*iyx,a", offset);
1081 emit2("ld !*iyx,%s", offset, s);
1086 /* PENDING: for re-target */
1087 if (!strcmp(s, "!*hl") || !strcmp(s, "(hl)") || !strcmp(s, "[hl]")) {
1091 setupPair(PAIR_HL, aop, offset);
1093 emit2("ld !*hl,%s", s);
1098 /* PENDING: re-target */
1099 if (!strcmp(s, "!*hl") || !strcmp(s, "(hl)") || !strcmp(s, "[hl]")) {
1103 setupPair(PAIR_HL, aop, offset);
1104 if (!canAssignToPtr(s)) {
1105 emit2("ld a,%s", s);
1109 emit2("ld !*hl,%s ; 3", s);
1112 if (!canAssignToPtr(s)) {
1113 emit2("ld a,%s", s);
1114 emit2("ld !*ixx,a", aop->aopu.aop_stk+offset);
1117 emit2("ld !*ixx,%s", aop->aopu.aop_stk+offset, s);
1122 /* if bit variable */
1123 if (!aop->aopu.aop_dir) {
1127 /* In bit space but not in C - cant happen */
1134 if (strcmp(aop->aopu.aop_str[offset],s)) {
1135 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1141 if (!offset && (strcmp(s,"acc") == 0))
1145 emitcode("", "; Error aopPut AOP_ACC");
1148 if (strcmp(aop->aopu.aop_str[offset],s))
1149 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1154 wassert(offset < 2);
1155 emit2("ld %s,%s", aop->aopu.aop_str[offset], s);
1159 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1160 "aopPut got unsupported aop->type");
1165 #define AOP(op) op->aop
1166 #define AOP_TYPE(op) AOP(op)->type
1167 #define AOP_SIZE(op) AOP(op)->size
1168 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1170 /*-----------------------------------------------------------------*/
1171 /* getDataSize - get the operand data size */
1172 /*-----------------------------------------------------------------*/
1173 int getDataSize(operand *op)
1176 size = AOP_SIZE(op);
1184 /*-----------------------------------------------------------------*/
1185 /* movLeft2Result - move byte from left to result */
1186 /*-----------------------------------------------------------------*/
1187 static void movLeft2Result (operand *left, int offl,
1188 operand *result, int offr, int sign)
1191 if(!sameRegs(AOP(left),AOP(result)) || (offl != offr)){
1192 l = aopGet(AOP(left),offl,FALSE);
1195 aopPut(AOP(result),l,offr);
1204 /** Put Acc into a register set
1206 void outAcc(operand *result)
1209 size = getDataSize(result);
1211 aopPut(AOP(result),"a",0);
1214 /* unsigned or positive */
1216 aopPut(AOP(result), zero, offset++);
1221 /** Take the value in carry and put it into a register
1223 void outBitC(operand *result)
1225 /* if the result is bit */
1226 if (AOP_TYPE(result) == AOP_CRY) {
1227 emitcode("", "; Note: outBitC form 1");
1228 aopPut(AOP(result),"blah",0);
1231 emit2("ld a,!zero");
1237 /*-----------------------------------------------------------------*/
1238 /* toBoolean - emit code for orl a,operator(sizeop) */
1239 /*-----------------------------------------------------------------*/
1240 void toBoolean(operand *oper)
1242 int size = AOP_SIZE(oper);
1245 emitcode("ld", "a,%s", aopGet(AOP(oper), offset++, FALSE));
1248 emitcode("or","a,%s",aopGet(AOP(oper),offset++,FALSE));
1251 if (AOP(oper)->type != AOP_ACC) {
1253 emitcode("or","a,%s",aopGet(AOP(oper),0,FALSE));
1258 /*-----------------------------------------------------------------*/
1259 /* genNot - generate code for ! operation */
1260 /*-----------------------------------------------------------------*/
1261 static void genNot (iCode *ic)
1263 link *optype = operandType(IC_LEFT(ic));
1265 /* assign asmOps to operand & result */
1266 aopOp (IC_LEFT(ic),ic,FALSE, TRUE);
1267 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1269 /* if in bit space then a special case */
1270 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) {
1274 /* if type float then do float */
1275 if (IS_FLOAT(optype)) {
1279 toBoolean(IC_LEFT(ic));
1284 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1285 emit2("sub a,!one");
1286 outBitC(IC_RESULT(ic));
1288 /* release the aops */
1289 freeAsmop(IC_LEFT(ic),NULL,ic);
1290 freeAsmop(IC_RESULT(ic),NULL,ic);
1293 /*-----------------------------------------------------------------*/
1294 /* genCpl - generate code for complement */
1295 /*-----------------------------------------------------------------*/
1296 static void genCpl (iCode *ic)
1302 /* assign asmOps to operand & result */
1303 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
1304 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1306 /* if both are in bit space then
1308 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1309 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1313 size = AOP_SIZE(IC_RESULT(ic));
1315 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1318 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1321 /* release the aops */
1322 freeAsmop(IC_LEFT(ic),NULL,ic);
1323 freeAsmop(IC_RESULT(ic),NULL,ic);
1326 /*-----------------------------------------------------------------*/
1327 /* genUminus - unary minus code generation */
1328 /*-----------------------------------------------------------------*/
1329 static void genUminus (iCode *ic)
1332 link *optype, *rtype;
1335 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1336 aopOp(IC_RESULT(ic),ic,TRUE, FALSE);
1338 /* if both in bit space then special
1340 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1341 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1346 optype = operandType(IC_LEFT(ic));
1347 rtype = operandType(IC_RESULT(ic));
1349 /* if float then do float stuff */
1350 if (IS_FLOAT(optype)) {
1355 /* otherwise subtract from zero */
1356 size = AOP_SIZE(IC_LEFT(ic));
1360 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1361 emit2("ld a,!zero");
1362 emit2("sbc a,%s",l);
1363 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1366 /* if any remaining bytes in the result */
1367 /* we just need to propagate the sign */
1368 if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic))))) {
1372 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1376 /* release the aops */
1377 freeAsmop(IC_LEFT(ic),NULL,ic);
1378 freeAsmop(IC_RESULT(ic),NULL,ic);
1381 /*-----------------------------------------------------------------*/
1382 /* assignResultValue - */
1383 /*-----------------------------------------------------------------*/
1384 void assignResultValue(operand * oper)
1386 int size = AOP_SIZE(oper);
1390 topInA = requiresHL(AOP(oper));
1396 if (IS_GB && size == 4 && requiresHL(AOP(oper))) {
1397 /* We do it the hard way here. */
1398 emitcode("push", "hl");
1399 _G.stack.pushed += 2;
1400 aopPut(AOP(oper), _fReturn[0], 0);
1401 aopPut(AOP(oper), _fReturn[1], 1);
1402 emitcode("pop", "de");
1403 _G.stack.pushed -= 2;
1404 aopPut(AOP(oper), _fReturn[0], 2);
1405 aopPut(AOP(oper), _fReturn[1], 3);
1409 aopPut(AOP(oper), _fReturn[size], size);
1414 /*-----------------------------------------------------------------*/
1415 /* genIpush - genrate code for pushing this gets a little complex */
1416 /*-----------------------------------------------------------------*/
1417 static void genIpush (iCode *ic)
1419 int size, offset = 0 ;
1423 /* if this is not a parm push : ie. it is spill push
1424 and spill push is always done on the local stack */
1425 if (!ic->parmPush) {
1426 /* and the item is spilt then do nothing */
1427 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1430 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1431 size = AOP_SIZE(IC_LEFT(ic));
1432 /* push it on the stack */
1433 if (isPair(AOP(IC_LEFT(ic)))) {
1434 emitcode("push", getPairName(AOP(IC_LEFT(ic))));
1435 _G.stack.pushed += 2;
1440 /* Simple for now - load into A and PUSH AF */
1441 if (AOP(IC_LEFT(ic))->type == AOP_IY) {
1442 char *l = aopGetLitWordLong(AOP(IC_LEFT(ic)), --offset, FALSE);
1444 emit2("ld a,(%s)", l);
1447 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1448 emit2("ld a,%s", l);
1458 /* Hmmm... what about saving the currently used registers
1461 /* then do the push */
1462 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1464 size = AOP_SIZE(IC_LEFT(ic));
1466 if (isPair(AOP(IC_LEFT(ic)))) {
1468 emitcode("push", "%s", getPairName(AOP(IC_LEFT(ic))));
1472 fetchHL(AOP(IC_LEFT(ic)));
1473 emitcode("push", "hl");
1475 _G.stack.pushed += 2;
1479 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
1480 emitcode("push", "hl");
1482 _G.stack.pushed += 2;
1483 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 0);
1484 emitcode("push", "hl");
1486 _G.stack.pushed += 2;
1491 if (AOP(IC_LEFT(ic))->type == AOP_IY) {
1492 char *l = aopGetLitWordLong(AOP(IC_LEFT(ic)), --offset, FALSE);
1494 emit2("ld a,(%s)", l);
1497 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1498 emit2("ld a,%s", l);
1500 emitcode("push", "af");
1501 emitcode("inc", "sp");
1506 freeAsmop(IC_LEFT(ic),NULL,ic);
1509 /*-----------------------------------------------------------------*/
1510 /* genIpop - recover the registers: can happen only for spilling */
1511 /*-----------------------------------------------------------------*/
1512 static void genIpop (iCode *ic)
1517 /* if the temp was not pushed then */
1518 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1521 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1522 size = AOP_SIZE(IC_LEFT(ic));
1524 if (isPair(AOP(IC_LEFT(ic)))) {
1525 emitcode("pop", getPairName(AOP(IC_LEFT(ic))));
1529 emitcode("dec", "sp");
1530 emitcode("pop", "hl");
1532 aopPut(AOP(IC_LEFT(ic)), "l", offset--);
1536 freeAsmop(IC_LEFT(ic),NULL,ic);
1539 /** Emit the code for a call statement
1541 static void emitCall (iCode *ic, bool ispcall)
1543 /* if caller saves & we have not saved then */
1544 if (!ic->regsSaved) {
1548 /* if send set is not empty then assign */
1551 for (sic = setFirstItem(sendSet) ; sic ;
1552 sic = setNextItem(sendSet)) {
1553 int size, offset = 0;
1554 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1555 size = AOP_SIZE(IC_LEFT(sic));
1557 char *l = aopGet(AOP(IC_LEFT(sic)),offset,
1559 if (strcmp(l, _fReturn[offset]))
1560 emitcode("ld","%s,%s",
1565 freeAsmop (IC_LEFT(sic),NULL,sic);
1571 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1573 if (isLitWord(AOP(IC_LEFT(ic)))) {
1574 emitcode("", "; Special case where the pCall is to a constant");
1575 emitcode("call", aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE));
1578 symbol *rlbl = newiTempLabel(NULL);
1580 emit2("ld hl,#!tlabel", (rlbl->key+100));
1581 emitcode("push", "hl");
1582 _G.stack.pushed += 2;
1584 fetchHL(AOP(IC_LEFT(ic)));
1586 emit2("!tlabeldef", (rlbl->key+100));
1587 _G.stack.pushed -= 2;
1589 freeAsmop(IC_LEFT(ic),NULL,ic);
1593 char *name = OP_SYMBOL(IC_LEFT(ic))->rname[0] ?
1594 OP_SYMBOL(IC_LEFT(ic))->rname :
1595 OP_SYMBOL(IC_LEFT(ic))->name;
1596 emitcode("call", "%s", name);
1600 /* if we need assign a result value */
1601 if ((IS_ITEMP(IC_RESULT(ic)) &&
1602 (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
1603 OP_SYMBOL(IC_RESULT(ic))->spildir )) ||
1604 IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
1607 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
1610 assignResultValue(IC_RESULT(ic));
1612 freeAsmop(IC_RESULT(ic),NULL, ic);
1615 /* adjust the stack for parameters if required */
1616 if (IC_LEFT(ic)->parmBytes) {
1617 int i = IC_LEFT(ic)->parmBytes;
1618 _G.stack.pushed -= i;
1620 emit2("!ldaspsp", i);
1625 emitcode("ld", "hl,#%d", i);
1626 emitcode("add", "hl,sp");
1627 emitcode("ld", "sp,hl");
1631 emitcode("pop", "hl");
1635 emitcode("inc", "sp");
1643 /*-----------------------------------------------------------------*/
1644 /* genCall - generates a call statement */
1645 /*-----------------------------------------------------------------*/
1646 static void genCall (iCode *ic)
1648 emitCall(ic, FALSE);
1651 /*-----------------------------------------------------------------*/
1652 /* genPcall - generates a call by pointer statement */
1653 /*-----------------------------------------------------------------*/
1654 static void genPcall (iCode *ic)
1659 /*-----------------------------------------------------------------*/
1660 /* resultRemat - result is rematerializable */
1661 /*-----------------------------------------------------------------*/
1662 static int resultRemat (iCode *ic)
1664 if (SKIP_IC(ic) || ic->op == IFX)
1667 if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
1668 symbol *sym = OP_SYMBOL(IC_RESULT(ic));
1669 if (sym->remat && !POINTER_SET(ic))
1676 /*-----------------------------------------------------------------*/
1677 /* genFunction - generated code for function entry */
1678 /*-----------------------------------------------------------------*/
1679 static void genFunction (iCode *ic)
1681 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1685 /* create the function header */
1686 emit2("!functionheader", sym->name);
1687 /* PENDING: portability. */
1688 emit2("__%s_start:", sym->rname);
1689 emit2("!functionlabeldef", sym->rname);
1691 fetype = getSpec(operandType(IC_LEFT(ic)));
1693 /* if critical function then turn interrupts off */
1694 if (SPEC_CRTCL(fetype))
1697 /* if this is an interrupt service routine then
1698 save acc, b, dpl, dph */
1699 if (IS_ISR(sym->etype)) {
1702 /* PENDING: callee-save etc */
1704 /* adjust the stack for the function */
1705 _G.stack.last = sym->stack;
1708 emit2("!enterx", sym->stack);
1711 _G.stack.offset = sym->stack;
1714 /*-----------------------------------------------------------------*/
1715 /* genEndFunction - generates epilogue for functions */
1716 /*-----------------------------------------------------------------*/
1717 static void genEndFunction (iCode *ic)
1719 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1721 if (IS_ISR(sym->etype)) {
1725 if (SPEC_CRTCL(sym->etype))
1728 /* PENDING: calleeSave */
1730 /* if debug then send end of function */
1731 if (options.debug && currFunc) {
1733 emitcode("","C$%s$%d$%d$%d ==.",
1734 ic->filename,currFunc->lastLine,
1735 ic->level,ic->block);
1736 if (IS_STATIC(currFunc->etype))
1737 emitcode("","XF%s$%s$0$0 ==.",moduleName,currFunc->name);
1739 emitcode("","XG$%s$0$0 ==.",currFunc->name);
1742 if (_G.stack.offset)
1743 emit2("!leavex", _G.stack.offset);
1746 /* PENDING: portability. */
1747 emit2("__%s_end:", sym->rname);
1749 _G.stack.pushed = 0;
1750 _G.stack.offset = 0;
1753 /*-----------------------------------------------------------------*/
1754 /* genRet - generate code for return statement */
1755 /*-----------------------------------------------------------------*/
1756 static void genRet (iCode *ic)
1759 /* Errk. This is a hack until I can figure out how
1760 to cause dehl to spill on a call */
1761 int size,offset = 0;
1763 /* if we have no return value then
1764 just generate the "ret" */
1768 /* we have something to return then
1769 move the return value into place */
1770 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1771 size = AOP_SIZE(IC_LEFT(ic));
1773 if ((size == 2) && ((l = aopGetWord(AOP(IC_LEFT(ic)), 0)))) {
1775 emitcode("ld", "de,%s", l);
1778 emitcode("ld", "hl,%s", l);
1782 if (IS_GB && size == 4 && requiresHL(AOP(IC_LEFT(ic)))) {
1783 fetchPair(PAIR_DE, AOP(IC_LEFT(ic)));
1784 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
1788 l = aopGet(AOP(IC_LEFT(ic)),offset,
1790 if (strcmp(_fReturn[offset],l))
1791 emitcode("ld","%s,%s", _fReturn[offset++],l);
1795 freeAsmop (IC_LEFT(ic),NULL,ic);
1798 /* generate a jump to the return label
1799 if the next is not the return statement */
1800 if (!(ic->next && ic->next->op == LABEL &&
1801 IC_LABEL(ic->next) == returnLabel))
1803 emit2("jp !tlabel", returnLabel->key+100);
1806 /*-----------------------------------------------------------------*/
1807 /* genLabel - generates a label */
1808 /*-----------------------------------------------------------------*/
1809 static void genLabel (iCode *ic)
1811 /* special case never generate */
1812 if (IC_LABEL(ic) == entryLabel)
1815 emitLabel(IC_LABEL(ic)->key+100);
1818 /*-----------------------------------------------------------------*/
1819 /* genGoto - generates a ljmp */
1820 /*-----------------------------------------------------------------*/
1821 static void genGoto (iCode *ic)
1823 emit2("jp !tlabel", IC_LABEL(ic)->key+100);
1826 /*-----------------------------------------------------------------*/
1827 /* genPlusIncr :- does addition with increment if possible */
1828 /*-----------------------------------------------------------------*/
1829 static bool genPlusIncr (iCode *ic)
1831 unsigned int icount ;
1832 unsigned int size = getDataSize(IC_RESULT(ic));
1833 PAIR_ID resultId = getPairId(AOP(IC_RESULT(ic)));
1835 /* will try to generate an increment */
1836 /* if the right side is not a literal
1838 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1841 emitcode("", "; genPlusIncr");
1843 icount = floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
1845 /* If result is a pair */
1846 if (resultId != PAIR_INVALID) {
1847 if (isLitWord(AOP(IC_LEFT(ic)))) {
1848 fetchLitPair(getPairId(AOP(IC_RESULT(ic))), AOP(IC_LEFT(ic)), icount);
1851 if (isPair(AOP(IC_LEFT(ic))) && resultId == PAIR_HL && icount > 2) {
1852 fetchPair(resultId, AOP(IC_RIGHT(ic)));
1853 emitcode("add", "hl,%s", getPairName(AOP(IC_LEFT(ic))));
1859 if (!sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
1862 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
1863 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
1866 emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
1871 /* if the literal value of the right hand side
1872 is greater than 4 then it is not worth it */
1876 /* if increment 16 bits in register */
1877 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1882 symbol *tlbl = NULL;
1883 tlbl = newiTempLabel(NULL);
1885 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)), offset++, FALSE));
1887 emit2("!shortjp nz,!tlabel", tlbl->key+100);
1890 emitLabel(tlbl->key+100);
1894 /* if the sizes are greater than 1 then we cannot */
1895 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
1896 AOP_SIZE(IC_LEFT(ic)) > 1 )
1899 /* we can if the aops of the left & result match or
1900 if they are in registers and the registers are the
1902 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
1904 emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0, FALSE));
1911 /*-----------------------------------------------------------------*/
1912 /* outBitAcc - output a bit in acc */
1913 /*-----------------------------------------------------------------*/
1914 void outBitAcc(operand *result)
1916 symbol *tlbl = newiTempLabel(NULL);
1917 /* if the result is a bit */
1918 if (AOP_TYPE(result) == AOP_CRY){
1922 emit2("!shortjp z,!tlabel", tlbl->key+100);
1924 emitLabel(tlbl->key+100);
1929 /*-----------------------------------------------------------------*/
1930 /* genPlus - generates code for addition */
1931 /*-----------------------------------------------------------------*/
1932 static void genPlus (iCode *ic)
1934 int size, offset = 0;
1936 /* special cases :- */
1938 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
1939 aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
1940 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1942 /* Swap the left and right operands if:
1944 if literal, literal on the right or
1945 if left requires ACC or right is already
1948 if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
1949 (AOP_NEEDSACC(IC_LEFT(ic))) ||
1950 AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
1951 operand *t = IC_RIGHT(ic);
1952 IC_RIGHT(ic) = IC_LEFT(ic);
1956 /* if both left & right are in bit
1958 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1959 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
1964 /* if left in bit space & right literal */
1965 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1966 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
1967 /* Can happen I guess */
1971 /* if I can do an increment instead
1972 of add then GOOD for ME */
1973 if (genPlusIncr (ic) == TRUE)
1976 size = getDataSize(IC_RESULT(ic));
1978 /* Special case when left and right are constant */
1979 if (isPair(AOP(IC_RESULT(ic)))) {
1982 left = aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE);
1983 right = aopGetLitWordLong(AOP(IC_RIGHT(ic)), 0, FALSE);
1984 if (left && right) {
1988 sprintf(buffer, "#(%s + %s)", left, right);
1989 emitcode("ld", "%s,%s", getPairName(AOP(IC_RESULT(ic))), buffer);
1994 if (isPair(AOP(IC_RIGHT(ic))) && getPairId(AOP(IC_RESULT(ic))) == PAIR_HL) {
1995 /* Fetch into HL then do the add */
1997 fetchPair(PAIR_HL, AOP(IC_LEFT(ic)));
1998 emitcode("add", "hl,%s", getPairName(AOP(IC_RIGHT(ic))));
2003 if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
2004 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2006 emitcode("add","a,%s",
2007 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2009 emitcode("adc","a,%s",
2010 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2012 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2014 emitcode("add","a,%s",
2015 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2017 emitcode("adc","a,%s",
2018 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2020 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2023 /* Some kind of pointer arith. */
2024 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2025 AOP_SIZE(IC_LEFT(ic)) == 3 &&
2026 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2029 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2030 AOP_SIZE(IC_RIGHT(ic)) == 3 &&
2031 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
2036 freeAsmop(IC_LEFT(ic),NULL,ic);
2037 freeAsmop(IC_RIGHT(ic),NULL,ic);
2038 freeAsmop(IC_RESULT(ic),NULL,ic);
2042 /*-----------------------------------------------------------------*/
2043 /* genMinusDec :- does subtraction with deccrement if possible */
2044 /*-----------------------------------------------------------------*/
2045 static bool genMinusDec (iCode *ic)
2047 unsigned int icount ;
2048 unsigned int size = getDataSize(IC_RESULT(ic));
2050 /* will try to generate an increment */
2051 /* if the right side is not a literal we cannot */
2052 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
2055 /* if the literal value of the right hand side
2056 is greater than 4 then it is not worth it */
2057 if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
2060 size = getDataSize(IC_RESULT(ic));
2063 /* if increment 16 bits in register */
2064 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2067 symbol *tlbl = newiTempLabel(NULL);
2068 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
2069 emitcode("jp", "np," LABEL_STR ,tlbl->key+100);
2071 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
2075 emitLabel(tlbl->key+100);
2080 /* if decrement 16 bits in register */
2081 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2082 (size > 1) && isPair(AOP(IC_RESULT(ic)))) {
2084 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2088 /* If result is a pair */
2089 if (isPair(AOP(IC_RESULT(ic)))) {
2090 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
2091 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
2093 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2097 /* if the sizes are greater than 1 then we cannot */
2098 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2099 AOP_SIZE(IC_LEFT(ic)) > 1 )
2102 /* we can if the aops of the left & result match or if they are in
2103 registers and the registers are the same */
2104 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
2106 emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE));
2113 /*-----------------------------------------------------------------*/
2114 /* genMinus - generates code for subtraction */
2115 /*-----------------------------------------------------------------*/
2116 static void genMinus (iCode *ic)
2118 int size, offset = 0;
2119 unsigned long lit = 0L;
2121 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
2122 aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
2123 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
2125 /* special cases :- */
2126 /* if both left & right are in bit space */
2127 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2128 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2133 /* if I can do an decrement instead of subtract then GOOD for ME */
2134 if (genMinusDec (ic) == TRUE)
2137 size = getDataSize(IC_RESULT(ic));
2139 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
2142 lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
2147 /* if literal, add a,#-lit, else normal subb */
2149 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2150 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) {
2152 emitcode("sub","a,%s",
2153 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2155 emitcode("sbc","a,%s",
2156 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2159 /* first add without previous c */
2161 emit2("add a,!immedbyte", (unsigned int)(lit & 0x0FFL));
2163 emit2("adc a,!immedbyte", (unsigned int)((lit >> (offset*8)) & 0x0FFL));
2165 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2168 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2169 AOP_SIZE(IC_LEFT(ic)) == 3 &&
2170 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2174 freeAsmop(IC_LEFT(ic),NULL,ic);
2175 freeAsmop(IC_RIGHT(ic),NULL,ic);
2176 freeAsmop(IC_RESULT(ic),NULL,ic);
2179 /*-----------------------------------------------------------------*/
2180 /* genMult - generates code for multiplication */
2181 /*-----------------------------------------------------------------*/
2182 static void genMult (iCode *ic)
2184 /* Shouldn't occur - all done through function calls */
2188 /*-----------------------------------------------------------------*/
2189 /* genDiv - generates code for division */
2190 /*-----------------------------------------------------------------*/
2191 static void genDiv (iCode *ic)
2193 /* Shouldn't occur - all done through function calls */
2197 /*-----------------------------------------------------------------*/
2198 /* genMod - generates code for division */
2199 /*-----------------------------------------------------------------*/
2200 static void genMod (iCode *ic)
2202 /* Shouldn't occur - all done through function calls */
2206 /*-----------------------------------------------------------------*/
2207 /* genIfxJump :- will create a jump depending on the ifx */
2208 /*-----------------------------------------------------------------*/
2209 static void genIfxJump (iCode *ic, char *jval)
2214 /* if true label then we jump if condition
2216 if ( IC_TRUE(ic) ) {
2218 if (!strcmp(jval, "a")) {
2221 else if (!strcmp(jval, "c")) {
2225 /* The buffer contains the bit on A that we should test */
2230 /* false label is present */
2231 jlbl = IC_FALSE(ic) ;
2232 if (!strcmp(jval, "a")) {
2235 else if (!strcmp(jval, "c")) {
2239 /* The buffer contains the bit on A that we should test */
2243 /* Z80 can do a conditional long jump */
2244 if (!strcmp(jval, "a")) {
2245 emitcode("or", "a,a");
2247 else if (!strcmp(jval, "c")) {
2250 emitcode("bit", "%s,a", jval);
2252 emit2("jp %s,!tlabel", inst, jlbl->key+100);
2254 /* mark the icode as generated */
2258 /** Generic compare for > or <
2260 static void genCmp (operand *left,operand *right,
2261 operand *result, iCode *ifx, int sign)
2263 int size, offset = 0 ;
2264 unsigned long lit = 0L;
2266 /* if left & right are bit variables */
2267 if (AOP_TYPE(left) == AOP_CRY &&
2268 AOP_TYPE(right) == AOP_CRY ) {
2269 /* Cant happen on the Z80 */
2272 /* subtract right from left if at the
2273 end the carry flag is set then we know that
2274 left is greater than right */
2275 size = max(AOP_SIZE(left),AOP_SIZE(right));
2277 /* if unsigned char cmp with lit, just compare */
2279 (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
2280 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2282 emit2("xor a,!immedbyte", 0x80);
2283 emit2("cp %s^!constbyte", aopGet(AOP(right), offset, FALSE), 0x80);
2286 emitcode("cp", "%s", aopGet(AOP(right), offset, FALSE));
2289 if(AOP_TYPE(right) == AOP_LIT) {
2290 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2291 /* optimize if(x < 0) or if(x >= 0) */
2294 /* No sign so it's always false */
2298 /* Just load in the top most bit */
2299 MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE));
2300 if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx) {
2301 genIfxJump (ifx,"7");
2305 emitcode("rlc","a");
2311 /* First setup h and l contaning the top most bytes XORed */
2312 bool fDidXor = FALSE;
2313 if (AOP_TYPE(left) == AOP_LIT){
2314 unsigned long lit = (unsigned long)
2315 floatFromVal(AOP(left)->aopu.aop_lit);
2316 emit2("ld %s,!immedbyte", _fTmp[0],
2317 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2320 emitcode("ld", "a,%s", aopGet(AOP(left), size-1, FALSE));
2321 emit2("xor a,!immedbyte", 0x80);
2322 emitcode("ld", "%s,a", _fTmp[0]);
2325 if (AOP_TYPE(right) == AOP_LIT) {
2326 unsigned long lit = (unsigned long)
2327 floatFromVal(AOP(right)->aopu.aop_lit);
2328 emit2("ld %s,!immedbyte", _fTmp[1],
2329 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2332 emitcode("ld", "a,%s", aopGet(AOP(right), size-1, FALSE));
2333 emit2("xor a,!immedbyte", 0x80);
2334 emitcode("ld", "%s,a", _fTmp[1]);
2344 /* Do a long subtract */
2345 if (!sign || size ) {
2346 MOVA(aopGet(AOP(left),offset,FALSE));
2348 if (sign && size == 0) {
2349 emitcode("ld", "a,%s", _fTmp[0]);
2350 emitcode("sbc", "a,%s", _fTmp[1]);
2353 /* Subtract through, propagating the carry */
2354 emitcode("sbc","a,%s ; 2",aopGet(AOP(right),offset++,FALSE));
2361 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2364 /* if the result is used in the next
2365 ifx conditional branch then generate
2366 code a little differently */
2368 genIfxJump (ifx,"c");
2371 /* leave the result in acc */
2375 /*-----------------------------------------------------------------*/
2376 /* genCmpGt :- greater than comparison */
2377 /*-----------------------------------------------------------------*/
2378 static void genCmpGt (iCode *ic, iCode *ifx)
2380 operand *left, *right, *result;
2381 link *letype , *retype;
2385 right= IC_RIGHT(ic);
2386 result = IC_RESULT(ic);
2388 letype = getSpec(operandType(left));
2389 retype =getSpec(operandType(right));
2390 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2391 /* assign the amsops */
2392 aopOp (left,ic,FALSE, FALSE);
2393 aopOp (right,ic,FALSE, FALSE);
2394 aopOp (result,ic,TRUE, FALSE);
2396 genCmp(right, left, result, ifx, sign);
2398 freeAsmop(left,NULL,ic);
2399 freeAsmop(right,NULL,ic);
2400 freeAsmop(result,NULL,ic);
2403 /*-----------------------------------------------------------------*/
2404 /* genCmpLt - less than comparisons */
2405 /*-----------------------------------------------------------------*/
2406 static void genCmpLt (iCode *ic, iCode *ifx)
2408 operand *left, *right, *result;
2409 link *letype , *retype;
2413 right= IC_RIGHT(ic);
2414 result = IC_RESULT(ic);
2416 letype = getSpec(operandType(left));
2417 retype =getSpec(operandType(right));
2418 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2420 /* assign the amsops */
2421 aopOp (left,ic,FALSE, FALSE);
2422 aopOp (right,ic,FALSE, FALSE);
2423 aopOp (result,ic,TRUE, FALSE);
2425 genCmp(left, right, result, ifx, sign);
2427 freeAsmop(left,NULL,ic);
2428 freeAsmop(right,NULL,ic);
2429 freeAsmop(result,NULL,ic);
2432 /*-----------------------------------------------------------------*/
2433 /* gencjneshort - compare and jump if not equal */
2434 /*-----------------------------------------------------------------*/
2435 static void gencjneshort(operand *left, operand *right, symbol *lbl)
2437 int size = max(AOP_SIZE(left),AOP_SIZE(right));
2439 unsigned long lit = 0L;
2441 /* Swap the left and right if it makes the computation easier */
2442 if (AOP_TYPE(left) == AOP_LIT) {
2448 if(AOP_TYPE(right) == AOP_LIT)
2449 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2451 /* if the right side is a literal then anything goes */
2452 if (AOP_TYPE(right) == AOP_LIT &&
2453 AOP_TYPE(left) != AOP_DIR ) {
2455 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2460 emitcode("or", "a,%s", aopGet(AOP(left), offset, FALSE));
2464 emitcode("or", "a,a");
2466 emit2("jp nz,!tlabel", lbl->key+100);
2470 emitcode("ld", "a,%s ; 2", aopGet(AOP(left),offset,FALSE));
2471 if ((AOP_TYPE(right) == AOP_LIT) && lit == 0)
2472 emitcode("or", "a,a");
2474 emitcode("cp", "a,%s", aopGet(AOP(right),offset,FALSE));
2475 emit2("jp nz,!tlabel", lbl->key+100);
2480 /* if the right side is in a register or in direct space or
2481 if the left is a pointer register & right is not */
2482 else if (AOP_TYPE(right) == AOP_REG ||
2483 AOP_TYPE(right) == AOP_DIR ||
2484 (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT)) {
2486 MOVA(aopGet(AOP(left),offset,FALSE));
2487 if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
2488 ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
2490 emit2("jp nz,!tlabel", lbl->key+100);
2492 emitcode("cp", "%s ; 4", aopGet(AOP(right),offset,FALSE));
2493 emit2("jp nz,!tlabel", lbl->key+100);
2498 /* right is a pointer reg need both a & b */
2499 /* PENDING: is this required? */
2501 MOVA(aopGet(AOP(right),offset,FALSE));
2502 emitcode("cp", "%s ; 5", aopGet(AOP(left), offset, FALSE));
2503 emit2("!shortjp nz,!tlabel", lbl->key+100);
2509 /*-----------------------------------------------------------------*/
2510 /* gencjne - compare and jump if not equal */
2511 /*-----------------------------------------------------------------*/
2512 static void gencjne(operand *left, operand *right, symbol *lbl)
2514 symbol *tlbl = newiTempLabel(NULL);
2516 gencjneshort(left, right, lbl);
2520 emit2("!shortjp !tlabel", tlbl->key+100);
2521 emitLabel(lbl->key+100);
2522 emitcode("xor","a,a");
2523 emitLabel(tlbl->key+100);
2526 /*-----------------------------------------------------------------*/
2527 /* genCmpEq - generates code for equal to */
2528 /*-----------------------------------------------------------------*/
2529 static void genCmpEq (iCode *ic, iCode *ifx)
2531 operand *left, *right, *result;
2533 aopOp((left=IC_LEFT(ic)),ic,FALSE, FALSE);
2534 aopOp((right=IC_RIGHT(ic)),ic,FALSE, FALSE);
2535 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2537 /* Swap operands if it makes the operation easier. ie if:
2538 1. Left is a literal.
2540 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
2541 operand *t = IC_RIGHT(ic);
2542 IC_RIGHT(ic) = IC_LEFT(ic);
2546 if (ifx && !AOP_SIZE(result)){
2548 /* if they are both bit variables */
2549 if (AOP_TYPE(left) == AOP_CRY &&
2550 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2553 tlbl = newiTempLabel(NULL);
2554 gencjneshort(left, right, tlbl);
2555 if ( IC_TRUE(ifx) ) {
2556 emit2("jp !tlabel", IC_TRUE(ifx)->key+100);
2557 emitLabel(tlbl->key+100);
2559 /* PENDING: do this better */
2560 symbol *lbl = newiTempLabel(NULL);
2561 emit2("!shortjp !tlabel", lbl->key+100);
2562 emitLabel(tlbl->key+100);
2563 emit2("jp !tlabel", IC_FALSE(ifx)->key+100);
2564 emitLabel(lbl->key+100);
2567 /* mark the icode as generated */
2572 /* if they are both bit variables */
2573 if (AOP_TYPE(left) == AOP_CRY &&
2574 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2577 gencjne(left,right,newiTempLabel(NULL));
2578 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2582 genIfxJump(ifx,"a");
2585 /* if the result is used in an arithmetic operation
2586 then put the result in place */
2587 if (AOP_TYPE(result) != AOP_CRY) {
2590 /* leave the result in acc */
2594 freeAsmop(left,NULL,ic);
2595 freeAsmop(right,NULL,ic);
2596 freeAsmop(result,NULL,ic);
2599 /*-----------------------------------------------------------------*/
2600 /* ifxForOp - returns the icode containing the ifx for operand */
2601 /*-----------------------------------------------------------------*/
2602 static iCode *ifxForOp ( operand *op, iCode *ic )
2604 /* if true symbol then needs to be assigned */
2605 if (IS_TRUE_SYMOP(op))
2608 /* if this has register type condition and
2609 the next instruction is ifx with the same operand
2610 and live to of the operand is upto the ifx only then */
2612 ic->next->op == IFX &&
2613 IC_COND(ic->next)->key == op->key &&
2614 OP_SYMBOL(op)->liveTo <= ic->next->seq )
2620 /*-----------------------------------------------------------------*/
2621 /* genAndOp - for && operation */
2622 /*-----------------------------------------------------------------*/
2623 static void genAndOp (iCode *ic)
2625 operand *left,*right, *result;
2628 /* note here that && operations that are in an if statement are
2629 taken away by backPatchLabels only those used in arthmetic
2630 operations remain */
2631 aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2632 aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2633 aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2635 /* if both are bit variables */
2636 if (AOP_TYPE(left) == AOP_CRY &&
2637 AOP_TYPE(right) == AOP_CRY ) {
2640 tlbl = newiTempLabel(NULL);
2642 emit2("!shortjp z,!tlabel", tlbl->key+100);
2644 emitLabel(tlbl->key+100);
2648 freeAsmop(left,NULL,ic);
2649 freeAsmop(right,NULL,ic);
2650 freeAsmop(result,NULL,ic);
2653 /*-----------------------------------------------------------------*/
2654 /* genOrOp - for || operation */
2655 /*-----------------------------------------------------------------*/
2656 static void genOrOp (iCode *ic)
2658 operand *left,*right, *result;
2661 /* note here that || operations that are in an
2662 if statement are taken away by backPatchLabels
2663 only those used in arthmetic operations remain */
2664 aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2665 aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2666 aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2668 /* if both are bit variables */
2669 if (AOP_TYPE(left) == AOP_CRY &&
2670 AOP_TYPE(right) == AOP_CRY ) {
2673 tlbl = newiTempLabel(NULL);
2675 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2677 emitLabel(tlbl->key+100);
2681 freeAsmop(left,NULL,ic);
2682 freeAsmop(right,NULL,ic);
2683 freeAsmop(result,NULL,ic);
2686 /*-----------------------------------------------------------------*/
2687 /* isLiteralBit - test if lit == 2^n */
2688 /*-----------------------------------------------------------------*/
2689 int isLiteralBit(unsigned long lit)
2691 unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
2692 0x100L,0x200L,0x400L,0x800L,
2693 0x1000L,0x2000L,0x4000L,0x8000L,
2694 0x10000L,0x20000L,0x40000L,0x80000L,
2695 0x100000L,0x200000L,0x400000L,0x800000L,
2696 0x1000000L,0x2000000L,0x4000000L,0x8000000L,
2697 0x10000000L,0x20000000L,0x40000000L,0x80000000L};
2700 for(idx = 0; idx < 32; idx++)
2706 /*-----------------------------------------------------------------*/
2707 /* jmpTrueOrFalse - */
2708 /*-----------------------------------------------------------------*/
2709 static void jmpTrueOrFalse (iCode *ic, symbol *tlbl)
2711 // ugly but optimized by peephole
2713 symbol *nlbl = newiTempLabel(NULL);
2714 emit2("jp !tlabel", nlbl->key+100);
2715 emitLabel(tlbl->key+100);
2716 emit2("jp !tlabel", IC_TRUE(ic)->key+100);
2717 emitLabel(nlbl->key+100);
2720 emit2("jp !tlabel", IC_FALSE(ic)->key+100);
2721 emitLabel(tlbl->key+100);
2726 /*-----------------------------------------------------------------*/
2727 /* genAnd - code for and */
2728 /*-----------------------------------------------------------------*/
2729 static void genAnd (iCode *ic, iCode *ifx)
2731 operand *left, *right, *result;
2733 unsigned long lit = 0L;
2736 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
2737 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
2738 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2741 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2743 AOP_TYPE(left), AOP_TYPE(right));
2744 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2746 AOP_SIZE(left), AOP_SIZE(right));
2749 /* if left is a literal & right is not then exchange them */
2750 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2751 AOP_NEEDSACC(left)) {
2752 operand *tmp = right ;
2757 /* if result = right then exchange them */
2758 if(sameRegs(AOP(result),AOP(right))){
2759 operand *tmp = right ;
2764 /* if right is bit then exchange them */
2765 if (AOP_TYPE(right) == AOP_CRY &&
2766 AOP_TYPE(left) != AOP_CRY){
2767 operand *tmp = right ;
2771 if(AOP_TYPE(right) == AOP_LIT)
2772 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2774 size = AOP_SIZE(result);
2776 if (AOP_TYPE(left) == AOP_CRY){
2781 // if(val & 0xZZ) - size = 0, ifx != FALSE -
2782 // bit = val & 0xZZ - size = 1, ifx = FALSE -
2783 if((AOP_TYPE(right) == AOP_LIT) &&
2784 (AOP_TYPE(result) == AOP_CRY) &&
2785 (AOP_TYPE(left) != AOP_CRY)) {
2786 int posbit = isLiteralBit(lit);
2790 MOVA(aopGet(AOP(left),posbit>>3,FALSE));
2794 emitcode("mov","c,acc.%d",posbit&0x07);
2799 sprintf(buffer, "%d", posbit&0x07);
2800 genIfxJump(ifx, buffer);
2808 symbol *tlbl = newiTempLabel(NULL);
2809 int sizel = AOP_SIZE(left);
2812 emitcode("setb","c");
2815 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
2816 MOVA( aopGet(AOP(left),offset,FALSE));
2818 if((posbit = isLiteralBit(bytelit)) != 0) {
2820 emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
2823 if(bytelit != 0x0FFL)
2824 emitcode("and","a,%s",
2825 aopGet(AOP(right),offset,FALSE));
2829 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2834 // bit = left & literal
2836 emitcode("clr","c");
2837 emit2("!tlabeldef", tlbl->key+100);
2839 // if(left & literal)
2842 jmpTrueOrFalse(ifx, tlbl);
2850 /* if left is same as result */
2851 if(sameRegs(AOP(result),AOP(left))){
2852 for(;size--; offset++) {
2853 if(AOP_TYPE(right) == AOP_LIT){
2854 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
2858 aopPut(AOP(result),zero,offset);
2860 MOVA(aopGet(AOP(left),offset,FALSE));
2861 emitcode("and","a,%s",
2862 aopGet(AOP(right),offset,FALSE));
2863 aopPut(AOP(left), "a", offset);
2868 if (AOP_TYPE(left) == AOP_ACC) {
2872 MOVA(aopGet(AOP(left),offset,FALSE));
2873 emitcode("and","a,%s",
2874 aopGet(AOP(right),offset,FALSE));
2875 aopPut(AOP(left), "a", offset);
2880 // left & result in different registers
2881 if(AOP_TYPE(result) == AOP_CRY){
2884 for(;(size--);offset++) {
2886 // result = left & right
2887 if(AOP_TYPE(right) == AOP_LIT){
2888 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
2890 aopGet(AOP(left),offset,FALSE),
2893 } else if(bytelit == 0){
2894 aopPut(AOP(result),zero,offset);
2898 // faster than result <- left, anl result,right
2899 // and better if result is SFR
2900 if (AOP_TYPE(left) == AOP_ACC)
2901 emitcode("and","a,%s",aopGet(AOP(right),offset,FALSE));
2903 MOVA(aopGet(AOP(left),offset,FALSE));
2904 emitcode("and","a,%s",
2905 aopGet(AOP(right),offset,FALSE));
2907 aopPut(AOP(result),"a",offset);
2914 freeAsmop(left,NULL,ic);
2915 freeAsmop(right,NULL,ic);
2916 freeAsmop(result,NULL,ic);
2919 /*-----------------------------------------------------------------*/
2920 /* genOr - code for or */
2921 /*-----------------------------------------------------------------*/
2922 static void genOr (iCode *ic, iCode *ifx)
2924 operand *left, *right, *result;
2926 unsigned long lit = 0L;
2928 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
2929 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
2930 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2933 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2935 AOP_TYPE(left), AOP_TYPE(right));
2936 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2938 AOP_SIZE(left), AOP_SIZE(right));
2941 /* if left is a literal & right is not then exchange them */
2942 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2943 AOP_NEEDSACC(left)) {
2944 operand *tmp = right ;
2949 /* if result = right then exchange them */
2950 if(sameRegs(AOP(result),AOP(right))){
2951 operand *tmp = right ;
2956 /* if right is bit then exchange them */
2957 if (AOP_TYPE(right) == AOP_CRY &&
2958 AOP_TYPE(left) != AOP_CRY){
2959 operand *tmp = right ;
2963 if(AOP_TYPE(right) == AOP_LIT)
2964 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2966 size = AOP_SIZE(result);
2968 if (AOP_TYPE(left) == AOP_CRY){
2973 if((AOP_TYPE(right) == AOP_LIT) &&
2974 (AOP_TYPE(result) == AOP_CRY) &&
2975 (AOP_TYPE(left) != AOP_CRY)){
2980 /* if left is same as result */
2981 if(sameRegs(AOP(result),AOP(left))){
2982 for(;size--; offset++) {
2983 if(AOP_TYPE(right) == AOP_LIT){
2984 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
2987 MOVA(aopGet(AOP(left),offset,FALSE));
2988 emitcode("or","a,%s",
2989 aopGet(AOP(right),offset,FALSE));
2990 aopPut(AOP(result),"a", offset);
2993 if (AOP_TYPE(left) == AOP_ACC)
2994 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
2996 MOVA(aopGet(AOP(left),offset,FALSE));
2997 emitcode("or","a,%s",
2998 aopGet(AOP(right),offset,FALSE));
2999 aopPut(AOP(result),"a", offset);
3004 // left & result in different registers
3005 if(AOP_TYPE(result) == AOP_CRY){
3007 } else for(;(size--);offset++){
3009 // result = left & right
3010 if(AOP_TYPE(right) == AOP_LIT){
3011 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3013 aopGet(AOP(left),offset,FALSE),
3018 // faster than result <- left, anl result,right
3019 // and better if result is SFR
3020 if (AOP_TYPE(left) == AOP_ACC)
3021 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
3023 MOVA(aopGet(AOP(left),offset,FALSE));
3024 emitcode("or","a,%s",
3025 aopGet(AOP(right),offset,FALSE));
3027 aopPut(AOP(result),"a",offset);
3028 /* PENDING: something weird is going on here. Add exception. */
3029 if (AOP_TYPE(result) == AOP_ACC)
3035 freeAsmop(left,NULL,ic);
3036 freeAsmop(right,NULL,ic);
3037 freeAsmop(result,NULL,ic);
3040 /*-----------------------------------------------------------------*/
3041 /* genXor - code for xclusive or */
3042 /*-----------------------------------------------------------------*/
3043 static void genXor (iCode *ic, iCode *ifx)
3045 operand *left, *right, *result;
3047 unsigned long lit = 0L;
3049 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3050 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3051 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3053 /* if left is a literal & right is not then exchange them */
3054 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3055 AOP_NEEDSACC(left)) {
3056 operand *tmp = right ;
3061 /* if result = right then exchange them */
3062 if(sameRegs(AOP(result),AOP(right))){
3063 operand *tmp = right ;
3068 /* if right is bit then exchange them */
3069 if (AOP_TYPE(right) == AOP_CRY &&
3070 AOP_TYPE(left) != AOP_CRY){
3071 operand *tmp = right ;
3075 if(AOP_TYPE(right) == AOP_LIT)
3076 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3078 size = AOP_SIZE(result);
3080 if (AOP_TYPE(left) == AOP_CRY){
3085 if((AOP_TYPE(right) == AOP_LIT) &&
3086 (AOP_TYPE(result) == AOP_CRY) &&
3087 (AOP_TYPE(left) != AOP_CRY)){
3092 /* if left is same as result */
3093 if(sameRegs(AOP(result),AOP(left))){
3094 for(;size--; offset++) {
3095 if(AOP_TYPE(right) == AOP_LIT){
3096 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3099 MOVA(aopGet(AOP(right),offset,FALSE));
3100 emitcode("xor","a,%s",
3101 aopGet(AOP(left),offset,FALSE));
3102 aopPut(AOP(result),"a",0);
3105 if (AOP_TYPE(left) == AOP_ACC)
3106 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3108 MOVA(aopGet(AOP(right),offset,FALSE));
3109 emitcode("xor","a,%s",
3110 aopGet(AOP(left),offset,FALSE));
3111 aopPut(AOP(result),"a",0);
3116 // left & result in different registers
3117 if(AOP_TYPE(result) == AOP_CRY){
3119 } else for(;(size--);offset++){
3121 // result = left & right
3122 if(AOP_TYPE(right) == AOP_LIT){
3123 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3125 aopGet(AOP(left),offset,FALSE),
3130 // faster than result <- left, anl result,right
3131 // and better if result is SFR
3132 if (AOP_TYPE(left) == AOP_ACC)
3133 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3135 MOVA(aopGet(AOP(right),offset,FALSE));
3136 emitcode("xor","a,%s",
3137 aopGet(AOP(left),offset,FALSE));
3138 aopPut(AOP(result),"a",0);
3140 aopPut(AOP(result),"a",offset);
3145 freeAsmop(left,NULL,ic);
3146 freeAsmop(right,NULL,ic);
3147 freeAsmop(result,NULL,ic);
3150 /*-----------------------------------------------------------------*/
3151 /* genInline - write the inline code out */
3152 /*-----------------------------------------------------------------*/
3153 static void genInline (iCode *ic)
3155 char buffer[MAX_INLINEASM];
3159 inLine += (!options.asmpeep);
3160 strcpy(buffer,IC_INLINE(ic));
3162 /* emit each line as a code */
3181 /* emitcode("",buffer); */
3182 inLine -= (!options.asmpeep);
3185 /*-----------------------------------------------------------------*/
3186 /* genRRC - rotate right with carry */
3187 /*-----------------------------------------------------------------*/
3188 static void genRRC (iCode *ic)
3193 /*-----------------------------------------------------------------*/
3194 /* genRLC - generate code for rotate left with carry */
3195 /*-----------------------------------------------------------------*/
3196 static void genRLC (iCode *ic)
3201 /*-----------------------------------------------------------------*/
3202 /* shiftR2Left2Result - shift right two bytes from left to result */
3203 /*-----------------------------------------------------------------*/
3204 static void shiftR2Left2Result (operand *left, int offl,
3205 operand *result, int offr,
3206 int shCount, int sign)
3208 movLeft2Result(left, offl, result, offr, 0);
3209 movLeft2Result(left, offl+1, result, offr+1, 0);
3215 /* 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");
3233 l = aopGet(AOP(result), --offset, FALSE);
3234 emitcode("rr","%s", l);
3237 emitLabel(tlbl1->key+100);
3238 emitcode("dec", "a");
3239 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3244 /*-----------------------------------------------------------------*/
3245 /* shiftL2Left2Result - shift left two bytes from left to result */
3246 /*-----------------------------------------------------------------*/
3247 static void shiftL2Left2Result (operand *left, int offl,
3248 operand *result, int offr, int shCount)
3250 if(sameRegs(AOP(result), AOP(left)) &&
3251 ((offl + MSB16) == offr)){
3254 /* Copy left into result */
3255 movLeft2Result(left, offl, result, offr, 0);
3256 movLeft2Result(left, offl+1, result, offr+1, 0);
3258 /* PENDING: for now just see if it'll work. */
3259 /*if (AOP(result)->type == AOP_REG) { */
3263 symbol *tlbl , *tlbl1;
3266 /* Left is already in result - so now do the shift */
3268 emit2("ld a,!immedbyte+1", shCount);
3269 tlbl = newiTempLabel(NULL);
3270 tlbl1 = newiTempLabel(NULL);
3271 emit2("!shortjp !tlabel", tlbl1->key+100);
3272 emitLabel(tlbl->key+100);
3275 emitcode("or", "a,a");
3277 l = aopGet(AOP(result),offset++,FALSE);
3278 emitcode("rl","%s", l);
3281 emitLabel(tlbl1->key+100);
3282 emitcode("dec", "a");
3283 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3288 /*-----------------------------------------------------------------*/
3289 /* AccRol - rotate left accumulator by known count */
3290 /*-----------------------------------------------------------------*/
3291 static void AccRol (int shCount)
3293 shCount &= 0x0007; // shCount : 0..7
3330 /*-----------------------------------------------------------------*/
3331 /* AccLsh - left shift accumulator by known count */
3332 /*-----------------------------------------------------------------*/
3333 static void AccLsh (int shCount)
3337 emitcode("add","a,a");
3340 emitcode("add","a,a");
3341 emitcode("add","a,a");
3343 /* rotate left accumulator */
3345 /* and kill the lower order bits */
3346 emit2("and a,!immedbyte", SLMask[shCount]);
3351 /*-----------------------------------------------------------------*/
3352 /* shiftL1Left2Result - shift left one byte from left to result */
3353 /*-----------------------------------------------------------------*/
3354 static void shiftL1Left2Result (operand *left, int offl,
3355 operand *result, int offr, int shCount)
3358 l = aopGet(AOP(left),offl,FALSE);
3360 /* shift left accumulator */
3362 aopPut(AOP(result),"a",offr);
3366 /*-----------------------------------------------------------------*/
3367 /* genlshTwo - left shift two bytes by known amount != 0 */
3368 /*-----------------------------------------------------------------*/
3369 static void genlshTwo (operand *result,operand *left, int shCount)
3371 int size = AOP_SIZE(result);
3375 /* if shCount >= 8 */
3381 movLeft2Result(left, LSB, result, MSB16, 0);
3382 aopPut(AOP(result),zero, 0);
3383 shiftL1Left2Result(left, MSB16, result, MSB16, shCount-8);
3386 movLeft2Result(left, LSB, result, MSB16, 0);
3387 aopPut(AOP(result),zero, 0);
3390 aopPut(AOP(result),zero,LSB);
3392 /* 1 <= shCount <= 7 */
3398 shiftL2Left2Result(left, LSB, result, LSB, shCount);
3403 /*-----------------------------------------------------------------*/
3404 /* genlshOne - left shift a one byte quantity by known count */
3405 /*-----------------------------------------------------------------*/
3406 static void genlshOne (operand *result, operand *left, int shCount)
3408 shiftL1Left2Result(left, LSB, result, LSB, shCount);
3411 /*-----------------------------------------------------------------*/
3412 /* genLeftShiftLiteral - left shifting by known count */
3413 /*-----------------------------------------------------------------*/
3414 static void genLeftShiftLiteral (operand *left,
3419 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3422 freeAsmop(right,NULL,ic);
3424 aopOp(left,ic,FALSE, FALSE);
3425 aopOp(result,ic,FALSE, FALSE);
3427 size = getSize(operandType(result));
3430 emitcode("; shift left ","result %d, left %d",size,
3434 /* I suppose that the left size >= result size */
3439 else if(shCount >= (size * 8))
3441 aopPut(AOP(result),zero,size);
3445 genlshOne (result,left,shCount);
3448 genlshTwo (result,left,shCount);
3457 freeAsmop(left,NULL,ic);
3458 freeAsmop(result,NULL,ic);
3461 /*-----------------------------------------------------------------*/
3462 /* genLeftShift - generates code for left shifting */
3463 /*-----------------------------------------------------------------*/
3464 static void genLeftShift (iCode *ic)
3468 symbol *tlbl , *tlbl1;
3469 operand *left,*right, *result;
3471 right = IC_RIGHT(ic);
3473 result = IC_RESULT(ic);
3475 aopOp(right,ic,FALSE, FALSE);
3477 /* if the shift count is known then do it
3478 as efficiently as possible */
3479 if (AOP_TYPE(right) == AOP_LIT) {
3480 genLeftShiftLiteral (left,right,result,ic);
3484 /* shift count is unknown then we have to form a loop get the loop
3485 count in B : Note: we take only the lower order byte since
3486 shifting more that 32 bits make no sense anyway, ( the largest
3487 size of an object can be only 32 bits ) */
3488 emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE));
3489 emitcode("inc","a");
3490 freeAsmop (right,NULL,ic);
3491 aopOp(left,ic,FALSE, FALSE);
3492 aopOp(result,ic,FALSE, FALSE);
3494 /* now move the left to the result if they are not the
3497 if (!sameRegs(AOP(left),AOP(result))) {
3499 size = AOP_SIZE(result);
3502 l = aopGet(AOP(left),offset,FALSE);
3503 aopPut(AOP(result),l,offset);
3508 size = AOP_SIZE(result);
3511 l = aopGet(AOP(left),offset,FALSE);
3512 aopPut(AOP(result),l,offset);
3518 tlbl = newiTempLabel(NULL);
3519 size = AOP_SIZE(result);
3521 tlbl1 = newiTempLabel(NULL);
3523 emit2("!shortjp !tlabel", tlbl1->key+100);
3524 emitLabel(tlbl->key+100);
3525 l = aopGet(AOP(result),offset,FALSE);
3526 emitcode("or", "a,a");
3528 l = aopGet(AOP(result),offset++,FALSE);
3529 emitcode("rl","%s", l);
3531 emitLabel(tlbl1->key+100);
3532 emitcode("dec", "a");
3533 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3535 freeAsmop(left,NULL,ic);
3536 freeAsmop(result,NULL,ic);
3539 /*-----------------------------------------------------------------*/
3540 /* genlshTwo - left shift two bytes by known amount != 0 */
3541 /*-----------------------------------------------------------------*/
3542 static void genrshOne (operand *result,operand *left, int shCount)
3545 int size = AOP_SIZE(result);
3551 l = aopGet(AOP(left),0,FALSE);
3552 if (AOP(result)->type == AOP_REG) {
3553 aopPut(AOP(result), l, 0);
3554 l = aopGet(AOP(result), 0, FALSE);
3556 emitcode("srl", "%s", l);
3561 emitcode("srl", "a");
3563 aopPut(AOP(result),"a",0);
3567 /*-----------------------------------------------------------------*/
3568 /* AccRsh - right shift accumulator by known count */
3569 /*-----------------------------------------------------------------*/
3570 static void AccRsh (int shCount)
3577 /* rotate right accumulator */
3578 AccRol(8 - shCount);
3579 /* and kill the higher order bits */
3580 emit2("and a,!immedbyte", SRMask[shCount]);
3585 /*-----------------------------------------------------------------*/
3586 /* shiftR1Left2Result - shift right one byte from left to result */
3587 /*-----------------------------------------------------------------*/
3588 static void shiftR1Left2Result (operand *left, int offl,
3589 operand *result, int offr,
3590 int shCount, int sign)
3592 MOVA(aopGet(AOP(left),offl,FALSE));
3599 aopPut(AOP(result),"a",offr);
3602 /*-----------------------------------------------------------------*/
3603 /* genrshTwo - right shift two bytes by known amount != 0 */
3604 /*-----------------------------------------------------------------*/
3605 static void genrshTwo (operand *result,operand *left,
3606 int shCount, int sign)
3608 /* if shCount >= 8 */
3612 shiftR1Left2Result(left, MSB16, result, LSB,
3616 movLeft2Result(left, MSB16, result, LSB, sign);
3617 aopPut(AOP(result),zero,1);
3620 /* 1 <= shCount <= 7 */
3622 shiftR2Left2Result(left, LSB, result, LSB, shCount, sign);
3626 /*-----------------------------------------------------------------*/
3627 /* genRightShiftLiteral - left shifting by known count */
3628 /*-----------------------------------------------------------------*/
3629 static void genRightShiftLiteral (operand *left,
3634 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3637 freeAsmop(right,NULL,ic);
3639 aopOp(left,ic,FALSE, FALSE);
3640 aopOp(result,ic,FALSE, FALSE);
3642 size = getSize(operandType(result));
3644 emitcode("; shift right ","result %d, left %d",size,
3647 /* I suppose that the left size >= result size */
3652 else if(shCount >= (size * 8))
3654 aopPut(AOP(result),zero,size);
3658 genrshOne(result, left, shCount);
3661 /* PENDING: sign support */
3662 genrshTwo(result, left, shCount, FALSE);
3671 freeAsmop(left,NULL,ic);
3672 freeAsmop(result,NULL,ic);
3675 /*-----------------------------------------------------------------*/
3676 /* genRightShift - generate code for right shifting */
3677 /*-----------------------------------------------------------------*/
3678 static void genRightShift (iCode *ic)
3680 operand *right, *left, *result;
3682 int size, offset, first = 1;
3686 symbol *tlbl, *tlbl1 ;
3688 /* if signed then we do it the hard way preserve the
3689 sign bit moving it inwards */
3690 retype = getSpec(operandType(IC_RESULT(ic)));
3692 is_signed = !SPEC_USIGN(retype);
3694 /* signed & unsigned types are treated the same : i.e. the
3695 signed is NOT propagated inwards : quoting from the
3696 ANSI - standard : "for E1 >> E2, is equivalent to division
3697 by 2**E2 if unsigned or if it has a non-negative value,
3698 otherwise the result is implementation defined ", MY definition
3699 is that the sign does not get propagated */
3701 right = IC_RIGHT(ic);
3703 result = IC_RESULT(ic);
3705 aopOp(right,ic,FALSE, FALSE);
3707 /* if the shift count is known then do it
3708 as efficiently as possible */
3709 if (AOP_TYPE(right) == AOP_LIT) {
3710 genRightShiftLiteral(left,right,result,ic);
3714 aopOp(left,ic,FALSE, FALSE);
3715 aopOp(result,ic,FALSE, FALSE);
3717 /* now move the left to the result if they are not the
3719 if (!sameRegs(AOP(left),AOP(result)) &&
3720 AOP_SIZE(result) > 1) {
3722 size = AOP_SIZE(result);
3725 l = aopGet(AOP(left),offset,FALSE);
3726 aopPut(AOP(result),l,offset);
3731 emitcode("ld", "a,%s",aopGet(AOP(right),0,FALSE));
3732 emitcode("inc","a");
3733 freeAsmop (right, NULL, ic);
3735 tlbl = newiTempLabel(NULL);
3736 tlbl1= newiTempLabel(NULL);
3737 size = AOP_SIZE(result);
3740 emit2("!shortjp !tlabel", tlbl1->key+100);
3741 emitLabel(tlbl->key+100);
3743 l = aopGet(AOP(result),offset--,FALSE);
3746 emitcode("sra", "%s", l);
3748 emitcode("srl", "%s", l);
3752 emitcode("rr", "%s", l);
3754 emitLabel(tlbl1->key+100);
3755 emitcode("dec", "a");
3756 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3758 freeAsmop(left,NULL,ic);
3759 freeAsmop(result,NULL,ic);
3762 /*-----------------------------------------------------------------*/
3763 /* genGenPointerGet - gget value from generic pointer space */
3764 /*-----------------------------------------------------------------*/
3765 static void genGenPointerGet (operand *left,
3766 operand *result, iCode *ic)
3769 link *retype = getSpec(operandType(result));
3775 aopOp(left,ic,FALSE, FALSE);
3776 aopOp(result,ic,FALSE, FALSE);
3778 if (isPair(AOP(left)) && AOP_SIZE(result)==1) {
3780 if (isPtrPair(AOP(left)))
3782 tsprintf(buffer, "!*pair", getPairName(AOP(left)));
3783 aopPut(AOP(result), buffer, 0);
3786 emit2("ld a,!*pair", getPairName(AOP(left)));
3787 aopPut(AOP(result),"a", 0);
3789 freeAsmop(left,NULL,ic);
3793 /* For now we always load into IY */
3794 /* if this is remateriazable */
3795 fetchPair(pair, AOP(left));
3797 /* so iy now contains the address */
3798 freeAsmop(left,NULL,ic);
3800 /* if bit then unpack */
3801 if (IS_BITVAR(retype)) {
3805 size = AOP_SIZE(result);
3809 /* PENDING: make this better */
3810 if (!IS_GB && AOP(result)->type == AOP_REG) {
3811 aopPut(AOP(result), "!*hl", offset++);
3814 emit2("ld a,!*pair", _pairs[pair].name);
3815 aopPut(AOP(result),"a",offset++);
3818 emit2("inc %s", _pairs[pair].name);
3824 freeAsmop(result,NULL,ic);
3827 /*-----------------------------------------------------------------*/
3828 /* genPointerGet - generate code for pointer get */
3829 /*-----------------------------------------------------------------*/
3830 static void genPointerGet (iCode *ic)
3832 operand *left, *result ;
3836 result = IC_RESULT(ic) ;
3838 /* depending on the type of pointer we need to
3839 move it to the correct pointer register */
3840 type = operandType(left);
3841 etype = getSpec(type);
3843 genGenPointerGet (left,result,ic);
3846 bool isRegOrLit(asmop *aop)
3848 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
3853 /*-----------------------------------------------------------------*/
3854 /* genGenPointerSet - stores the value into a pointer location */
3855 /*-----------------------------------------------------------------*/
3856 static void genGenPointerSet (operand *right,
3857 operand *result, iCode *ic)
3860 link *retype = getSpec(operandType(right));
3861 PAIR_ID pairId = PAIR_HL;
3863 aopOp(result,ic,FALSE, FALSE);
3864 aopOp(right,ic,FALSE, FALSE);
3869 /* Handle the exceptions first */
3870 if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
3872 char *l = aopGet(AOP(right), 0, FALSE);
3873 const char *pair = getPairName(AOP(result));
3874 if (canAssignToPtr(l) && isPtr(pair)) {
3875 emit2("ld !*pair,%s", pair, l);
3879 emit2("ld !*pair,a", pair);
3884 /* if the operand is already in dptr
3885 then we do nothing else we move the value to dptr */
3886 if (AOP_TYPE(result) != AOP_STR) {
3887 fetchPair(pairId, AOP(result));
3889 /* so hl know contains the address */
3890 freeAsmop(result,NULL,ic);
3892 /* if bit then unpack */
3893 if (IS_BITVAR(retype)) {
3897 size = AOP_SIZE(right);
3901 char *l = aopGet(AOP(right),offset,FALSE);
3902 if (isRegOrLit(AOP(right)) && !IS_GB) {
3903 emit2("ld !*pair,%s", _pairs[pairId].name, l);
3907 emit2("ld !*pair,a", _pairs[pairId].name);
3910 emitcode("inc", _pairs[pairId].name);
3916 freeAsmop(right,NULL,ic);
3919 /*-----------------------------------------------------------------*/
3920 /* genPointerSet - stores the value into a pointer location */
3921 /*-----------------------------------------------------------------*/
3922 static void genPointerSet (iCode *ic)
3924 operand *right, *result ;
3927 right = IC_RIGHT(ic);
3928 result = IC_RESULT(ic) ;
3930 /* depending on the type of pointer we need to
3931 move it to the correct pointer register */
3932 type = operandType(result);
3933 etype = getSpec(type);
3935 genGenPointerSet (right,result,ic);
3938 /*-----------------------------------------------------------------*/
3939 /* genIfx - generate code for Ifx statement */
3940 /*-----------------------------------------------------------------*/
3941 static void genIfx (iCode *ic, iCode *popIc)
3943 operand *cond = IC_COND(ic);
3946 aopOp(cond,ic,FALSE, TRUE);
3948 /* get the value into acc */
3949 if (AOP_TYPE(cond) != AOP_CRY)
3953 /* the result is now in the accumulator */
3954 freeAsmop(cond,NULL,ic);
3956 /* if there was something to be popped then do it */
3960 /* if the condition is a bit variable */
3961 if (isbit && IS_ITEMP(cond) &&
3963 genIfxJump(ic,SPIL_LOC(cond)->rname);
3965 if (isbit && !IS_ITEMP(cond))
3966 genIfxJump(ic,OP_SYMBOL(cond)->rname);
3973 /*-----------------------------------------------------------------*/
3974 /* genAddrOf - generates code for address of */
3975 /*-----------------------------------------------------------------*/
3976 static void genAddrOf (iCode *ic)
3978 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
3980 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
3982 /* if the operand is on the stack then we
3983 need to get the stack offset of this
3988 emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
3989 emitcode("ld", "d,h");
3990 emitcode("ld", "e,l");
3993 emitcode("ld", "de,#%s", sym->rname);
3995 aopPut(AOP(IC_RESULT(ic)), "e", 0);
3996 aopPut(AOP(IC_RESULT(ic)), "d", 1);
4001 /* if it has an offset then we need to compute it */
4002 emitcode("ld", "hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
4003 emitcode("add", "hl,sp");
4006 emitcode("ld", "hl,#%s", sym->rname);
4008 aopPut(AOP(IC_RESULT(ic)), "l", 0);
4009 aopPut(AOP(IC_RESULT(ic)), "h", 1);
4011 freeAsmop(IC_RESULT(ic),NULL,ic);
4014 /*-----------------------------------------------------------------*/
4015 /* genAssign - generate code for assignment */
4016 /*-----------------------------------------------------------------*/
4017 static void genAssign (iCode *ic)
4019 operand *result, *right;
4021 unsigned long lit = 0L;
4023 result = IC_RESULT(ic);
4024 right = IC_RIGHT(ic) ;
4027 /* Dont bother assigning if they are the same */
4028 if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) {
4029 emitcode("", "; (operands are equal %u)", operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)));
4034 aopOp(right,ic,FALSE, FALSE);
4035 aopOp(result,ic,TRUE, FALSE);
4037 /* if they are the same registers */
4038 if (sameRegs(AOP(right),AOP(result))) {
4039 emitcode("", "; (registers are the same)");
4043 /* if the result is a bit */
4044 if (AOP_TYPE(result) == AOP_CRY) {
4049 size = AOP_SIZE(result);
4052 if(AOP_TYPE(right) == AOP_LIT)
4053 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
4054 if (isPair(AOP(result))) {
4055 fetchPair(getPairId(AOP(result)), AOP(right));
4057 else if((size > 1) &&
4058 (AOP_TYPE(result) != AOP_REG) &&
4059 (AOP_TYPE(right) == AOP_LIT) &&
4060 !IS_FLOAT(operandType(right)) &&
4062 bool fXored = FALSE;
4064 /* Work from the top down.
4065 Done this way so that we can use the cached copy of 0
4066 in A for a fast clear */
4068 if((unsigned int)((lit >> (offset*8)) & 0x0FFL)== 0) {
4069 if (!fXored && size>1) {
4070 emitcode("xor", "a,a");
4074 aopPut(AOP(result),"a",offset);
4077 aopPut(AOP(result), zero, offset);
4082 aopGet(AOP(right),offset,FALSE),
4087 else if (size == 2 && requiresHL(AOP(right)) && requiresHL(AOP(result)) && IS_GB) {
4088 /* Special case. Load into a and d, then load out. */
4089 MOVA(aopGet(AOP(right), 0, FALSE));
4090 emitcode("ld", "e,%s", aopGet(AOP(right), 1, FALSE));
4091 aopPut(AOP(result), "a", 0);
4092 aopPut(AOP(result), "e", 1);
4095 /* PENDING: do this check better */
4096 if (requiresHL(AOP(right)) && requiresHL(AOP(result))) {
4097 MOVA(aopGet(AOP(right), offset, FALSE));
4098 aopPut(AOP(result), "a", offset);
4102 aopGet(AOP(right),offset,FALSE),
4109 freeAsmop(right,NULL,ic);
4110 freeAsmop(result,NULL,ic);
4113 /*-----------------------------------------------------------------*/
4114 /* genJumpTab - genrates code for jump table */
4115 /*-----------------------------------------------------------------*/
4116 static void genJumpTab (iCode *ic)
4121 aopOp(IC_JTCOND(ic),ic,FALSE, FALSE);
4122 /* get the condition into accumulator */
4123 l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE);
4125 emitcode("push", "de");
4126 emitcode("ld", "e,%s", l);
4127 emit2("ld d,!zero");
4128 jtab = newiTempLabel(NULL);
4130 emit2("ld hl,!immed!tlabel", jtab->key+100);
4131 emitcode("add", "hl,de");
4132 emitcode("add", "hl,de");
4133 emitcode("add", "hl,de");
4134 freeAsmop(IC_JTCOND(ic),NULL,ic);
4136 emitcode("pop", "de");
4138 emitLabel(jtab->key+100);
4139 /* now generate the jump labels */
4140 for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
4141 jtab = setNextItem(IC_JTLABELS(ic)))
4142 emit2("jp !tlabel", jtab->key+100);
4145 /*-----------------------------------------------------------------*/
4146 /* genCast - gen code for casting */
4147 /*-----------------------------------------------------------------*/
4148 static void genCast (iCode *ic)
4150 operand *result = IC_RESULT(ic);
4151 link *ctype = operandType(IC_LEFT(ic));
4152 operand *right = IC_RIGHT(ic);
4155 /* if they are equivalent then do nothing */
4156 if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
4159 aopOp(right,ic,FALSE, FALSE);
4160 aopOp(result,ic,FALSE, FALSE);
4162 /* if the result is a bit */
4163 if (AOP_TYPE(result) == AOP_CRY) {
4167 /* if they are the same size : or less */
4168 if (AOP_SIZE(result) <= AOP_SIZE(right)) {
4170 /* if they are in the same place */
4171 if (sameRegs(AOP(right),AOP(result)))
4174 /* if they in different places then copy */
4175 size = AOP_SIZE(result);
4179 aopGet(AOP(right),offset,FALSE),
4186 /* PENDING: should be OK. */
4188 /* if the result is of type pointer */
4189 if (IS_PTR(ctype)) {
4194 /* so we now know that the size of destination is greater
4195 than the size of the source */
4196 /* we move to result for the size of source */
4197 size = AOP_SIZE(right);
4201 aopGet(AOP(right),offset,FALSE),
4206 /* now depending on the sign of the destination */
4207 size = AOP_SIZE(result) - AOP_SIZE(right);
4208 /* Unsigned or not an integral type - right fill with zeros */
4209 if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) {
4211 aopPut(AOP(result),zero,offset++);
4213 /* we need to extend the sign :{ */
4214 char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
4217 emitcode("", "; genCast: sign extend untested.");
4218 emitcode("rla", "");
4219 emitcode("sbc", "a,a");
4221 aopPut(AOP(result),"a",offset++);
4225 freeAsmop(right, NULL, ic);
4226 freeAsmop(result, NULL, ic);
4229 /*-----------------------------------------------------------------*/
4230 /* genReceive - generate code for a receive iCode */
4231 /*-----------------------------------------------------------------*/
4232 static void genReceive (iCode *ic)
4234 if (isOperandInFarSpace(IC_RESULT(ic)) &&
4235 ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
4236 IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
4240 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
4242 assignResultValue(IC_RESULT(ic));
4245 freeAsmop(IC_RESULT(ic),NULL,ic);
4248 /*-----------------------------------------------------------------*/
4249 /* genZ80Code - generate code for Z80 based controllers */
4250 /*-----------------------------------------------------------------*/
4251 void genZ80Code (iCode *lic)
4258 _fReturn = _gbz80_return;
4259 _fTmp = _gbz80_return;
4262 _fReturn = _z80_return;
4263 _fTmp = _z80_return;
4265 tsprintf(zero, "!zero");
4267 lineHead = lineCurr = NULL;
4269 /* if debug information required */
4270 if (options.debug && currFunc) {
4271 cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
4273 if (IS_STATIC(currFunc->etype))
4274 emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name);
4276 emitcode("","G$%s$0$0 ==.",currFunc->name);
4279 /* stack pointer name */
4283 for (ic = lic ; ic ; ic = ic->next ) {
4285 if ( cln != ic->lineno ) {
4286 if ( options.debug ) {
4288 emitcode("","C$%s$%d$%d$%d ==.",
4289 ic->filename,ic->lineno,
4290 ic->level,ic->block);
4293 emitcode(";","%s %d",ic->filename,ic->lineno);
4296 /* if the result is marked as
4297 spilt and rematerializable or code for
4298 this has already been generated then
4300 if (resultRemat(ic) || ic->generated )
4303 /* depending on the operation */
4306 emitcode("", "; genNot");
4311 emitcode("", "; genCpl");
4316 emitcode("", "; genUminus");
4321 emitcode("", "; genIpush");
4326 /* IPOP happens only when trying to restore a
4327 spilt live range, if there is an ifx statement
4328 following this pop then the if statement might
4329 be using some of the registers being popped which
4330 would destory the contents of the register so
4331 we need to check for this condition and handle it */
4333 ic->next->op == IFX &&
4334 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) {
4335 emitcode("", "; genIfx");
4336 genIfx (ic->next,ic);
4339 emitcode("", "; genIpop");
4345 emitcode("", "; genCall");
4350 emitcode("", "; genPcall");
4355 emitcode("", "; genFunction");
4360 emitcode("", "; genEndFunction");
4361 genEndFunction (ic);
4365 emitcode("", "; genRet");
4370 emitcode("", "; genLabel");
4375 emitcode("", "; genGoto");
4380 emitcode("", "; genPlus");
4385 emitcode("", "; genMinus");
4390 emitcode("", "; genMult");
4395 emitcode("", "; genDiv");
4400 emitcode("", "; genMod");
4405 emitcode("", "; genCmpGt");
4406 genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));
4410 emitcode("", "; genCmpLt");
4411 genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
4418 /* note these two are xlated by algebraic equivalence
4419 during parsing SDCC.y */
4420 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
4421 "got '>=' or '<=' shouldn't have come here");
4425 emitcode("", "; genCmpEq");
4426 genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
4430 emitcode("", "; genAndOp");
4435 emitcode("", "; genOrOp");
4440 emitcode("", "; genXor");
4441 genXor (ic,ifxForOp(IC_RESULT(ic),ic));
4445 emitcode("", "; genOr");
4446 genOr (ic,ifxForOp(IC_RESULT(ic),ic));
4450 emitcode("", "; genAnd");
4451 genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
4455 emitcode("", "; genInline");
4460 emitcode("", "; genRRC");
4465 emitcode("", "; genRLC");
4470 emitcode("", "; genHBIT");
4474 emitcode("", "; genLeftShift");
4479 emitcode("", "; genRightShift");
4483 case GET_VALUE_AT_ADDRESS:
4484 emitcode("", "; genPointerGet");
4490 if (POINTER_SET(ic)) {
4491 emitcode("", "; genAssign (pointer)");
4495 emitcode("", "; genAssign");
4501 emitcode("", "; genIfx");
4506 emitcode("", "; genAddrOf");
4511 emitcode("", "; genJumpTab");
4516 emitcode("", "; genCast");
4521 emitcode("", "; genReceive");
4526 emitcode("", "; addSet");
4527 addSet(&sendSet,ic);
4532 /* piCode(ic,stdout); */
4538 /* now we are ready to call the
4539 peep hole optimizer */
4540 if (!options.nopeep)
4541 peepHole (&lineHead);
4543 /* now do the actual printing */
4544 printLine (lineHead,codeOutFile);