1 /*-------------------------------------------------------------------------
2 gen.c - Z80 specific code generator.
4 Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
6 Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
7 Improved WORD push 22784 144 19AE
8 With label1 on 22694 144 197E
9 With label2 on 22743 144 198A
10 With label3 on 22776 144 1999
11 With label4 on 22776 144 1999
12 With all 'label' on 22661 144 196F
13 With loopInvariant on 20919 156 19AB
14 With loopInduction on Breaks 198B
15 With all working on 20796 158 196C
16 Slightly better genCmp(signed) 20597 159 195B
17 Better reg packing, first peephole 20038 163 1873
18 With assign packing 19281 165 1849
21 Michael Hope <michaelh@earthling.net> 2000
22 Based on the mcs51 generator - Sandeep Dutta . sandeep.dutta@usa.net (1998)
23 and - Jean-Louis VERN.jlvern@writeme.com (1999)
25 This program is free software; you can redistribute it and/or modify it
26 under the terms of the GNU General Public License as published by the
27 Free Software Foundation; either version 2, or (at your option) any
30 This program is distributed in the hope that it will be useful,
31 but WITHOUT ANY WARRANTY; without even the implied warranty of
32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 GNU General Public License for more details.
36 You should have received a copy of the GNU General Public License
37 along with this program; if not, write to the Free Software
38 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
40 In other words, you are welcome to use, share and improve this program.
41 You are forbidden to forbid anyone else to use, share and improve
42 what you give them. Help stamp out software-hoarding!
44 -------------------------------------------------------------------------*/
51 #ifdef HAVE_SYS_ISA_DEFS_H
52 #include <sys/isa_defs.h>
56 #include "SDCCpeeph.h"
60 /* this is the down and dirty file with all kinds of kludgy & hacky
61 stuff. This is what it is all about CODE GENERATION for a specific MCU.
62 Some of the routines may be reusable, will have to see */
65 static char *_z80_return[] = {"l", "h", "e", "d" };
66 static char *_gbz80_return[] = { "e", "d", "l", "h" };
67 static char **_fReturn;
73 static char *accUse[] = {"a" };
79 extern int ptrRegReq ;
81 extern FILE *codeOutFile;
98 } _pairs[NUM_PAIRS] = {
103 { "iy", "iy.l?", "iy.h?" },
104 { "ix", "ix.l?", "ix.h?" }
107 #define RESULTONSTACK(x) \
108 (IC_RESULT(x) && IC_RESULT(x)->aop && \
109 IC_RESULT(x)->aop->type == AOP_STK )
111 #define MOVA(x) if (strcmp(x,"a")) emitcode("ld","a,%s",x);
112 #define CLRC emitcode("xor","a,a");
114 lineNode *lineHead = NULL;
115 lineNode *lineCurr = NULL;
117 static const unsigned char SLMask[] =
118 {0xFF ,0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00};
119 static const unsigned char SRMask[] =
120 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00};
148 static char *aopGet(asmop *aop, int offset, bool bit16);
150 static void _tidyUp(char *buf)
152 /* Clean up the line so that it is 'prettier' */
153 if (strchr(buf, ':')) {
154 /* Is a label - cant do anything */
157 /* Change the first (and probably only) ' ' to a tab so
169 static void emit2(const char *szFormat, ...)
174 va_start(ap, szFormat);
176 tvsprintf(buffer, szFormat, ap);
179 lineCurr = (lineCurr ?
180 connectLine(lineCurr,newLineNode(buffer)) :
181 (lineHead = newLineNode(buffer)));
183 lineCurr->isInline = inLine;
184 lineCurr->isDebug = debugLine;
187 /*-----------------------------------------------------------------*/
188 /* emitcode - writes the code into a file : for now it is simple */
189 /*-----------------------------------------------------------------*/
190 void emitcode (const char *inst, const char *fmt, ...)
193 char lb[MAX_INLINEASM];
199 sprintf(lb,"%s\t",inst);
200 vsprintf(lb+(strlen(lb)),fmt,ap);
204 while (isspace(*lbp)) lbp++;
207 lineCurr = (lineCurr ?
208 connectLine(lineCurr,newLineNode(lb)) :
209 (lineHead = newLineNode(lb)));
210 lineCurr->isInline = inLine;
211 lineCurr->isDebug = debugLine;
228 emitcode("ld", "sp,ix");
229 emitcode("pop", "ix");
230 emitcode("pop", "de");
235 const char *getPairName(asmop *aop)
237 if (aop->type == AOP_REG) {
238 switch (aop->aopu.aop_reg[0]->rIdx) {
250 else if (aop->type == AOP_STR) {
251 switch (*aop->aopu.aop_str[0]) {
267 static PAIR_ID getPairId(asmop *aop)
269 if (aop->size == 2) {
270 if (aop->type == AOP_REG) {
271 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX)&&(aop->aopu.aop_reg[1]->rIdx == B_IDX)) {
274 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX)&&(aop->aopu.aop_reg[1]->rIdx == D_IDX)) {
277 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX)&&(aop->aopu.aop_reg[1]->rIdx == H_IDX)) {
281 if (aop->type == AOP_STR) {
282 if (!strcmp(aop->aopu.aop_str[0], "c")&&!strcmp(aop->aopu.aop_str[1], "b")) {
285 if (!strcmp(aop->aopu.aop_str[0], "e")&&!strcmp(aop->aopu.aop_str[1], "d")) {
288 if (!strcmp(aop->aopu.aop_str[0], "l")&&!strcmp(aop->aopu.aop_str[1], "h")) {
296 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
297 bool isPair(asmop *aop)
299 return (getPairId(aop) != PAIR_INVALID);
302 bool isPtrPair(asmop *aop)
304 PAIR_ID pairId = getPairId(aop);
314 /** Push a register pair onto the stack */
315 void genPairPush(asmop *aop)
317 emitcode("push", "%s", getPairName(aop));
321 /*-----------------------------------------------------------------*/
322 /* newAsmop - creates a new asmOp */
323 /*-----------------------------------------------------------------*/
324 static asmop *newAsmop (short type)
328 ALLOC(aop,sizeof(asmop));
333 /*-----------------------------------------------------------------*/
334 /* aopForSym - for a true symbol */
335 /*-----------------------------------------------------------------*/
336 static asmop *aopForSym (iCode *ic,symbol *sym,bool result, bool requires_a)
339 memmap *space= SPEC_OCLS(sym->etype);
341 /* if already has one */
345 /* Assign depending on the storage class */
346 if (sym->onStack || sym->iaccess) {
347 emitcode("", "; AOP_STK for %s", sym->rname);
348 sym->aop = aop = newAsmop(AOP_STK);
349 aop->size = getSize(sym->type);
350 aop->aopu.aop_stk = sym->stack;
354 /* special case for a function */
355 if (IS_FUNC(sym->type)) {
356 sym->aop = aop = newAsmop(AOP_IMMD);
357 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(sym->rname)+1);
358 strcpy(aop->aopu.aop_immd,sym->rname);
364 /* if it is in direct space */
365 if (IN_REGSP(space) && !requires_a) {
366 sym->aop = aop = newAsmop (AOP_SFR);
367 aop->aopu.aop_dir = sym->rname ;
368 aop->size = getSize(sym->type);
369 emitcode("", "; AOP_SFR for %s", sym->rname);
374 /* only remaining is far space */
375 /* in which case DPTR gets the address */
377 emitcode("", "; AOP_HL for %s", sym->rname);
378 sym->aop = aop = newAsmop(AOP_HL);
381 sym->aop = aop = newAsmop(AOP_IY);
383 aop->size = getSize(sym->type);
384 aop->aopu.aop_dir = sym->rname;
386 /* if it is in code space */
387 if (IN_CODESPACE(space))
393 /*-----------------------------------------------------------------*/
394 /* aopForRemat - rematerialzes an object */
395 /*-----------------------------------------------------------------*/
396 static asmop *aopForRemat (symbol *sym)
399 iCode *ic = sym->rematiCode;
400 asmop *aop = newAsmop(AOP_IMMD);
403 /* if plus or minus print the right hand side */
404 if (ic->op == '+' || ic->op == '-') {
405 /* PENDING: for re-target */
406 sprintf(s,"0x%04x %c ",(int) operandLitValue(IC_RIGHT(ic)),
409 ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode;
412 /* we reached the end */
413 sprintf(s,"%s",OP_SYMBOL(IC_LEFT(ic))->rname);
417 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(buffer)+1);
418 strcpy(aop->aopu.aop_immd,buffer);
422 /*-----------------------------------------------------------------*/
423 /* regsInCommon - two operands have some registers in common */
424 /*-----------------------------------------------------------------*/
425 bool regsInCommon (operand *op1, operand *op2)
430 /* if they have registers in common */
431 if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
434 sym1 = OP_SYMBOL(op1);
435 sym2 = OP_SYMBOL(op2);
437 if (sym1->nRegs == 0 || sym2->nRegs == 0)
440 for (i = 0 ; i < sym1->nRegs ; i++) {
445 for (j = 0 ; j < sym2->nRegs ;j++ ) {
449 if (sym2->regs[j] == sym1->regs[i])
457 /*-----------------------------------------------------------------*/
458 /* operandsEqu - equivalent */
459 /*-----------------------------------------------------------------*/
460 bool operandsEqu ( operand *op1, operand *op2)
464 /* if they not symbols */
465 if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
468 sym1 = OP_SYMBOL(op1);
469 sym2 = OP_SYMBOL(op2);
471 /* if both are itemps & one is spilt
472 and the other is not then false */
473 if (IS_ITEMP(op1) && IS_ITEMP(op2) &&
474 sym1->isspilt != sym2->isspilt )
477 /* if they are the same */
481 if (strcmp(sym1->rname,sym2->rname) == 0)
485 /* if left is a tmp & right is not */
489 (sym1->usl.spillLoc == sym2))
496 (sym2->usl.spillLoc == sym1))
502 /*-----------------------------------------------------------------*/
503 /* sameRegs - two asmops have the same registers */
504 /*-----------------------------------------------------------------*/
505 bool sameRegs (asmop *aop1, asmop *aop2 )
509 if (aop1->type == AOP_SFR ||
510 aop2->type == AOP_SFR)
516 if (aop1->type != AOP_REG ||
517 aop2->type != AOP_REG )
520 if (aop1->size != aop2->size)
523 for (i = 0 ; i < aop1->size ; i++ )
524 if (aop1->aopu.aop_reg[i] !=
525 aop2->aopu.aop_reg[i] )
531 /*-----------------------------------------------------------------*/
532 /* aopOp - allocates an asmop for an operand : */
533 /*-----------------------------------------------------------------*/
534 static void aopOp (operand *op, iCode *ic, bool result, bool requires_a)
543 /* if this a literal */
544 if (IS_OP_LITERAL(op)) {
545 op->aop = aop = newAsmop(AOP_LIT);
546 aop->aopu.aop_lit = op->operand.valOperand;
547 aop->size = getSize(operandType(op));
551 /* if already has a asmop then continue */
555 /* if the underlying symbol has a aop */
556 if (IS_SYMOP(op) && OP_SYMBOL(op)->aop) {
557 op->aop = OP_SYMBOL(op)->aop;
561 /* if this is a true symbol */
562 if (IS_TRUE_SYMOP(op)) {
563 op->aop = aopForSym(ic,OP_SYMBOL(op),result, requires_a);
567 /* this is a temporary : this has
573 e) can be a return use only */
577 /* if the type is a conditional */
578 if (sym->regType == REG_CND) {
579 aop = op->aop = sym->aop = newAsmop(AOP_CRY);
584 /* if it is spilt then two situations
586 b) has a spill location */
587 if (sym->isspilt || sym->nRegs == 0) {
588 /* rematerialize it NOW */
590 sym->aop = op->aop = aop =
592 aop->size = getSize(sym->type);
598 aop = op->aop = sym->aop = newAsmop(AOP_ACC);
599 aop->size = getSize(sym->type);
600 for ( i = 0 ; i < 2 ; i++ )
601 aop->aopu.aop_str[i] = accUse[i];
607 aop = op->aop = sym->aop = newAsmop(AOP_STR);
608 aop->size = getSize(sym->type);
609 for ( i = 0 ; i < 4 ; i++ )
610 aop->aopu.aop_str[i] = _fReturn[i];
614 /* else spill location */
615 sym->aop = op->aop = aop =
616 aopForSym(ic,sym->usl.spillLoc,result, requires_a);
617 aop->size = getSize(sym->type);
621 /* must be in a register */
622 sym->aop = op->aop = aop = newAsmop(AOP_REG);
623 aop->size = sym->nRegs;
624 for ( i = 0 ; i < sym->nRegs ;i++)
625 aop->aopu.aop_reg[i] = sym->regs[i];
628 /*-----------------------------------------------------------------*/
629 /* freeAsmop - free up the asmop given to an operand */
630 /*----------------------------------------------------------------*/
631 static void freeAsmop (operand *op, asmop *aaop, iCode *ic)
649 /* all other cases just dealloc */
653 OP_SYMBOL(op)->aop = NULL;
654 /* if the symbol has a spill */
656 SPIL_LOC(op)->aop = NULL;
661 bool isLitWord(asmop *aop)
663 /* if (aop->size != 2)
674 char *aopGetLitWordLong(asmop *aop, int offset, bool with_hash)
680 if (aop->size != 2 && aop->type != AOP_HL)
683 wassert(offset == 0);
685 /* depending on type */
690 /* PENDING: for re-target */
692 tsprintf(s, "!hashedstr", aop->aopu.aop_immd);
694 strcpy(s, aop->aopu.aop_immd);
695 ALLOC_ATOMIC(rs,strlen(s)+1);
699 value * val = aop->aopu.aop_lit;
700 /* if it is a float then it gets tricky */
701 /* otherwise it is fairly simple */
702 if (!IS_FLOAT(val->type)) {
703 unsigned long v = floatFromVal(val);
705 tsprintf(buffer, "!immedword", v);
707 tsprintf(buffer, "!constword", v);
708 ALLOC_ATOMIC(rs,strlen(buffer)+1);
709 return strcpy (rs,buffer);
719 char *aopGetWord(asmop *aop, int offset)
721 return aopGetLitWordLong(aop, offset, TRUE);
724 bool isPtr(const char *s)
726 if (!strcmp(s, "hl"))
728 if (!strcmp(s, "ix"))
730 if (!strcmp(s, "iy"))
735 static void adjustPair(const char *pair, int *pold, int new)
739 while (*pold < new) {
740 emitcode("inc", "%s", pair);
743 while (*pold > new) {
744 emitcode("dec", "%s", pair);
749 static void spillPair(PAIR_ID pairId)
751 _G.pairs[pairId].last_type = AOP_INVALID;
752 _G.pairs[pairId].lit = NULL;
755 static void spillCached(void)
761 static bool requiresHL(asmop *aop)
772 static void fetchLitPair(PAIR_ID pairId, asmop *left, int offset)
775 const char *pair = _pairs[pairId].name;
776 l = aopGetLitWordLong(left, 0, FALSE);
780 if (pairId == PAIR_HL || pairId == PAIR_IY) {
781 if (_G.pairs[pairId].last_type == left->type) {
782 if (_G.pairs[pairId].lit && !strcmp(_G.pairs[pairId].lit, l)) {
783 if (pairId == PAIR_HL && abs(_G.pairs[pairId].offset - offset) < 3) {
784 adjustPair(pair, &_G.pairs[pairId].offset, offset);
787 if (pairId == PAIR_IY && abs(offset)<127) {
793 _G.pairs[pairId].last_type = left->type;
794 _G.pairs[pairId].lit = gc_strdup(l);
795 _G.pairs[pairId].offset = offset;
797 /* Both a lit on the right and a true symbol on the left */
798 /* PENDING: for re-target */
800 emit2("ld %s,!hashedstr + %d", pair, l, offset);
802 emit2("ld %s,!hashedstr", pair, l);
805 static void fetchPairLong(PAIR_ID pairId, asmop *aop, int offset)
807 /* if this is remateriazable */
808 if (isLitWord(aop)) {
809 fetchLitPair(pairId, aop, offset);
811 else { /* we need to get it byte by byte */
812 if (pairId == PAIR_HL && IS_GB && requiresHL(aop)) {
813 aopGet(aop, offset, FALSE);
819 emitcode("ld", "%s,%s", _pairs[pairId].l, aopGet(aop, offset, FALSE));
820 emitcode("ld", "%s,%s", _pairs[pairId].h, aopGet(aop, offset+1, FALSE));
822 /* PENDING: check? */
823 if (pairId == PAIR_HL)
828 static void fetchPair(PAIR_ID pairId, asmop *aop)
830 fetchPairLong(pairId, aop, 0);
833 static void fetchHL(asmop *aop)
835 fetchPair(PAIR_HL, aop);
838 static void setupPair(PAIR_ID pairId, asmop *aop, int offset)
840 assert(pairId == PAIR_HL || pairId == PAIR_IY);
845 fetchLitPair(pairId, aop, offset);
846 _G.pairs[pairId].offset = offset;
849 /* Doesnt include _G.stack.pushed */
850 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
851 assert(pairId == PAIR_HL);
852 /* In some cases we can still inc or dec hl */
853 if (_G.pairs[pairId].last_type == AOP_STK && abs(_G.pairs[pairId].offset - abso) < 3) {
854 adjustPair(_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
857 emit2("!ldahlsp", aop->aopu.aop_stk+offset + _G.stack.pushed + _G.stack.offset);
859 _G.pairs[pairId].offset = abso;
865 _G.pairs[pairId].last_type = aop->type;
868 static void emitIntLabel(int key)
870 emit2("!tlabeldef", key);
873 static void emitLabel(int key)
875 emit2("!tlabeldef", key);
879 /*-----------------------------------------------------------------*/
880 /* aopGet - for fetching value of the aop */
881 /*-----------------------------------------------------------------*/
882 static char *aopGet(asmop *aop, int offset, bool bit16)
887 /* offset is greater than size then zero */
888 /* PENDING: this seems a bit screwed in some pointer cases. */
889 if (offset > (aop->size - 1) &&
890 aop->type != AOP_LIT)
893 /* depending on type */
896 /* PENDING: re-target */
898 tsprintf (s,"!immedwords", aop->aopu.aop_immd);
901 wassert(offset == 1);
902 tsprintf(s, "!lsbimmeds", aop->aopu.aop_immd);
905 tsprintf(s, "!msbimmeds", aop->aopu.aop_immd);
906 ALLOC_ATOMIC(rs,strlen(s)+1);
912 emitcode("ld", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
914 ALLOC_ATOMIC(rs,strlen(s)+1);
920 emitcode("ldh", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
922 ALLOC_ATOMIC(rs,strlen(s)+1);
927 return aop->aopu.aop_reg[offset]->name;
931 setupPair(PAIR_HL, aop, offset);
937 setupPair(PAIR_IY, aop, offset);
938 tsprintf(s,"!*iyx", offset);
939 ALLOC_ATOMIC(rs,strlen(s)+1);
945 setupPair(PAIR_HL, aop, offset);
949 tsprintf(s,"!*ixx", aop->aopu.aop_stk+offset);
951 ALLOC_ATOMIC(rs,strlen(s)+1);
965 return aopLiteral (aop->aopu.aop_lit,offset);
969 return aop->aopu.aop_str[offset];
973 wassertl(0, "aopget got unsupported aop->type");
977 bool isRegString(char *s)
979 if (!strcmp(s, "b") ||
990 bool isConstant(const char *s)
992 /* This is a bit of a hack... */
993 return (*s == '#' || *s == '$');
996 bool canAssignToPtr(char *s)
1005 /*-----------------------------------------------------------------*/
1006 /* aopPut - puts a string for a aop */
1007 /*-----------------------------------------------------------------*/
1008 static void aopPut (asmop *aop, char *s, int offset)
1010 if (aop->size && offset > ( aop->size - 1)) {
1011 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1012 "aopPut got offset > aop->size");
1016 /* will assign value to value */
1017 /* depending on where it is ofcourse */
1018 switch (aop->type) {
1023 emitcode("ld", "a,%s", s);
1024 emitcode("ld", "(%s+%d),a", aop->aopu.aop_dir, offset);
1030 emitcode("ld", "a,%s", s);
1031 emitcode("ldh", "(%s+%d),a", aop->aopu.aop_dir, offset);
1035 emitcode("ld","%s,%s",
1036 aop->aopu.aop_reg[offset]->name,s);
1041 setupPair(PAIR_IY, aop, offset);
1042 if (!canAssignToPtr(s)) {
1043 emit2("ld a,%s", s);
1044 emit2("ld !*iyx,a", offset);
1047 emit2("ld !*iyx,%s", offset, s);
1052 /* PENDING: for re-target */
1053 if (!strcmp(s, "!*hl") || !strcmp(s, "(hl)") || !strcmp(s, "[hl]")) {
1057 setupPair(PAIR_HL, aop, offset);
1059 emit2("ld !*hl,%s", s);
1064 /* PENDING: re-target */
1065 if (!strcmp(s, "!*hl") || !strcmp(s, "(hl)") || !strcmp(s, "[hl]")) {
1069 setupPair(PAIR_HL, aop, offset);
1070 if (!canAssignToPtr(s)) {
1071 emit2("ld a,%s", s);
1075 emit2("ld !*hl,%s ; 3", s);
1078 if (!canAssignToPtr(s)) {
1079 emit2("ld a,%s", s);
1080 emit2("ld !*ixx,a", aop->aopu.aop_stk+offset);
1083 emit2("ld !*ixx,%s", aop->aopu.aop_stk+offset, s);
1088 /* if bit variable */
1089 if (!aop->aopu.aop_dir) {
1093 /* In bit space but not in C - cant happen */
1100 if (strcmp(aop->aopu.aop_str[offset],s)) {
1101 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1107 if (!offset && (strcmp(s,"acc") == 0))
1111 emitcode("", "; Error aopPut AOP_ACC");
1114 if (strcmp(aop->aopu.aop_str[offset],s))
1115 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1120 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1121 "aopPut got unsupported aop->type");
1126 #define AOP(op) op->aop
1127 #define AOP_TYPE(op) AOP(op)->type
1128 #define AOP_SIZE(op) AOP(op)->size
1129 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1131 /*-----------------------------------------------------------------*/
1132 /* getDataSize - get the operand data size */
1133 /*-----------------------------------------------------------------*/
1134 int getDataSize(operand *op)
1137 size = AOP_SIZE(op);
1145 /*-----------------------------------------------------------------*/
1146 /* movLeft2Result - move byte from left to result */
1147 /*-----------------------------------------------------------------*/
1148 static void movLeft2Result (operand *left, int offl,
1149 operand *result, int offr, int sign)
1152 if(!sameRegs(AOP(left),AOP(result)) || (offl != offr)){
1153 l = aopGet(AOP(left),offl,FALSE);
1156 aopPut(AOP(result),l,offr);
1165 /** Put Acc into a register set
1167 void outAcc(operand *result)
1170 size = getDataSize(result);
1172 aopPut(AOP(result),"a",0);
1175 /* unsigned or positive */
1177 aopPut(AOP(result), zero, offset++);
1182 /** Take the value in carry and put it into a register
1184 void outBitC(operand *result)
1186 /* if the result is bit */
1187 if (AOP_TYPE(result) == AOP_CRY) {
1188 emitcode("", "; Note: outBitC form 1");
1189 aopPut(AOP(result),"blah",0);
1192 emit2("ld a,!zero");
1198 /*-----------------------------------------------------------------*/
1199 /* toBoolean - emit code for orl a,operator(sizeop) */
1200 /*-----------------------------------------------------------------*/
1201 void toBoolean(operand *oper)
1203 int size = AOP_SIZE(oper);
1206 emitcode("ld", "a,%s", aopGet(AOP(oper), offset++, FALSE));
1209 emitcode("or","a,%s",aopGet(AOP(oper),offset++,FALSE));
1212 if (AOP(oper)->type != AOP_ACC) {
1214 emitcode("or","a,%s",aopGet(AOP(oper),0,FALSE));
1219 /*-----------------------------------------------------------------*/
1220 /* genNot - generate code for ! operation */
1221 /*-----------------------------------------------------------------*/
1222 static void genNot (iCode *ic)
1224 link *optype = operandType(IC_LEFT(ic));
1226 /* assign asmOps to operand & result */
1227 aopOp (IC_LEFT(ic),ic,FALSE, TRUE);
1228 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1230 /* if in bit space then a special case */
1231 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) {
1235 /* if type float then do float */
1236 if (IS_FLOAT(optype)) {
1240 toBoolean(IC_LEFT(ic));
1245 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1246 emit2("sub a,!one");
1247 outBitC(IC_RESULT(ic));
1249 /* release the aops */
1250 freeAsmop(IC_LEFT(ic),NULL,ic);
1251 freeAsmop(IC_RESULT(ic),NULL,ic);
1254 /*-----------------------------------------------------------------*/
1255 /* genCpl - generate code for complement */
1256 /*-----------------------------------------------------------------*/
1257 static void genCpl (iCode *ic)
1263 /* assign asmOps to operand & result */
1264 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
1265 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1267 /* if both are in bit space then
1269 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1270 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1274 size = AOP_SIZE(IC_RESULT(ic));
1276 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1279 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1282 /* release the aops */
1283 freeAsmop(IC_LEFT(ic),NULL,ic);
1284 freeAsmop(IC_RESULT(ic),NULL,ic);
1287 /*-----------------------------------------------------------------*/
1288 /* genUminus - unary minus code generation */
1289 /*-----------------------------------------------------------------*/
1290 static void genUminus (iCode *ic)
1293 link *optype, *rtype;
1296 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1297 aopOp(IC_RESULT(ic),ic,TRUE, FALSE);
1299 /* if both in bit space then special
1301 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1302 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1307 optype = operandType(IC_LEFT(ic));
1308 rtype = operandType(IC_RESULT(ic));
1310 /* if float then do float stuff */
1311 if (IS_FLOAT(optype)) {
1316 /* otherwise subtract from zero */
1317 size = AOP_SIZE(IC_LEFT(ic));
1321 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1322 emit2("ld a,!zero");
1323 emit2("sbc a,%s",l);
1324 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1327 /* if any remaining bytes in the result */
1328 /* we just need to propagate the sign */
1329 if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic))))) {
1333 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1337 /* release the aops */
1338 freeAsmop(IC_LEFT(ic),NULL,ic);
1339 freeAsmop(IC_RESULT(ic),NULL,ic);
1342 /*-----------------------------------------------------------------*/
1343 /* assignResultValue - */
1344 /*-----------------------------------------------------------------*/
1345 void assignResultValue(operand * oper)
1347 int size = AOP_SIZE(oper);
1351 topInA = requiresHL(AOP(oper));
1355 if (IS_GB && size == 4 && requiresHL(AOP(oper))) {
1356 /* We do it the hard way here. */
1357 emitcode("push", "hl");
1358 _G.stack.pushed += 2;
1359 aopPut(AOP(oper), _fReturn[0], 0);
1360 aopPut(AOP(oper), _fReturn[1], 1);
1361 emitcode("pop", "de");
1362 _G.stack.pushed -= 2;
1363 aopPut(AOP(oper), _fReturn[0], 2);
1364 aopPut(AOP(oper), _fReturn[1], 3);
1368 aopPut(AOP(oper), _fReturn[size], size);
1373 /*-----------------------------------------------------------------*/
1374 /* genIpush - genrate code for pushing this gets a little complex */
1375 /*-----------------------------------------------------------------*/
1376 static void genIpush (iCode *ic)
1378 int size, offset = 0 ;
1382 /* if this is not a parm push : ie. it is spill push
1383 and spill push is always done on the local stack */
1384 if (!ic->parmPush) {
1385 /* and the item is spilt then do nothing */
1386 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1389 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1390 size = AOP_SIZE(IC_LEFT(ic));
1391 /* push it on the stack */
1392 if (isPair(AOP(IC_LEFT(ic)))) {
1393 emitcode("push", getPairName(AOP(IC_LEFT(ic))));
1394 _G.stack.pushed += 2;
1399 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1400 /* Simple for now - load into A and PUSH AF */
1401 emitcode("ld", "a,%s", l);
1402 emitcode("push", "af");
1403 emitcode("inc", "sp");
1410 /* Hmmm... what about saving the currently used registers
1413 /* then do the push */
1414 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1416 size = AOP_SIZE(IC_LEFT(ic));
1418 if (isPair(AOP(IC_LEFT(ic)))) {
1420 emitcode("push", "%s", getPairName(AOP(IC_LEFT(ic))));
1424 fetchHL(AOP(IC_LEFT(ic)));
1425 emitcode("push", "hl");
1427 _G.stack.pushed += 2;
1432 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1433 emitcode("ld", "a,%s", l);
1434 emitcode("push", "af");
1435 emitcode("inc", "sp");
1440 freeAsmop(IC_LEFT(ic),NULL,ic);
1443 /*-----------------------------------------------------------------*/
1444 /* genIpop - recover the registers: can happen only for spilling */
1445 /*-----------------------------------------------------------------*/
1446 static void genIpop (iCode *ic)
1451 /* if the temp was not pushed then */
1452 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1455 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1456 size = AOP_SIZE(IC_LEFT(ic));
1458 if (isPair(AOP(IC_LEFT(ic)))) {
1459 emitcode("pop", getPairName(AOP(IC_LEFT(ic))));
1463 emitcode("dec", "sp");
1464 emitcode("pop", "hl");
1466 aopPut(AOP(IC_LEFT(ic)), "l", offset--);
1470 freeAsmop(IC_LEFT(ic),NULL,ic);
1473 /** Emit the code for a call statement
1475 static void emitCall (iCode *ic, bool ispcall)
1477 /* if caller saves & we have not saved then */
1478 if (!ic->regsSaved) {
1482 /* if send set is not empty then assign */
1485 for (sic = setFirstItem(sendSet) ; sic ;
1486 sic = setNextItem(sendSet)) {
1487 int size, offset = 0;
1488 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1489 size = AOP_SIZE(IC_LEFT(sic));
1491 char *l = aopGet(AOP(IC_LEFT(sic)),offset,
1493 if (strcmp(l, _fReturn[offset]))
1494 emitcode("ld","%s,%s",
1499 freeAsmop (IC_LEFT(sic),NULL,sic);
1505 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1507 if (isLitWord(AOP(IC_LEFT(ic)))) {
1508 emitcode("", "; Special case where the pCall is to a constant");
1509 emitcode("call", aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE));
1512 symbol *rlbl = newiTempLabel(NULL);
1514 emit2("ld hl,#!tlabel", (rlbl->key+100));
1515 emitcode("push", "hl");
1516 _G.stack.pushed += 2;
1518 fetchHL(AOP(IC_LEFT(ic)));
1520 emit2("!tlabeldef", (rlbl->key+100));
1521 _G.stack.pushed -= 2;
1523 freeAsmop(IC_LEFT(ic),NULL,ic);
1527 char *name = OP_SYMBOL(IC_LEFT(ic))->rname[0] ?
1528 OP_SYMBOL(IC_LEFT(ic))->rname :
1529 OP_SYMBOL(IC_LEFT(ic))->name;
1530 emitcode("call", "%s", name);
1534 /* if we need assign a result value */
1535 if ((IS_ITEMP(IC_RESULT(ic)) &&
1536 (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
1537 OP_SYMBOL(IC_RESULT(ic))->spildir )) ||
1538 IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
1541 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
1544 assignResultValue(IC_RESULT(ic));
1546 freeAsmop(IC_RESULT(ic),NULL, ic);
1549 /* adjust the stack for parameters if required */
1550 if (IC_LEFT(ic)->parmBytes) {
1551 int i = IC_LEFT(ic)->parmBytes;
1552 _G.stack.pushed -= i;
1554 emit2("!ldaspsp", i);
1559 emitcode("ld", "hl,#%d", i);
1560 emitcode("add", "hl,sp");
1561 emitcode("ld", "sp,hl");
1565 emitcode("pop", "hl");
1569 emitcode("inc", "sp");
1577 /*-----------------------------------------------------------------*/
1578 /* genCall - generates a call statement */
1579 /*-----------------------------------------------------------------*/
1580 static void genCall (iCode *ic)
1582 emitCall(ic, FALSE);
1585 /*-----------------------------------------------------------------*/
1586 /* genPcall - generates a call by pointer statement */
1587 /*-----------------------------------------------------------------*/
1588 static void genPcall (iCode *ic)
1593 /*-----------------------------------------------------------------*/
1594 /* resultRemat - result is rematerializable */
1595 /*-----------------------------------------------------------------*/
1596 static int resultRemat (iCode *ic)
1598 if (SKIP_IC(ic) || ic->op == IFX)
1601 if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
1602 symbol *sym = OP_SYMBOL(IC_RESULT(ic));
1603 if (sym->remat && !POINTER_SET(ic))
1610 /*-----------------------------------------------------------------*/
1611 /* genFunction - generated code for function entry */
1612 /*-----------------------------------------------------------------*/
1613 static void genFunction (iCode *ic)
1615 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1619 /* create the function header */
1620 emit2("!functionheader", sym->name);
1621 /* PENDING: portability. */
1622 emit2("__%s_start:", sym->rname);
1623 emit2("!functionlabeldef", sym->rname);
1625 fetype = getSpec(operandType(IC_LEFT(ic)));
1627 /* if critical function then turn interrupts off */
1628 if (SPEC_CRTCL(fetype))
1631 /* if this is an interrupt service routine then
1632 save acc, b, dpl, dph */
1633 if (IS_ISR(sym->etype)) {
1636 /* PENDING: callee-save etc */
1638 /* adjust the stack for the function */
1639 _G.stack.last = sym->stack;
1642 emit2("!enterx", sym->stack);
1645 _G.stack.offset = sym->stack;
1648 /*-----------------------------------------------------------------*/
1649 /* genEndFunction - generates epilogue for functions */
1650 /*-----------------------------------------------------------------*/
1651 static void genEndFunction (iCode *ic)
1653 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1655 if (IS_ISR(sym->etype)) {
1659 if (SPEC_CRTCL(sym->etype))
1662 /* PENDING: calleeSave */
1664 /* if debug then send end of function */
1665 if (options.debug && currFunc) {
1667 emitcode("","C$%s$%d$%d$%d ==.",
1668 ic->filename,currFunc->lastLine,
1669 ic->level,ic->block);
1670 if (IS_STATIC(currFunc->etype))
1671 emitcode("","XF%s$%s$0$0 ==.",moduleName,currFunc->name);
1673 emitcode("","XG$%s$0$0 ==.",currFunc->name);
1676 if (_G.stack.offset)
1677 emit2("!leavex", _G.stack.offset);
1680 /* PENDING: portability. */
1681 emit2("__%s_end:", sym->rname);
1683 _G.stack.pushed = 0;
1684 _G.stack.offset = 0;
1687 /*-----------------------------------------------------------------*/
1688 /* genRet - generate code for return statement */
1689 /*-----------------------------------------------------------------*/
1690 static void genRet (iCode *ic)
1693 /* Errk. This is a hack until I can figure out how
1694 to cause dehl to spill on a call */
1695 int size,offset = 0;
1697 /* if we have no return value then
1698 just generate the "ret" */
1702 /* we have something to return then
1703 move the return value into place */
1704 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1705 size = AOP_SIZE(IC_LEFT(ic));
1707 if ((size == 2) && ((l = aopGetWord(AOP(IC_LEFT(ic)), 0)))) {
1709 emitcode("ld", "de,%s", l);
1712 emitcode("ld", "hl,%s", l);
1716 if (IS_GB && size == 4 && requiresHL(AOP(IC_LEFT(ic)))) {
1717 fetchPair(PAIR_DE, AOP(IC_LEFT(ic)));
1718 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
1722 l = aopGet(AOP(IC_LEFT(ic)),offset,
1724 if (strcmp(_fReturn[offset],l))
1725 emitcode("ld","%s,%s", _fReturn[offset++],l);
1729 freeAsmop (IC_LEFT(ic),NULL,ic);
1732 /* generate a jump to the return label
1733 if the next is not the return statement */
1734 if (!(ic->next && ic->next->op == LABEL &&
1735 IC_LABEL(ic->next) == returnLabel))
1737 emit2("jp !tlabel", returnLabel->key+100);
1740 /*-----------------------------------------------------------------*/
1741 /* genLabel - generates a label */
1742 /*-----------------------------------------------------------------*/
1743 static void genLabel (iCode *ic)
1745 /* special case never generate */
1746 if (IC_LABEL(ic) == entryLabel)
1749 emitLabel(IC_LABEL(ic)->key+100);
1752 /*-----------------------------------------------------------------*/
1753 /* genGoto - generates a ljmp */
1754 /*-----------------------------------------------------------------*/
1755 static void genGoto (iCode *ic)
1757 emit2("jp !tlabel", IC_LABEL(ic)->key+100);
1760 /*-----------------------------------------------------------------*/
1761 /* genPlusIncr :- does addition with increment if possible */
1762 /*-----------------------------------------------------------------*/
1763 static bool genPlusIncr (iCode *ic)
1765 unsigned int icount ;
1766 unsigned int size = getDataSize(IC_RESULT(ic));
1767 PAIR_ID resultId = getPairId(AOP(IC_RESULT(ic)));
1769 /* will try to generate an increment */
1770 /* if the right side is not a literal
1772 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1775 emitcode("", "; genPlusIncr");
1777 icount = floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
1779 /* If result is a pair */
1780 if (resultId != PAIR_INVALID) {
1781 if (isLitWord(AOP(IC_LEFT(ic)))) {
1782 fetchLitPair(getPairId(AOP(IC_RESULT(ic))), AOP(IC_LEFT(ic)), icount);
1785 if (isPair(AOP(IC_LEFT(ic))) && resultId == PAIR_HL && icount > 2) {
1786 fetchPair(resultId, AOP(IC_RIGHT(ic)));
1787 emitcode("add", "hl,%s", getPairName(AOP(IC_LEFT(ic))));
1793 if (!sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
1796 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
1797 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
1800 emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
1805 /* if the literal value of the right hand side
1806 is greater than 4 then it is not worth it */
1810 /* if increment 16 bits in register */
1811 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1816 symbol *tlbl = NULL;
1817 tlbl = newiTempLabel(NULL);
1819 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)), offset++, FALSE));
1821 emit2("!shortjp nz,!tlabel", tlbl->key+100);
1824 emitLabel(tlbl->key+100);
1828 /* if the sizes are greater than 1 then we cannot */
1829 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
1830 AOP_SIZE(IC_LEFT(ic)) > 1 )
1833 /* we can if the aops of the left & result match or
1834 if they are in registers and the registers are the
1836 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
1838 emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0, FALSE));
1845 /*-----------------------------------------------------------------*/
1846 /* outBitAcc - output a bit in acc */
1847 /*-----------------------------------------------------------------*/
1848 void outBitAcc(operand *result)
1850 symbol *tlbl = newiTempLabel(NULL);
1851 /* if the result is a bit */
1852 if (AOP_TYPE(result) == AOP_CRY){
1856 emit2("!shortjp z,!tlabel", tlbl->key+100);
1858 emitLabel(tlbl->key+100);
1863 /*-----------------------------------------------------------------*/
1864 /* genPlus - generates code for addition */
1865 /*-----------------------------------------------------------------*/
1866 static void genPlus (iCode *ic)
1868 int size, offset = 0;
1870 /* special cases :- */
1872 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
1873 aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
1874 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1876 /* Swap the left and right operands if:
1878 if literal, literal on the right or
1879 if left requires ACC or right is already
1882 if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
1883 (AOP_NEEDSACC(IC_LEFT(ic))) ||
1884 AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
1885 operand *t = IC_RIGHT(ic);
1886 IC_RIGHT(ic) = IC_LEFT(ic);
1890 /* if both left & right are in bit
1892 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1893 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
1898 /* if left in bit space & right literal */
1899 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1900 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
1901 /* Can happen I guess */
1905 /* if I can do an increment instead
1906 of add then GOOD for ME */
1907 if (genPlusIncr (ic) == TRUE)
1910 size = getDataSize(IC_RESULT(ic));
1912 /* Special case when left and right are constant */
1913 if (isPair(AOP(IC_RESULT(ic)))) {
1916 left = aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE);
1917 right = aopGetLitWordLong(AOP(IC_RIGHT(ic)), 0, FALSE);
1918 if (left && right) {
1922 sprintf(buffer, "#(%s + %s)", left, right);
1923 emitcode("ld", "%s,%s", getPairName(AOP(IC_RESULT(ic))), buffer);
1928 if (isPair(AOP(IC_RIGHT(ic))) && getPairId(AOP(IC_RESULT(ic))) == PAIR_HL) {
1929 /* Fetch into HL then do the add */
1931 fetchPair(PAIR_HL, AOP(IC_LEFT(ic)));
1932 emitcode("add", "hl,%s", getPairName(AOP(IC_RIGHT(ic))));
1937 if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
1938 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1940 emitcode("add","a,%s",
1941 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1943 emitcode("adc","a,%s",
1944 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1946 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1948 emitcode("add","a,%s",
1949 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1951 emitcode("adc","a,%s",
1952 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1954 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1957 /* Some kind of pointer arith. */
1958 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
1959 AOP_SIZE(IC_LEFT(ic)) == 3 &&
1960 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
1963 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
1964 AOP_SIZE(IC_RIGHT(ic)) == 3 &&
1965 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
1970 freeAsmop(IC_LEFT(ic),NULL,ic);
1971 freeAsmop(IC_RIGHT(ic),NULL,ic);
1972 freeAsmop(IC_RESULT(ic),NULL,ic);
1976 /*-----------------------------------------------------------------*/
1977 /* genMinusDec :- does subtraction with deccrement if possible */
1978 /*-----------------------------------------------------------------*/
1979 static bool genMinusDec (iCode *ic)
1981 unsigned int icount ;
1982 unsigned int size = getDataSize(IC_RESULT(ic));
1984 /* will try to generate an increment */
1985 /* if the right side is not a literal we cannot */
1986 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1989 /* if the literal value of the right hand side
1990 is greater than 4 then it is not worth it */
1991 if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
1994 size = getDataSize(IC_RESULT(ic));
1997 /* if increment 16 bits in register */
1998 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2001 symbol *tlbl = newiTempLabel(NULL);
2002 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
2003 emitcode("jp", "np," LABEL_STR ,tlbl->key+100);
2005 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
2009 emitLabel(tlbl->key+100);
2014 /* if decrement 16 bits in register */
2015 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2016 (size > 1) && isPair(AOP(IC_RESULT(ic)))) {
2018 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2022 /* If result is a pair */
2023 if (isPair(AOP(IC_RESULT(ic)))) {
2024 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
2025 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
2027 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2031 /* if the sizes are greater than 1 then we cannot */
2032 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2033 AOP_SIZE(IC_LEFT(ic)) > 1 )
2036 /* we can if the aops of the left & result match or if they are in
2037 registers and the registers are the same */
2038 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
2040 emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE));
2047 /*-----------------------------------------------------------------*/
2048 /* genMinus - generates code for subtraction */
2049 /*-----------------------------------------------------------------*/
2050 static void genMinus (iCode *ic)
2052 int size, offset = 0;
2053 unsigned long lit = 0L;
2055 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
2056 aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
2057 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
2059 /* special cases :- */
2060 /* if both left & right are in bit space */
2061 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2062 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2067 /* if I can do an decrement instead of subtract then GOOD for ME */
2068 if (genMinusDec (ic) == TRUE)
2071 size = getDataSize(IC_RESULT(ic));
2073 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
2076 lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
2081 /* if literal, add a,#-lit, else normal subb */
2083 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2084 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) {
2086 emitcode("sub","a,%s",
2087 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2089 emitcode("sbc","a,%s",
2090 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2093 /* first add without previous c */
2095 emit2("add a,!immedbyte", (unsigned int)(lit & 0x0FFL));
2097 emit2("adc a,!immedbyte", (unsigned int)((lit >> (offset*8)) & 0x0FFL));
2099 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2102 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2103 AOP_SIZE(IC_LEFT(ic)) == 3 &&
2104 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2108 freeAsmop(IC_LEFT(ic),NULL,ic);
2109 freeAsmop(IC_RIGHT(ic),NULL,ic);
2110 freeAsmop(IC_RESULT(ic),NULL,ic);
2113 /*-----------------------------------------------------------------*/
2114 /* genMult - generates code for multiplication */
2115 /*-----------------------------------------------------------------*/
2116 static void genMult (iCode *ic)
2118 /* Shouldn't occur - all done through function calls */
2122 /*-----------------------------------------------------------------*/
2123 /* genDiv - generates code for division */
2124 /*-----------------------------------------------------------------*/
2125 static void genDiv (iCode *ic)
2127 /* Shouldn't occur - all done through function calls */
2131 /*-----------------------------------------------------------------*/
2132 /* genMod - generates code for division */
2133 /*-----------------------------------------------------------------*/
2134 static void genMod (iCode *ic)
2136 /* Shouldn't occur - all done through function calls */
2140 /*-----------------------------------------------------------------*/
2141 /* genIfxJump :- will create a jump depending on the ifx */
2142 /*-----------------------------------------------------------------*/
2143 static void genIfxJump (iCode *ic, char *jval)
2148 /* if true label then we jump if condition
2150 if ( IC_TRUE(ic) ) {
2152 if (!strcmp(jval, "a")) {
2155 else if (!strcmp(jval, "c")) {
2159 /* The buffer contains the bit on A that we should test */
2164 /* false label is present */
2165 jlbl = IC_FALSE(ic) ;
2166 if (!strcmp(jval, "a")) {
2169 else if (!strcmp(jval, "c")) {
2173 /* The buffer contains the bit on A that we should test */
2177 /* Z80 can do a conditional long jump */
2178 if (!strcmp(jval, "a")) {
2179 emitcode("or", "a,a");
2181 else if (!strcmp(jval, "c")) {
2184 emitcode("bit", "%s,a", jval);
2186 emit2("jp %s,!tlabel", inst, jlbl->key+100);
2188 /* mark the icode as generated */
2192 /** Generic compare for > or <
2194 static void genCmp (operand *left,operand *right,
2195 operand *result, iCode *ifx, int sign)
2197 int size, offset = 0 ;
2198 unsigned long lit = 0L;
2200 /* if left & right are bit variables */
2201 if (AOP_TYPE(left) == AOP_CRY &&
2202 AOP_TYPE(right) == AOP_CRY ) {
2203 /* Cant happen on the Z80 */
2206 /* subtract right from left if at the
2207 end the carry flag is set then we know that
2208 left is greater than right */
2209 size = max(AOP_SIZE(left),AOP_SIZE(right));
2211 /* if unsigned char cmp with lit, just compare */
2213 (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
2214 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2216 emit2("xor a,!immedbyte", 0x80);
2217 emit2("cp %s^!constbyte", aopGet(AOP(right), offset, FALSE), 0x80);
2220 emitcode("cp", "%s", aopGet(AOP(right), offset, FALSE));
2223 if(AOP_TYPE(right) == AOP_LIT) {
2224 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2225 /* optimize if(x < 0) or if(x >= 0) */
2228 /* No sign so it's always false */
2232 /* Just load in the top most bit */
2233 MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE));
2234 if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx) {
2235 genIfxJump (ifx,"7");
2239 emitcode("rlc","a");
2245 /* First setup h and l contaning the top most bytes XORed */
2246 bool fDidXor = FALSE;
2247 if (AOP_TYPE(left) == AOP_LIT){
2248 unsigned long lit = (unsigned long)
2249 floatFromVal(AOP(left)->aopu.aop_lit);
2250 emit2("ld %s,!immedbyte", _fTmp[0],
2251 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2254 emitcode("ld", "a,%s", aopGet(AOP(left), size-1, FALSE));
2255 emit2("xor a,!immedbyte", 0x80);
2256 emitcode("ld", "%s,a", _fTmp[0]);
2259 if (AOP_TYPE(right) == AOP_LIT) {
2260 unsigned long lit = (unsigned long)
2261 floatFromVal(AOP(right)->aopu.aop_lit);
2262 emit2("ld %s,!immedbyte", _fTmp[1],
2263 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2266 emitcode("ld", "a,%s", aopGet(AOP(right), size-1, FALSE));
2267 emit2("xor a,!immedbyte", 0x80);
2268 emitcode("ld", "%s,a", _fTmp[1]);
2278 /* Do a long subtract */
2279 if (!sign || size ) {
2280 MOVA(aopGet(AOP(left),offset,FALSE));
2282 if (sign && size == 0) {
2283 emitcode("ld", "a,%s", _fTmp[0]);
2284 emitcode("sbc", "a,%s", _fTmp[1]);
2287 /* Subtract through, propagating the carry */
2288 emitcode("sbc","a,%s ; 2",aopGet(AOP(right),offset++,FALSE));
2295 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2298 /* if the result is used in the next
2299 ifx conditional branch then generate
2300 code a little differently */
2302 genIfxJump (ifx,"c");
2305 /* leave the result in acc */
2309 /*-----------------------------------------------------------------*/
2310 /* genCmpGt :- greater than comparison */
2311 /*-----------------------------------------------------------------*/
2312 static void genCmpGt (iCode *ic, iCode *ifx)
2314 operand *left, *right, *result;
2315 link *letype , *retype;
2319 right= IC_RIGHT(ic);
2320 result = IC_RESULT(ic);
2322 letype = getSpec(operandType(left));
2323 retype =getSpec(operandType(right));
2324 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2325 /* assign the amsops */
2326 aopOp (left,ic,FALSE, FALSE);
2327 aopOp (right,ic,FALSE, FALSE);
2328 aopOp (result,ic,TRUE, FALSE);
2330 genCmp(right, left, result, ifx, sign);
2332 freeAsmop(left,NULL,ic);
2333 freeAsmop(right,NULL,ic);
2334 freeAsmop(result,NULL,ic);
2337 /*-----------------------------------------------------------------*/
2338 /* genCmpLt - less than comparisons */
2339 /*-----------------------------------------------------------------*/
2340 static void genCmpLt (iCode *ic, iCode *ifx)
2342 operand *left, *right, *result;
2343 link *letype , *retype;
2347 right= IC_RIGHT(ic);
2348 result = IC_RESULT(ic);
2350 letype = getSpec(operandType(left));
2351 retype =getSpec(operandType(right));
2352 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2354 /* assign the amsops */
2355 aopOp (left,ic,FALSE, FALSE);
2356 aopOp (right,ic,FALSE, FALSE);
2357 aopOp (result,ic,TRUE, FALSE);
2359 genCmp(left, right, result, ifx, sign);
2361 freeAsmop(left,NULL,ic);
2362 freeAsmop(right,NULL,ic);
2363 freeAsmop(result,NULL,ic);
2366 /*-----------------------------------------------------------------*/
2367 /* gencjneshort - compare and jump if not equal */
2368 /*-----------------------------------------------------------------*/
2369 static void gencjneshort(operand *left, operand *right, symbol *lbl)
2371 int size = max(AOP_SIZE(left),AOP_SIZE(right));
2373 unsigned long lit = 0L;
2375 /* Swap the left and right if it makes the computation easier */
2376 if (AOP_TYPE(left) == AOP_LIT) {
2382 if(AOP_TYPE(right) == AOP_LIT)
2383 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2385 /* if the right side is a literal then anything goes */
2386 if (AOP_TYPE(right) == AOP_LIT &&
2387 AOP_TYPE(left) != AOP_DIR ) {
2389 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2394 emitcode("or", "a,%s", aopGet(AOP(left), offset, FALSE));
2398 emitcode("or", "a,a");
2400 emit2("jp nz,!tlabel", lbl->key+100);
2404 emitcode("ld", "a,%s ; 2", aopGet(AOP(left),offset,FALSE));
2405 if ((AOP_TYPE(right) == AOP_LIT) && lit == 0)
2406 emitcode("or", "a,a");
2408 emitcode("cp", "a,%s", aopGet(AOP(right),offset,FALSE));
2409 emit2("jp nz,!tlabel", lbl->key+100);
2414 /* if the right side is in a register or in direct space or
2415 if the left is a pointer register & right is not */
2416 else if (AOP_TYPE(right) == AOP_REG ||
2417 AOP_TYPE(right) == AOP_DIR ||
2418 (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT)) {
2420 MOVA(aopGet(AOP(left),offset,FALSE));
2421 if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
2422 ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
2424 emit2("jp nz,!tlabel", lbl->key+100);
2426 emitcode("cp", "%s ; 4", aopGet(AOP(right),offset,FALSE));
2427 emit2("jp nz,!tlabel", lbl->key+100);
2432 /* right is a pointer reg need both a & b */
2433 /* PENDING: is this required? */
2435 MOVA(aopGet(AOP(right),offset,FALSE));
2436 emitcode("cp", "%s ; 5", aopGet(AOP(left), offset, FALSE));
2437 emit2("!shortjp nz,!tlabel", lbl->key+100);
2443 /*-----------------------------------------------------------------*/
2444 /* gencjne - compare and jump if not equal */
2445 /*-----------------------------------------------------------------*/
2446 static void gencjne(operand *left, operand *right, symbol *lbl)
2448 symbol *tlbl = newiTempLabel(NULL);
2450 gencjneshort(left, right, lbl);
2454 emit2("!shortjp !tlabel", tlbl->key+100);
2455 emitLabel(lbl->key+100);
2456 emitcode("xor","a,a");
2457 emitLabel(tlbl->key+100);
2460 /*-----------------------------------------------------------------*/
2461 /* genCmpEq - generates code for equal to */
2462 /*-----------------------------------------------------------------*/
2463 static void genCmpEq (iCode *ic, iCode *ifx)
2465 operand *left, *right, *result;
2467 aopOp((left=IC_LEFT(ic)),ic,FALSE, FALSE);
2468 aopOp((right=IC_RIGHT(ic)),ic,FALSE, FALSE);
2469 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2471 /* Swap operands if it makes the operation easier. ie if:
2472 1. Left is a literal.
2474 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
2475 operand *t = IC_RIGHT(ic);
2476 IC_RIGHT(ic) = IC_LEFT(ic);
2480 if (ifx && !AOP_SIZE(result)){
2482 /* if they are both bit variables */
2483 if (AOP_TYPE(left) == AOP_CRY &&
2484 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2487 tlbl = newiTempLabel(NULL);
2488 gencjneshort(left, right, tlbl);
2489 if ( IC_TRUE(ifx) ) {
2490 emit2("jp !tlabel", IC_TRUE(ifx)->key+100);
2491 emitLabel(tlbl->key+100);
2493 /* PENDING: do this better */
2494 symbol *lbl = newiTempLabel(NULL);
2495 emit2("!shortjp !tlabel", lbl->key+100);
2496 emitLabel(tlbl->key+100);
2497 emit2("jp !tlabel", IC_FALSE(ifx)->key+100);
2498 emitLabel(lbl->key+100);
2501 /* mark the icode as generated */
2506 /* if they are both bit variables */
2507 if (AOP_TYPE(left) == AOP_CRY &&
2508 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2511 gencjne(left,right,newiTempLabel(NULL));
2512 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2516 genIfxJump(ifx,"a");
2519 /* if the result is used in an arithmetic operation
2520 then put the result in place */
2521 if (AOP_TYPE(result) != AOP_CRY) {
2524 /* leave the result in acc */
2528 freeAsmop(left,NULL,ic);
2529 freeAsmop(right,NULL,ic);
2530 freeAsmop(result,NULL,ic);
2533 /*-----------------------------------------------------------------*/
2534 /* ifxForOp - returns the icode containing the ifx for operand */
2535 /*-----------------------------------------------------------------*/
2536 static iCode *ifxForOp ( operand *op, iCode *ic )
2538 /* if true symbol then needs to be assigned */
2539 if (IS_TRUE_SYMOP(op))
2542 /* if this has register type condition and
2543 the next instruction is ifx with the same operand
2544 and live to of the operand is upto the ifx only then */
2546 ic->next->op == IFX &&
2547 IC_COND(ic->next)->key == op->key &&
2548 OP_SYMBOL(op)->liveTo <= ic->next->seq )
2554 /*-----------------------------------------------------------------*/
2555 /* genAndOp - for && operation */
2556 /*-----------------------------------------------------------------*/
2557 static void genAndOp (iCode *ic)
2559 operand *left,*right, *result;
2562 /* note here that && operations that are in an if statement are
2563 taken away by backPatchLabels only those used in arthmetic
2564 operations remain */
2565 aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2566 aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2567 aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2569 /* if both are bit variables */
2570 if (AOP_TYPE(left) == AOP_CRY &&
2571 AOP_TYPE(right) == AOP_CRY ) {
2574 tlbl = newiTempLabel(NULL);
2576 emit2("!shortjp z,!tlabel", tlbl->key+100);
2578 emitLabel(tlbl->key+100);
2582 freeAsmop(left,NULL,ic);
2583 freeAsmop(right,NULL,ic);
2584 freeAsmop(result,NULL,ic);
2587 /*-----------------------------------------------------------------*/
2588 /* genOrOp - for || operation */
2589 /*-----------------------------------------------------------------*/
2590 static void genOrOp (iCode *ic)
2592 operand *left,*right, *result;
2595 /* note here that || operations that are in an
2596 if statement are taken away by backPatchLabels
2597 only those used in arthmetic operations remain */
2598 aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2599 aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2600 aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2602 /* if both are bit variables */
2603 if (AOP_TYPE(left) == AOP_CRY &&
2604 AOP_TYPE(right) == AOP_CRY ) {
2607 tlbl = newiTempLabel(NULL);
2609 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2611 emitLabel(tlbl->key+100);
2615 freeAsmop(left,NULL,ic);
2616 freeAsmop(right,NULL,ic);
2617 freeAsmop(result,NULL,ic);
2620 /*-----------------------------------------------------------------*/
2621 /* isLiteralBit - test if lit == 2^n */
2622 /*-----------------------------------------------------------------*/
2623 int isLiteralBit(unsigned long lit)
2625 unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
2626 0x100L,0x200L,0x400L,0x800L,
2627 0x1000L,0x2000L,0x4000L,0x8000L,
2628 0x10000L,0x20000L,0x40000L,0x80000L,
2629 0x100000L,0x200000L,0x400000L,0x800000L,
2630 0x1000000L,0x2000000L,0x4000000L,0x8000000L,
2631 0x10000000L,0x20000000L,0x40000000L,0x80000000L};
2634 for(idx = 0; idx < 32; idx++)
2640 /*-----------------------------------------------------------------*/
2641 /* jmpTrueOrFalse - */
2642 /*-----------------------------------------------------------------*/
2643 static void jmpTrueOrFalse (iCode *ic, symbol *tlbl)
2645 // ugly but optimized by peephole
2647 symbol *nlbl = newiTempLabel(NULL);
2648 emit2("jp !tlabel", nlbl->key+100);
2649 emitLabel(tlbl->key+100);
2650 emit2("jp !tlabel", IC_TRUE(ic)->key+100);
2651 emitLabel(nlbl->key+100);
2654 emit2("jp !tlabel", IC_FALSE(ic)->key+100);
2655 emitLabel(tlbl->key+100);
2660 /*-----------------------------------------------------------------*/
2661 /* genAnd - code for and */
2662 /*-----------------------------------------------------------------*/
2663 static void genAnd (iCode *ic, iCode *ifx)
2665 operand *left, *right, *result;
2667 unsigned long lit = 0L;
2670 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
2671 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
2672 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2675 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2677 AOP_TYPE(left), AOP_TYPE(right));
2678 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2680 AOP_SIZE(left), AOP_SIZE(right));
2683 /* if left is a literal & right is not then exchange them */
2684 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2685 AOP_NEEDSACC(left)) {
2686 operand *tmp = right ;
2691 /* if result = right then exchange them */
2692 if(sameRegs(AOP(result),AOP(right))){
2693 operand *tmp = right ;
2698 /* if right is bit then exchange them */
2699 if (AOP_TYPE(right) == AOP_CRY &&
2700 AOP_TYPE(left) != AOP_CRY){
2701 operand *tmp = right ;
2705 if(AOP_TYPE(right) == AOP_LIT)
2706 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2708 size = AOP_SIZE(result);
2710 if (AOP_TYPE(left) == AOP_CRY){
2715 // if(val & 0xZZ) - size = 0, ifx != FALSE -
2716 // bit = val & 0xZZ - size = 1, ifx = FALSE -
2717 if((AOP_TYPE(right) == AOP_LIT) &&
2718 (AOP_TYPE(result) == AOP_CRY) &&
2719 (AOP_TYPE(left) != AOP_CRY)) {
2720 int posbit = isLiteralBit(lit);
2724 MOVA(aopGet(AOP(left),posbit>>3,FALSE));
2728 emitcode("mov","c,acc.%d",posbit&0x07);
2733 sprintf(buffer, "%d", posbit&0x07);
2734 genIfxJump(ifx, buffer);
2742 symbol *tlbl = newiTempLabel(NULL);
2743 int sizel = AOP_SIZE(left);
2746 emitcode("setb","c");
2749 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
2750 MOVA( aopGet(AOP(left),offset,FALSE));
2752 if((posbit = isLiteralBit(bytelit)) != 0) {
2754 emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
2757 if(bytelit != 0x0FFL)
2758 emitcode("and","a,%s",
2759 aopGet(AOP(right),offset,FALSE));
2760 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2765 // bit = left & literal
2767 emitcode("clr","c");
2768 emit2("!tlabeldef", tlbl->key+100);
2770 // if(left & literal)
2773 jmpTrueOrFalse(ifx, tlbl);
2781 /* if left is same as result */
2782 if(sameRegs(AOP(result),AOP(left))){
2783 for(;size--; offset++) {
2784 if(AOP_TYPE(right) == AOP_LIT){
2785 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
2789 aopPut(AOP(result),zero,offset);
2791 MOVA(aopGet(AOP(left),offset,FALSE));
2792 emitcode("and","a,%s",
2793 aopGet(AOP(right),offset,FALSE));
2794 aopPut(AOP(left), "a", offset);
2799 if (AOP_TYPE(left) == AOP_ACC) {
2803 MOVA(aopGet(AOP(left),offset,FALSE));
2804 emitcode("and","a,%s",
2805 aopGet(AOP(right),offset,FALSE));
2806 aopPut(AOP(left), "a", offset);
2811 // left & result in different registers
2812 if(AOP_TYPE(result) == AOP_CRY){
2815 for(;(size--);offset++) {
2817 // result = left & right
2818 if(AOP_TYPE(right) == AOP_LIT){
2819 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
2821 aopGet(AOP(left),offset,FALSE),
2824 } else if(bytelit == 0){
2825 aopPut(AOP(result),zero,offset);
2829 // faster than result <- left, anl result,right
2830 // and better if result is SFR
2831 if (AOP_TYPE(left) == AOP_ACC)
2832 emitcode("and","a,%s",aopGet(AOP(right),offset,FALSE));
2834 MOVA(aopGet(AOP(left),offset,FALSE));
2835 emitcode("and","a,%s",
2836 aopGet(AOP(right),offset,FALSE));
2838 aopPut(AOP(result),"a",offset);
2845 freeAsmop(left,NULL,ic);
2846 freeAsmop(right,NULL,ic);
2847 freeAsmop(result,NULL,ic);
2850 /*-----------------------------------------------------------------*/
2851 /* genOr - code for or */
2852 /*-----------------------------------------------------------------*/
2853 static void genOr (iCode *ic, iCode *ifx)
2855 operand *left, *right, *result;
2857 unsigned long lit = 0L;
2859 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
2860 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
2861 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2864 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2866 AOP_TYPE(left), AOP_TYPE(right));
2867 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2869 AOP_SIZE(left), AOP_SIZE(right));
2872 /* if left is a literal & right is not then exchange them */
2873 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2874 AOP_NEEDSACC(left)) {
2875 operand *tmp = right ;
2880 /* if result = right then exchange them */
2881 if(sameRegs(AOP(result),AOP(right))){
2882 operand *tmp = right ;
2887 /* if right is bit then exchange them */
2888 if (AOP_TYPE(right) == AOP_CRY &&
2889 AOP_TYPE(left) != AOP_CRY){
2890 operand *tmp = right ;
2894 if(AOP_TYPE(right) == AOP_LIT)
2895 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2897 size = AOP_SIZE(result);
2899 if (AOP_TYPE(left) == AOP_CRY){
2904 if((AOP_TYPE(right) == AOP_LIT) &&
2905 (AOP_TYPE(result) == AOP_CRY) &&
2906 (AOP_TYPE(left) != AOP_CRY)){
2911 /* if left is same as result */
2912 if(sameRegs(AOP(result),AOP(left))){
2913 for(;size--; offset++) {
2914 if(AOP_TYPE(right) == AOP_LIT){
2915 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
2918 MOVA(aopGet(AOP(left),offset,FALSE));
2919 emitcode("or","a,%s",
2920 aopGet(AOP(right),offset,FALSE));
2921 aopPut(AOP(result),"a", offset);
2924 if (AOP_TYPE(left) == AOP_ACC)
2925 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
2927 MOVA(aopGet(AOP(left),offset,FALSE));
2928 emitcode("or","a,%s",
2929 aopGet(AOP(right),offset,FALSE));
2930 aopPut(AOP(result),"a", offset);
2935 // left & result in different registers
2936 if(AOP_TYPE(result) == AOP_CRY){
2938 } else for(;(size--);offset++){
2940 // result = left & right
2941 if(AOP_TYPE(right) == AOP_LIT){
2942 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
2944 aopGet(AOP(left),offset,FALSE),
2949 // faster than result <- left, anl result,right
2950 // and better if result is SFR
2951 if (AOP_TYPE(left) == AOP_ACC)
2952 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
2954 MOVA(aopGet(AOP(left),offset,FALSE));
2955 emitcode("or","a,%s",
2956 aopGet(AOP(right),offset,FALSE));
2958 aopPut(AOP(result),"a",offset);
2959 /* PENDING: something weird is going on here. Add exception. */
2960 if (AOP_TYPE(result) == AOP_ACC)
2966 freeAsmop(left,NULL,ic);
2967 freeAsmop(right,NULL,ic);
2968 freeAsmop(result,NULL,ic);
2971 /*-----------------------------------------------------------------*/
2972 /* genXor - code for xclusive or */
2973 /*-----------------------------------------------------------------*/
2974 static void genXor (iCode *ic, iCode *ifx)
2976 operand *left, *right, *result;
2978 unsigned long lit = 0L;
2980 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
2981 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
2982 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2984 /* if left is a literal & right is not then exchange them */
2985 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2986 AOP_NEEDSACC(left)) {
2987 operand *tmp = right ;
2992 /* if result = right then exchange them */
2993 if(sameRegs(AOP(result),AOP(right))){
2994 operand *tmp = right ;
2999 /* if right is bit then exchange them */
3000 if (AOP_TYPE(right) == AOP_CRY &&
3001 AOP_TYPE(left) != AOP_CRY){
3002 operand *tmp = right ;
3006 if(AOP_TYPE(right) == AOP_LIT)
3007 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3009 size = AOP_SIZE(result);
3011 if (AOP_TYPE(left) == AOP_CRY){
3016 if((AOP_TYPE(right) == AOP_LIT) &&
3017 (AOP_TYPE(result) == AOP_CRY) &&
3018 (AOP_TYPE(left) != AOP_CRY)){
3023 /* if left is same as result */
3024 if(sameRegs(AOP(result),AOP(left))){
3025 for(;size--; offset++) {
3026 if(AOP_TYPE(right) == AOP_LIT){
3027 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3030 MOVA(aopGet(AOP(right),offset,FALSE));
3031 emitcode("xor","a,%s",
3032 aopGet(AOP(left),offset,FALSE));
3033 aopPut(AOP(result),"a",0);
3036 if (AOP_TYPE(left) == AOP_ACC)
3037 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3039 MOVA(aopGet(AOP(right),offset,FALSE));
3040 emitcode("xor","a,%s",
3041 aopGet(AOP(left),offset,FALSE));
3042 aopPut(AOP(result),"a",0);
3047 // left & result in different registers
3048 if(AOP_TYPE(result) == AOP_CRY){
3050 } else for(;(size--);offset++){
3052 // result = left & right
3053 if(AOP_TYPE(right) == AOP_LIT){
3054 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3056 aopGet(AOP(left),offset,FALSE),
3061 // faster than result <- left, anl result,right
3062 // and better if result is SFR
3063 if (AOP_TYPE(left) == AOP_ACC)
3064 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3066 MOVA(aopGet(AOP(right),offset,FALSE));
3067 emitcode("xor","a,%s",
3068 aopGet(AOP(left),offset,FALSE));
3069 aopPut(AOP(result),"a",0);
3071 aopPut(AOP(result),"a",offset);
3076 freeAsmop(left,NULL,ic);
3077 freeAsmop(right,NULL,ic);
3078 freeAsmop(result,NULL,ic);
3081 /*-----------------------------------------------------------------*/
3082 /* genInline - write the inline code out */
3083 /*-----------------------------------------------------------------*/
3084 static void genInline (iCode *ic)
3086 char buffer[MAX_INLINEASM];
3090 inLine += (!options.asmpeep);
3091 strcpy(buffer,IC_INLINE(ic));
3093 /* emit each line as a code */
3112 /* emitcode("",buffer); */
3113 inLine -= (!options.asmpeep);
3116 /*-----------------------------------------------------------------*/
3117 /* genRRC - rotate right with carry */
3118 /*-----------------------------------------------------------------*/
3119 static void genRRC (iCode *ic)
3124 /*-----------------------------------------------------------------*/
3125 /* genRLC - generate code for rotate left with carry */
3126 /*-----------------------------------------------------------------*/
3127 static void genRLC (iCode *ic)
3132 /*-----------------------------------------------------------------*/
3133 /* shiftR2Left2Result - shift right two bytes from left to result */
3134 /*-----------------------------------------------------------------*/
3135 static void shiftR2Left2Result (operand *left, int offl,
3136 operand *result, int offr,
3137 int shCount, int sign)
3139 if(sameRegs(AOP(result), AOP(left)) &&
3140 ((offl + MSB16) == offr)){
3143 movLeft2Result(left, offl, result, offr, 0);
3144 movLeft2Result(left, offl+1, result, offr+1, 0);
3151 /* if (AOP(result)->type == AOP_REG) {*/
3154 symbol *tlbl , *tlbl1;
3157 /* Left is already in result - so now do the shift */
3159 emit2("ld a,!immedbyte+1", shCount);
3160 tlbl = newiTempLabel(NULL);
3161 tlbl1 = newiTempLabel(NULL);
3162 emit2("!shortjp !tlabel", tlbl1->key+100);
3163 emitLabel(tlbl->key+100);
3166 emitcode("or", "a,a");
3169 l = aopGet(AOP(result), --offset, FALSE);
3170 emitcode("rr","%s", l);
3173 emitLabel(tlbl1->key+100);
3174 emitcode("dec", "a");
3175 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3180 /*-----------------------------------------------------------------*/
3181 /* shiftL2Left2Result - shift left two bytes from left to result */
3182 /*-----------------------------------------------------------------*/
3183 static void shiftL2Left2Result (operand *left, int offl,
3184 operand *result, int offr, int shCount)
3186 if(sameRegs(AOP(result), AOP(left)) &&
3187 ((offl + MSB16) == offr)){
3190 /* Copy left into result */
3191 movLeft2Result(left, offl, result, offr, 0);
3192 movLeft2Result(left, offl+1, result, offr+1, 0);
3194 /* PENDING: for now just see if it'll work. */
3195 /*if (AOP(result)->type == AOP_REG) { */
3199 symbol *tlbl , *tlbl1;
3202 /* Left is already in result - so now do the shift */
3204 emit2("ld a,!immedbyte+1", shCount);
3205 tlbl = newiTempLabel(NULL);
3206 tlbl1 = newiTempLabel(NULL);
3207 emit2("!shortjp !tlabel", tlbl1->key+100);
3208 emitLabel(tlbl->key+100);
3211 emitcode("or", "a,a");
3213 l = aopGet(AOP(result),offset++,FALSE);
3214 emitcode("rl","%s", l);
3217 emitLabel(tlbl1->key+100);
3218 emitcode("dec", "a");
3219 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3224 /*-----------------------------------------------------------------*/
3225 /* AccRol - rotate left accumulator by known count */
3226 /*-----------------------------------------------------------------*/
3227 static void AccRol (int shCount)
3229 shCount &= 0x0007; // shCount : 0..7
3266 /*-----------------------------------------------------------------*/
3267 /* AccLsh - left shift accumulator by known count */
3268 /*-----------------------------------------------------------------*/
3269 static void AccLsh (int shCount)
3273 emitcode("add","a,a");
3276 emitcode("add","a,a");
3277 emitcode("add","a,a");
3279 /* rotate left accumulator */
3281 /* and kill the lower order bits */
3282 emit2("and a,!immedbyte", SLMask[shCount]);
3287 /*-----------------------------------------------------------------*/
3288 /* shiftL1Left2Result - shift left one byte from left to result */
3289 /*-----------------------------------------------------------------*/
3290 static void shiftL1Left2Result (operand *left, int offl,
3291 operand *result, int offr, int shCount)
3294 l = aopGet(AOP(left),offl,FALSE);
3296 /* shift left accumulator */
3298 aopPut(AOP(result),"a",offr);
3302 /*-----------------------------------------------------------------*/
3303 /* genlshTwo - left shift two bytes by known amount != 0 */
3304 /*-----------------------------------------------------------------*/
3305 static void genlshTwo (operand *result,operand *left, int shCount)
3307 int size = AOP_SIZE(result);
3311 /* if shCount >= 8 */
3317 movLeft2Result(left, LSB, result, MSB16, 0);
3318 aopPut(AOP(result),zero, 0);
3319 shiftL1Left2Result(left, MSB16, result, MSB16, shCount-8);
3322 movLeft2Result(left, LSB, result, MSB16, 0);
3323 aopPut(AOP(result),zero, 0);
3326 aopPut(AOP(result),zero,LSB);
3328 /* 1 <= shCount <= 7 */
3334 shiftL2Left2Result(left, LSB, result, LSB, shCount);
3339 /*-----------------------------------------------------------------*/
3340 /* genlshOne - left shift a one byte quantity by known count */
3341 /*-----------------------------------------------------------------*/
3342 static void genlshOne (operand *result, operand *left, int shCount)
3344 shiftL1Left2Result(left, LSB, result, LSB, shCount);
3347 /*-----------------------------------------------------------------*/
3348 /* genLeftShiftLiteral - left shifting by known count */
3349 /*-----------------------------------------------------------------*/
3350 static void genLeftShiftLiteral (operand *left,
3355 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3358 freeAsmop(right,NULL,ic);
3360 aopOp(left,ic,FALSE, FALSE);
3361 aopOp(result,ic,FALSE, FALSE);
3363 size = getSize(operandType(result));
3366 emitcode("; shift left ","result %d, left %d",size,
3370 /* I suppose that the left size >= result size */
3375 else if(shCount >= (size * 8))
3377 aopPut(AOP(result),zero,size);
3381 genlshOne (result,left,shCount);
3384 genlshTwo (result,left,shCount);
3393 freeAsmop(left,NULL,ic);
3394 freeAsmop(result,NULL,ic);
3397 /*-----------------------------------------------------------------*/
3398 /* genLeftShift - generates code for left shifting */
3399 /*-----------------------------------------------------------------*/
3400 static void genLeftShift (iCode *ic)
3404 symbol *tlbl , *tlbl1;
3405 operand *left,*right, *result;
3407 right = IC_RIGHT(ic);
3409 result = IC_RESULT(ic);
3411 aopOp(right,ic,FALSE, FALSE);
3413 /* if the shift count is known then do it
3414 as efficiently as possible */
3415 if (AOP_TYPE(right) == AOP_LIT) {
3416 genLeftShiftLiteral (left,right,result,ic);
3420 /* shift count is unknown then we have to form a loop get the loop
3421 count in B : Note: we take only the lower order byte since
3422 shifting more that 32 bits make no sense anyway, ( the largest
3423 size of an object can be only 32 bits ) */
3424 emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE));
3425 emitcode("inc","a");
3426 freeAsmop (right,NULL,ic);
3427 aopOp(left,ic,FALSE, FALSE);
3428 aopOp(result,ic,FALSE, FALSE);
3430 /* now move the left to the result if they are not the
3433 if (!sameRegs(AOP(left),AOP(result))) {
3435 size = AOP_SIZE(result);
3438 l = aopGet(AOP(left),offset,FALSE);
3439 aopPut(AOP(result),l,offset);
3444 size = AOP_SIZE(result);
3447 l = aopGet(AOP(left),offset,FALSE);
3448 aopPut(AOP(result),l,offset);
3454 tlbl = newiTempLabel(NULL);
3455 size = AOP_SIZE(result);
3457 tlbl1 = newiTempLabel(NULL);
3459 emit2("!shortjp !tlabel", tlbl1->key+100);
3460 emitLabel(tlbl->key+100);
3461 l = aopGet(AOP(result),offset,FALSE);
3462 emitcode("or", "a,a");
3464 l = aopGet(AOP(result),offset++,FALSE);
3465 emitcode("rl","%s", l);
3467 emitLabel(tlbl1->key+100);
3468 emitcode("dec", "a");
3469 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3471 freeAsmop(left,NULL,ic);
3472 freeAsmop(result,NULL,ic);
3475 /*-----------------------------------------------------------------*/
3476 /* genlshTwo - left shift two bytes by known amount != 0 */
3477 /*-----------------------------------------------------------------*/
3478 static void genrshOne (operand *result,operand *left, int shCount)
3481 int size = AOP_SIZE(result);
3487 l = aopGet(AOP(left),0,FALSE);
3488 if (AOP(result)->type == AOP_REG) {
3489 aopPut(AOP(result), l, 0);
3490 l = aopGet(AOP(result), 0, FALSE);
3492 emitcode("srl", "%s", l);
3497 emitcode("srl", "a");
3499 aopPut(AOP(result),"a",0);
3503 /*-----------------------------------------------------------------*/
3504 /* AccRsh - right shift accumulator by known count */
3505 /*-----------------------------------------------------------------*/
3506 static void AccRsh (int shCount)
3513 /* rotate right accumulator */
3514 AccRol(8 - shCount);
3515 /* and kill the higher order bits */
3516 emit2("and a,!immedbyte", SRMask[shCount]);
3521 /*-----------------------------------------------------------------*/
3522 /* shiftR1Left2Result - shift right one byte from left to result */
3523 /*-----------------------------------------------------------------*/
3524 static void shiftR1Left2Result (operand *left, int offl,
3525 operand *result, int offr,
3526 int shCount, int sign)
3528 MOVA(aopGet(AOP(left),offl,FALSE));
3535 aopPut(AOP(result),"a",offr);
3538 /*-----------------------------------------------------------------*/
3539 /* genrshTwo - right shift two bytes by known amount != 0 */
3540 /*-----------------------------------------------------------------*/
3541 static void genrshTwo (operand *result,operand *left,
3542 int shCount, int sign)
3544 /* if shCount >= 8 */
3549 shiftR1Left2Result(left, MSB16, result, LSB,
3553 movLeft2Result(left, MSB16, result, LSB, sign);
3554 aopPut(AOP(result),zero,1);
3557 /* 1 <= shCount <= 7 */
3559 shiftR2Left2Result(left, LSB, result, LSB, shCount, sign);
3563 /*-----------------------------------------------------------------*/
3564 /* genRightShiftLiteral - left shifting by known count */
3565 /*-----------------------------------------------------------------*/
3566 static void genRightShiftLiteral (operand *left,
3571 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3574 freeAsmop(right,NULL,ic);
3576 aopOp(left,ic,FALSE, FALSE);
3577 aopOp(result,ic,FALSE, FALSE);
3579 size = getSize(operandType(result));
3581 emitcode("; shift right ","result %d, left %d",size,
3584 /* I suppose that the left size >= result size */
3589 else if(shCount >= (size * 8))
3591 aopPut(AOP(result),zero,size);
3595 genrshOne(result, left, shCount);
3598 /* PENDING: sign support */
3599 genrshTwo(result, left, shCount, FALSE);
3608 freeAsmop(left,NULL,ic);
3609 freeAsmop(result,NULL,ic);
3612 /*-----------------------------------------------------------------*/
3613 /* genRightShift - generate code for right shifting */
3614 /*-----------------------------------------------------------------*/
3615 static void genRightShift (iCode *ic)
3617 operand *right, *left, *result;
3619 int size, offset, first = 1;
3623 symbol *tlbl, *tlbl1 ;
3625 /* if signed then we do it the hard way preserve the
3626 sign bit moving it inwards */
3627 retype = getSpec(operandType(IC_RESULT(ic)));
3629 is_signed = !SPEC_USIGN(retype);
3631 /* signed & unsigned types are treated the same : i.e. the
3632 signed is NOT propagated inwards : quoting from the
3633 ANSI - standard : "for E1 >> E2, is equivalent to division
3634 by 2**E2 if unsigned or if it has a non-negative value,
3635 otherwise the result is implementation defined ", MY definition
3636 is that the sign does not get propagated */
3638 right = IC_RIGHT(ic);
3640 result = IC_RESULT(ic);
3642 aopOp(right,ic,FALSE, FALSE);
3644 /* if the shift count is known then do it
3645 as efficiently as possible */
3646 if (AOP_TYPE(right) == AOP_LIT) {
3647 genRightShiftLiteral(left,right,result,ic);
3651 aopOp(left,ic,FALSE, FALSE);
3652 aopOp(result,ic,FALSE, FALSE);
3654 /* now move the left to the result if they are not the
3656 if (!sameRegs(AOP(left),AOP(result)) &&
3657 AOP_SIZE(result) > 1) {
3659 size = AOP_SIZE(result);
3662 l = aopGet(AOP(left),offset,FALSE);
3663 aopPut(AOP(result),l,offset);
3668 emitcode("ld", "a,%s",aopGet(AOP(right),0,FALSE));
3669 emitcode("inc","a");
3670 freeAsmop (right, NULL, ic);
3672 tlbl = newiTempLabel(NULL);
3673 tlbl1= newiTempLabel(NULL);
3674 size = AOP_SIZE(result);
3677 emit2("!shortjp !tlabel", tlbl1->key+100);
3678 emitLabel(tlbl->key+100);
3680 l = aopGet(AOP(result),offset--,FALSE);
3683 emitcode("sra", "%s", l);
3685 emitcode("srl", "%s", l);
3689 emitcode("rr", "%s", l);
3691 emitLabel(tlbl1->key+100);
3692 emitcode("dec", "a");
3693 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3695 freeAsmop(left,NULL,ic);
3696 freeAsmop(result,NULL,ic);
3699 /*-----------------------------------------------------------------*/
3700 /* genGenPointerGet - gget value from generic pointer space */
3701 /*-----------------------------------------------------------------*/
3702 static void genGenPointerGet (operand *left,
3703 operand *result, iCode *ic)
3706 link *retype = getSpec(operandType(result));
3712 aopOp(left,ic,FALSE, FALSE);
3713 aopOp(result,ic,FALSE, FALSE);
3715 if (isPair(AOP(left)) && AOP_SIZE(result)==1) {
3717 if (isPtrPair(AOP(left)))
3719 tsprintf(buffer, "!*pair", getPairName(AOP(left)));
3720 aopPut(AOP(result), buffer, 0);
3723 emit2("ld a,!*pair", getPairName(AOP(left)));
3724 aopPut(AOP(result),"a", 0);
3726 freeAsmop(left,NULL,ic);
3730 /* For now we always load into IY */
3731 /* if this is remateriazable */
3732 fetchPair(pair, AOP(left));
3734 /* so iy now contains the address */
3735 freeAsmop(left,NULL,ic);
3737 /* if bit then unpack */
3738 if (IS_BITVAR(retype)) {
3742 size = AOP_SIZE(result);
3746 /* PENDING: make this better */
3747 if (!IS_GB && AOP(result)->type == AOP_REG) {
3748 aopPut(AOP(result), "!*hl", offset++);
3751 emit2("ld a,!*pair", _pairs[pair].name);
3752 aopPut(AOP(result),"a",offset++);
3755 emit2("inc %s", _pairs[pair].name);
3761 freeAsmop(result,NULL,ic);
3764 /*-----------------------------------------------------------------*/
3765 /* genPointerGet - generate code for pointer get */
3766 /*-----------------------------------------------------------------*/
3767 static void genPointerGet (iCode *ic)
3769 operand *left, *result ;
3773 result = IC_RESULT(ic) ;
3775 /* depending on the type of pointer we need to
3776 move it to the correct pointer register */
3777 type = operandType(left);
3778 etype = getSpec(type);
3780 genGenPointerGet (left,result,ic);
3783 bool isRegOrLit(asmop *aop)
3785 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
3790 /*-----------------------------------------------------------------*/
3791 /* genGenPointerSet - stores the value into a pointer location */
3792 /*-----------------------------------------------------------------*/
3793 static void genGenPointerSet (operand *right,
3794 operand *result, iCode *ic)
3797 link *retype = getSpec(operandType(right));
3798 PAIR_ID pairId = PAIR_HL;
3800 aopOp(result,ic,FALSE, FALSE);
3801 aopOp(right,ic,FALSE, FALSE);
3806 /* Handle the exceptions first */
3807 if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
3809 char *l = aopGet(AOP(right), 0, FALSE);
3810 const char *pair = getPairName(AOP(result));
3811 if (canAssignToPtr(l) && isPtr(pair)) {
3812 emit2("ld !*pair,%s", pair, l);
3816 emit2("ld !*pair,a", pair);
3821 /* if the operand is already in dptr
3822 then we do nothing else we move the value to dptr */
3823 if (AOP_TYPE(result) != AOP_STR) {
3824 fetchPair(pairId, AOP(result));
3826 /* so hl know contains the address */
3827 freeAsmop(result,NULL,ic);
3829 /* if bit then unpack */
3830 if (IS_BITVAR(retype)) {
3834 size = AOP_SIZE(right);
3838 char *l = aopGet(AOP(right),offset,FALSE);
3839 if (isRegOrLit(AOP(right)) && !IS_GB) {
3840 emit2("ld !*pair,%s", _pairs[pairId].name, l);
3844 emit2("ld !*pair,a", _pairs[pairId].name);
3847 emitcode("inc", _pairs[pairId].name);
3853 freeAsmop(right,NULL,ic);
3856 /*-----------------------------------------------------------------*/
3857 /* genPointerSet - stores the value into a pointer location */
3858 /*-----------------------------------------------------------------*/
3859 static void genPointerSet (iCode *ic)
3861 operand *right, *result ;
3864 right = IC_RIGHT(ic);
3865 result = IC_RESULT(ic) ;
3867 /* depending on the type of pointer we need to
3868 move it to the correct pointer register */
3869 type = operandType(result);
3870 etype = getSpec(type);
3872 genGenPointerSet (right,result,ic);
3875 /*-----------------------------------------------------------------*/
3876 /* genIfx - generate code for Ifx statement */
3877 /*-----------------------------------------------------------------*/
3878 static void genIfx (iCode *ic, iCode *popIc)
3880 operand *cond = IC_COND(ic);
3883 aopOp(cond,ic,FALSE, TRUE);
3885 /* get the value into acc */
3886 if (AOP_TYPE(cond) != AOP_CRY)
3890 /* the result is now in the accumulator */
3891 freeAsmop(cond,NULL,ic);
3893 /* if there was something to be popped then do it */
3897 /* if the condition is a bit variable */
3898 if (isbit && IS_ITEMP(cond) &&
3900 genIfxJump(ic,SPIL_LOC(cond)->rname);
3902 if (isbit && !IS_ITEMP(cond))
3903 genIfxJump(ic,OP_SYMBOL(cond)->rname);
3910 /*-----------------------------------------------------------------*/
3911 /* genAddrOf - generates code for address of */
3912 /*-----------------------------------------------------------------*/
3913 static void genAddrOf (iCode *ic)
3915 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
3917 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
3919 /* if the operand is on the stack then we
3920 need to get the stack offset of this
3925 emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
3926 emitcode("ld", "d,h");
3927 emitcode("ld", "e,l");
3930 emitcode("ld", "de,#%s", sym->rname);
3932 aopPut(AOP(IC_RESULT(ic)), "e", 0);
3933 aopPut(AOP(IC_RESULT(ic)), "d", 1);
3938 /* if it has an offset then we need to compute it */
3939 emitcode("ld", "hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
3940 emitcode("add", "hl,sp");
3943 emitcode("ld", "hl,#%s", sym->rname);
3945 aopPut(AOP(IC_RESULT(ic)), "l", 0);
3946 aopPut(AOP(IC_RESULT(ic)), "h", 1);
3948 freeAsmop(IC_RESULT(ic),NULL,ic);
3951 /*-----------------------------------------------------------------*/
3952 /* genAssign - generate code for assignment */
3953 /*-----------------------------------------------------------------*/
3954 static void genAssign (iCode *ic)
3956 operand *result, *right;
3958 unsigned long lit = 0L;
3960 result = IC_RESULT(ic);
3961 right = IC_RIGHT(ic) ;
3964 /* Dont bother assigning if they are the same */
3965 if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) {
3966 emitcode("", "; (operands are equal %u)", operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)));
3971 aopOp(right,ic,FALSE, FALSE);
3972 aopOp(result,ic,TRUE, FALSE);
3974 /* if they are the same registers */
3975 if (sameRegs(AOP(right),AOP(result))) {
3976 emitcode("", "; (registers are the same)");
3980 /* if the result is a bit */
3981 if (AOP_TYPE(result) == AOP_CRY) {
3986 size = AOP_SIZE(result);
3989 if(AOP_TYPE(right) == AOP_LIT)
3990 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
3991 if (isPair(AOP(result)) && isLitWord(AOP(right))) {
3992 emitcode("ld", "%s,%s", getPairName(AOP(result)), aopGetWord(AOP(right), 0));
3994 else if((size > 1) &&
3995 (AOP_TYPE(result) != AOP_REG) &&
3996 (AOP_TYPE(right) == AOP_LIT) &&
3997 !IS_FLOAT(operandType(right)) &&
3999 bool fXored = FALSE;
4001 /* Work from the top down.
4002 Done this way so that we can use the cached copy of 0
4003 in A for a fast clear */
4005 if((unsigned int)((lit >> (offset*8)) & 0x0FFL)== 0) {
4006 if (!fXored && size>1) {
4007 emitcode("xor", "a,a");
4011 aopPut(AOP(result),"a",offset);
4014 aopPut(AOP(result), zero, offset);
4019 aopGet(AOP(right),offset,FALSE),
4024 else if (size == 2 && requiresHL(AOP(right)) && requiresHL(AOP(result))) {
4025 /* Special case. Load into a and d, then load out. */
4026 MOVA(aopGet(AOP(right), 0, FALSE));
4027 emitcode("ld", "e,%s", aopGet(AOP(right), 1, FALSE));
4028 aopPut(AOP(result), "a", 0);
4029 aopPut(AOP(result), "e", 1);
4032 /* PENDING: do this check better */
4033 if (requiresHL(AOP(right)) && requiresHL(AOP(result))) {
4034 MOVA(aopGet(AOP(right), offset, FALSE));
4035 aopPut(AOP(result), "a", offset);
4039 aopGet(AOP(right),offset,FALSE),
4046 freeAsmop(right,NULL,ic);
4047 freeAsmop(result,NULL,ic);
4050 /*-----------------------------------------------------------------*/
4051 /* genJumpTab - genrates code for jump table */
4052 /*-----------------------------------------------------------------*/
4053 static void genJumpTab (iCode *ic)
4058 aopOp(IC_JTCOND(ic),ic,FALSE, FALSE);
4059 /* get the condition into accumulator */
4060 l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE);
4062 emitcode("push", "de");
4063 emitcode("ld", "e,%s", l);
4064 emit2("ld d,!zero");
4065 jtab = newiTempLabel(NULL);
4067 emit2("ld hl,!immed!tlabel", jtab->key+100);
4068 emitcode("add", "hl,de");
4069 emitcode("add", "hl,de");
4070 emitcode("add", "hl,de");
4071 freeAsmop(IC_JTCOND(ic),NULL,ic);
4073 emitcode("pop", "de");
4075 emitLabel(jtab->key+100);
4076 /* now generate the jump labels */
4077 for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
4078 jtab = setNextItem(IC_JTLABELS(ic)))
4079 emit2("jp !tlabel", jtab->key+100);
4082 /*-----------------------------------------------------------------*/
4083 /* genCast - gen code for casting */
4084 /*-----------------------------------------------------------------*/
4085 static void genCast (iCode *ic)
4087 operand *result = IC_RESULT(ic);
4088 link *ctype = operandType(IC_LEFT(ic));
4089 operand *right = IC_RIGHT(ic);
4092 /* if they are equivalent then do nothing */
4093 if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
4096 aopOp(right,ic,FALSE, FALSE);
4097 aopOp(result,ic,FALSE, FALSE);
4099 /* if the result is a bit */
4100 if (AOP_TYPE(result) == AOP_CRY) {
4104 /* if they are the same size : or less */
4105 if (AOP_SIZE(result) <= AOP_SIZE(right)) {
4107 /* if they are in the same place */
4108 if (sameRegs(AOP(right),AOP(result)))
4111 /* if they in different places then copy */
4112 size = AOP_SIZE(result);
4116 aopGet(AOP(right),offset,FALSE),
4123 /* PENDING: should be OK. */
4125 /* if the result is of type pointer */
4126 if (IS_PTR(ctype)) {
4131 /* so we now know that the size of destination is greater
4132 than the size of the source */
4133 /* we move to result for the size of source */
4134 size = AOP_SIZE(right);
4138 aopGet(AOP(right),offset,FALSE),
4143 /* now depending on the sign of the destination */
4144 size = AOP_SIZE(result) - AOP_SIZE(right);
4145 /* Unsigned or not an integral type - right fill with zeros */
4146 if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) {
4148 aopPut(AOP(result),zero,offset++);
4150 /* we need to extend the sign :{ */
4151 char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
4154 emitcode("", "; genCast: sign extend untested.");
4155 emitcode("rla", "");
4156 emitcode("sbc", "a,a");
4158 aopPut(AOP(result),"a",offset++);
4162 freeAsmop(right, NULL, ic);
4163 freeAsmop(result, NULL, ic);
4166 /*-----------------------------------------------------------------*/
4167 /* genReceive - generate code for a receive iCode */
4168 /*-----------------------------------------------------------------*/
4169 static void genReceive (iCode *ic)
4171 if (isOperandInFarSpace(IC_RESULT(ic)) &&
4172 ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
4173 IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
4177 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
4179 assignResultValue(IC_RESULT(ic));
4182 freeAsmop(IC_RESULT(ic),NULL,ic);
4185 /*-----------------------------------------------------------------*/
4186 /* genZ80Code - generate code for Z80 based controllers */
4187 /*-----------------------------------------------------------------*/
4188 void genZ80Code (iCode *lic)
4195 _fReturn = _gbz80_return;
4196 _fTmp = _gbz80_return;
4199 _fReturn = _z80_return;
4200 _fTmp = _z80_return;
4202 tsprintf(zero, "!zero");
4204 lineHead = lineCurr = NULL;
4206 /* if debug information required */
4207 if (options.debug && currFunc) {
4208 cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
4210 if (IS_STATIC(currFunc->etype))
4211 emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name);
4213 emitcode("","G$%s$0$0 ==.",currFunc->name);
4216 /* stack pointer name */
4220 for (ic = lic ; ic ; ic = ic->next ) {
4222 if ( cln != ic->lineno ) {
4223 if ( options.debug ) {
4225 emitcode("","C$%s$%d$%d$%d ==.",
4226 ic->filename,ic->lineno,
4227 ic->level,ic->block);
4230 emitcode(";","%s %d",ic->filename,ic->lineno);
4233 /* if the result is marked as
4234 spilt and rematerializable or code for
4235 this has already been generated then
4237 if (resultRemat(ic) || ic->generated )
4240 /* depending on the operation */
4243 emitcode("", "; genNot");
4248 emitcode("", "; genCpl");
4253 emitcode("", "; genUminus");
4258 emitcode("", "; genIpush");
4263 /* IPOP happens only when trying to restore a
4264 spilt live range, if there is an ifx statement
4265 following this pop then the if statement might
4266 be using some of the registers being popped which
4267 would destory the contents of the register so
4268 we need to check for this condition and handle it */
4270 ic->next->op == IFX &&
4271 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) {
4272 emitcode("", "; genIfx");
4273 genIfx (ic->next,ic);
4276 emitcode("", "; genIpop");
4282 emitcode("", "; genCall");
4287 emitcode("", "; genPcall");
4292 emitcode("", "; genFunction");
4297 emitcode("", "; genEndFunction");
4298 genEndFunction (ic);
4302 emitcode("", "; genRet");
4307 emitcode("", "; genLabel");
4312 emitcode("", "; genGoto");
4317 emitcode("", "; genPlus");
4322 emitcode("", "; genMinus");
4327 emitcode("", "; genMult");
4332 emitcode("", "; genDiv");
4337 emitcode("", "; genMod");
4342 emitcode("", "; genCmpGt");
4343 genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));
4347 emitcode("", "; genCmpLt");
4348 genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
4355 /* note these two are xlated by algebraic equivalence
4356 during parsing SDCC.y */
4357 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
4358 "got '>=' or '<=' shouldn't have come here");
4362 emitcode("", "; genCmpEq");
4363 genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
4367 emitcode("", "; genAndOp");
4372 emitcode("", "; genOrOp");
4377 emitcode("", "; genXor");
4378 genXor (ic,ifxForOp(IC_RESULT(ic),ic));
4382 emitcode("", "; genOr");
4383 genOr (ic,ifxForOp(IC_RESULT(ic),ic));
4387 emitcode("", "; genAnd");
4388 genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
4392 emitcode("", "; genInline");
4397 emitcode("", "; genRRC");
4402 emitcode("", "; genRLC");
4407 emitcode("", "; genHBIT");
4411 emitcode("", "; genLeftShift");
4416 emitcode("", "; genRightShift");
4420 case GET_VALUE_AT_ADDRESS:
4421 emitcode("", "; genPointerGet");
4427 if (POINTER_SET(ic)) {
4428 emitcode("", "; genAssign (pointer)");
4432 emitcode("", "; genAssign");
4438 emitcode("", "; genIfx");
4443 emitcode("", "; genAddrOf");
4448 emitcode("", "; genJumpTab");
4453 emitcode("", "; genCast");
4458 emitcode("", "; genReceive");
4463 emitcode("", "; addSet");
4464 addSet(&sendSet,ic);
4469 /* piCode(ic,stdout); */
4475 /* now we are ready to call the
4476 peep hole optimizer */
4477 if (!options.nopeep)
4478 peepHole (&lineHead);
4480 /* now do the actual printing */
4481 printLine (lineHead,codeOutFile);