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 -
23 Sandeep Dutta . sandeep.dutta@usa.net (1998)
24 and - Jean-Louis VERN.jlvern@writeme.com (1999)
26 This program is free software; you can redistribute it and/or modify it
27 under the terms of the GNU General Public License as published by the
28 Free Software Foundation; either version 2, or (at your option) any
31 This program is distributed in the hope that it will be useful,
32 but WITHOUT ANY WARRANTY; without even the implied warranty of
33 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 GNU General Public License for more details.
37 You should have received a copy of the GNU General Public License
38 along with this program; if not, write to the Free Software
39 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
41 In other words, you are welcome to use, share and improve this program.
42 You are forbidden to forbid anyone else to use, share and improve
43 what you give them. Help stamp out software-hoarding!
45 -------------------------------------------------------------------------*/
52 #ifdef HAVE_SYS_ISA_DEFS_H
53 #include <sys/isa_defs.h>
57 #include "SDCCpeeph.h"
61 /* this is the down and dirty file with all kinds of kludgy & hacky
62 stuff. This is what it is all about CODE GENERATION for a specific MCU.
63 Some of the routines may be reusable, will have to see */
66 static char *_z80_return[] = {"l", "h", "e", "d" };
67 static char *_gbz80_return[] = { "e", "d", "l", "h" };
68 static char **_fReturn;
74 static char *accUse[] = {"a" };
75 static char *hlUse[] = { "l", "h" };
81 extern int ptrRegReq ;
83 extern FILE *codeOutFile;
100 } _pairs[NUM_PAIRS] = {
105 { "iy", "iy.l?", "iy.h?" },
106 { "ix", "ix.l?", "ix.h?" }
109 #define RESULTONSTACK(x) \
110 (IC_RESULT(x) && IC_RESULT(x)->aop && \
111 IC_RESULT(x)->aop->type == AOP_STK )
113 #define MOVA(x) if (strcmp(x,"a")) emitcode("ld","a,%s",x);
114 #define CLRC emitcode("xor","a,a");
116 lineNode *lineHead = NULL;
117 lineNode *lineCurr = NULL;
119 static const unsigned char SLMask[] =
120 {0xFF ,0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00};
121 static const unsigned char SRMask[] =
122 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00};
150 static char *aopGet(asmop *aop, int offset, bool bit16);
152 static void _tidyUp(char *buf)
154 /* Clean up the line so that it is 'prettier' */
155 if (strchr(buf, ':')) {
156 /* Is a label - cant do anything */
159 /* Change the first (and probably only) ' ' to a tab so
171 static void emit2(const char *szFormat, ...)
176 va_start(ap, szFormat);
178 tvsprintf(buffer, szFormat, ap);
181 lineCurr = (lineCurr ?
182 connectLine(lineCurr,newLineNode(buffer)) :
183 (lineHead = newLineNode(buffer)));
185 lineCurr->isInline = inLine;
186 lineCurr->isDebug = debugLine;
189 /*-----------------------------------------------------------------*/
190 /* emitcode - writes the code into a file : for now it is simple */
191 /*-----------------------------------------------------------------*/
192 void emitcode (const char *inst, const char *fmt, ...)
195 char lb[MAX_INLINEASM];
201 sprintf(lb,"%s\t",inst);
202 vsprintf(lb+(strlen(lb)),fmt,ap);
206 while (isspace(*lbp)) lbp++;
209 lineCurr = (lineCurr ?
210 connectLine(lineCurr,newLineNode(lb)) :
211 (lineHead = newLineNode(lb)));
212 lineCurr->isInline = inLine;
213 lineCurr->isDebug = debugLine;
230 emitcode("ld", "sp,ix");
231 emitcode("pop", "ix");
232 emitcode("pop", "de");
237 const char *getPairName(asmop *aop)
239 if (aop->type == AOP_REG) {
240 switch (aop->aopu.aop_reg[0]->rIdx) {
252 else if (aop->type == AOP_STR) {
253 switch (*aop->aopu.aop_str[0]) {
269 static PAIR_ID getPairId(asmop *aop)
271 if (aop->size == 2) {
272 if (aop->type == AOP_REG) {
273 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX)&&(aop->aopu.aop_reg[1]->rIdx == B_IDX)) {
276 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX)&&(aop->aopu.aop_reg[1]->rIdx == D_IDX)) {
279 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX)&&(aop->aopu.aop_reg[1]->rIdx == H_IDX)) {
283 if (aop->type == AOP_STR) {
284 if (!strcmp(aop->aopu.aop_str[0], "c")&&!strcmp(aop->aopu.aop_str[1], "b")) {
287 if (!strcmp(aop->aopu.aop_str[0], "e")&&!strcmp(aop->aopu.aop_str[1], "d")) {
290 if (!strcmp(aop->aopu.aop_str[0], "l")&&!strcmp(aop->aopu.aop_str[1], "h")) {
298 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
299 bool isPair(asmop *aop)
301 return (getPairId(aop) != PAIR_INVALID);
304 bool isPtrPair(asmop *aop)
306 PAIR_ID pairId = getPairId(aop);
316 /** Push a register pair onto the stack */
317 void genPairPush(asmop *aop)
319 emitcode("push", "%s", getPairName(aop));
323 /*-----------------------------------------------------------------*/
324 /* newAsmop - creates a new asmOp */
325 /*-----------------------------------------------------------------*/
326 static asmop *newAsmop (short type)
330 ALLOC(aop,sizeof(asmop));
335 /*-----------------------------------------------------------------*/
336 /* aopForSym - for a true symbol */
337 /*-----------------------------------------------------------------*/
338 static asmop *aopForSym (iCode *ic,symbol *sym,bool result, bool requires_a)
347 space = SPEC_OCLS(sym->etype);
349 /* if already has one */
353 /* Assign depending on the storage class */
354 if (sym->onStack || sym->iaccess) {
355 emitcode("", "; AOP_STK for %s", sym->rname);
356 sym->aop = aop = newAsmop(AOP_STK);
357 aop->size = getSize(sym->type);
358 aop->aopu.aop_stk = sym->stack;
362 /* special case for a function */
363 if (IS_FUNC(sym->type)) {
364 sym->aop = aop = newAsmop(AOP_IMMD);
365 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(sym->rname)+1);
366 strcpy(aop->aopu.aop_immd,sym->rname);
372 /* if it is in direct space */
373 if (IN_REGSP(space) && !requires_a) {
374 sym->aop = aop = newAsmop (AOP_SFR);
375 aop->aopu.aop_dir = sym->rname ;
376 aop->size = getSize(sym->type);
377 emitcode("", "; AOP_SFR for %s", sym->rname);
382 /* only remaining is far space */
383 /* in which case DPTR gets the address */
385 emitcode("", "; AOP_HL for %s", sym->rname);
386 sym->aop = aop = newAsmop(AOP_HL);
389 sym->aop = aop = newAsmop(AOP_IY);
391 aop->size = getSize(sym->type);
392 aop->aopu.aop_dir = sym->rname;
394 /* if it is in code space */
395 if (IN_CODESPACE(space))
401 /*-----------------------------------------------------------------*/
402 /* aopForRemat - rematerialzes an object */
403 /*-----------------------------------------------------------------*/
404 static asmop *aopForRemat (symbol *sym)
407 iCode *ic = sym->rematiCode;
408 asmop *aop = newAsmop(AOP_IMMD);
411 /* if plus or minus print the right hand side */
412 if (ic->op == '+' || ic->op == '-') {
413 /* PENDING: for re-target */
414 sprintf(s,"0x%04x %c ",(int) operandLitValue(IC_RIGHT(ic)),
417 ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode;
420 /* we reached the end */
421 sprintf(s,"%s",OP_SYMBOL(IC_LEFT(ic))->rname);
425 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(buffer)+1);
426 strcpy(aop->aopu.aop_immd,buffer);
430 /*-----------------------------------------------------------------*/
431 /* regsInCommon - two operands have some registers in common */
432 /*-----------------------------------------------------------------*/
433 bool regsInCommon (operand *op1, operand *op2)
438 /* if they have registers in common */
439 if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
442 sym1 = OP_SYMBOL(op1);
443 sym2 = OP_SYMBOL(op2);
445 if (sym1->nRegs == 0 || sym2->nRegs == 0)
448 for (i = 0 ; i < sym1->nRegs ; i++) {
453 for (j = 0 ; j < sym2->nRegs ;j++ ) {
457 if (sym2->regs[j] == sym1->regs[i])
465 /*-----------------------------------------------------------------*/
466 /* operandsEqu - equivalent */
467 /*-----------------------------------------------------------------*/
468 bool operandsEqu ( operand *op1, operand *op2)
472 /* if they not symbols */
473 if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
476 sym1 = OP_SYMBOL(op1);
477 sym2 = OP_SYMBOL(op2);
479 /* if both are itemps & one is spilt
480 and the other is not then false */
481 if (IS_ITEMP(op1) && IS_ITEMP(op2) &&
482 sym1->isspilt != sym2->isspilt )
485 /* if they are the same */
489 if (strcmp(sym1->rname,sym2->rname) == 0)
493 /* if left is a tmp & right is not */
497 (sym1->usl.spillLoc == sym2))
504 (sym2->usl.spillLoc == sym1))
510 /*-----------------------------------------------------------------*/
511 /* sameRegs - two asmops have the same registers */
512 /*-----------------------------------------------------------------*/
513 bool sameRegs (asmop *aop1, asmop *aop2 )
517 if (aop1->type == AOP_SFR ||
518 aop2->type == AOP_SFR)
524 if (aop1->type != AOP_REG ||
525 aop2->type != AOP_REG )
528 if (aop1->size != aop2->size)
531 for (i = 0 ; i < aop1->size ; i++ )
532 if (aop1->aopu.aop_reg[i] !=
533 aop2->aopu.aop_reg[i] )
539 /*-----------------------------------------------------------------*/
540 /* aopOp - allocates an asmop for an operand : */
541 /*-----------------------------------------------------------------*/
542 static void aopOp (operand *op, iCode *ic, bool result, bool requires_a)
551 /* if this a literal */
552 if (IS_OP_LITERAL(op)) {
553 op->aop = aop = newAsmop(AOP_LIT);
554 aop->aopu.aop_lit = op->operand.valOperand;
555 aop->size = getSize(operandType(op));
559 /* if already has a asmop then continue */
563 /* if the underlying symbol has a aop */
564 if (IS_SYMOP(op) && OP_SYMBOL(op)->aop) {
565 op->aop = OP_SYMBOL(op)->aop;
569 /* if this is a true symbol */
570 if (IS_TRUE_SYMOP(op)) {
571 op->aop = aopForSym(ic, OP_SYMBOL(op), result, requires_a);
575 /* this is a temporary : this has
581 e) can be a return use only */
585 /* if the type is a conditional */
586 if (sym->regType == REG_CND) {
587 aop = op->aop = sym->aop = newAsmop(AOP_CRY);
592 /* if it is spilt then two situations
594 b) has a spill location */
595 if (sym->isspilt || sym->nRegs == 0) {
596 /* rematerialize it NOW */
598 sym->aop = op->aop = aop =
600 aop->size = getSize(sym->type);
606 if (sym->accuse == ACCUSE_A) {
607 aop = op->aop = sym->aop = newAsmop(AOP_ACC);
608 aop->size = getSize(sym->type);
609 for ( i = 0 ; i < 2 ; i++ )
610 aop->aopu.aop_str[i] = accUse[i];
612 else if (sym->accuse == ACCUSE_HL) {
614 aop = op->aop = sym->aop = newAsmop(AOP_HLREG);
615 aop->size = getSize(sym->type);
616 for ( i = 0 ; i < 2 ; i++ )
617 aop->aopu.aop_str[i] = hlUse[i];
626 aop = op->aop = sym->aop = newAsmop(AOP_STR);
627 aop->size = getSize(sym->type);
628 for ( i = 0 ; i < 4 ; i++ )
629 aop->aopu.aop_str[i] = _fReturn[i];
633 /* else spill location */
634 sym->aop = op->aop = aop =
635 aopForSym(ic,sym->usl.spillLoc,result, requires_a);
636 aop->size = getSize(sym->type);
640 /* must be in a register */
641 sym->aop = op->aop = aop = newAsmop(AOP_REG);
642 aop->size = sym->nRegs;
643 for ( i = 0 ; i < sym->nRegs ;i++)
644 aop->aopu.aop_reg[i] = sym->regs[i];
647 /*-----------------------------------------------------------------*/
648 /* freeAsmop - free up the asmop given to an operand */
649 /*----------------------------------------------------------------*/
650 static void freeAsmop (operand *op, asmop *aaop, iCode *ic)
668 /* all other cases just dealloc */
672 OP_SYMBOL(op)->aop = NULL;
673 /* if the symbol has a spill */
675 SPIL_LOC(op)->aop = NULL;
680 bool isLitWord(asmop *aop)
682 /* if (aop->size != 2)
693 char *aopGetLitWordLong(asmop *aop, int offset, bool with_hash)
699 if (aop->size != 2 && aop->type != AOP_HL)
702 /* depending on type */
707 /* PENDING: for re-target */
709 tsprintf(s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
711 tsprintf(s, "%s + %d", aop->aopu.aop_immd, offset);
712 ALLOC_ATOMIC(rs,strlen(s)+1);
716 value * val = aop->aopu.aop_lit;
717 /* if it is a float then it gets tricky */
718 /* otherwise it is fairly simple */
719 if (!IS_FLOAT(val->type)) {
720 unsigned long v = floatFromVal(val);
724 tsprintf(buffer, "!immedword", v);
726 tsprintf(buffer, "!constword", v);
727 ALLOC_ATOMIC(rs,strlen(buffer)+1);
728 return strcpy (rs,buffer);
733 convertFloat(&f, floatFromVal(val));
735 tsprintf(buffer, "!immedword", f.w[offset/2]);
737 tsprintf(buffer, "!constword", f.w[offset/2]);
738 ALLOC_ATOMIC(rs,strlen(buffer)+1);
739 return strcpy (rs,buffer);
747 char *aopGetWord(asmop *aop, int offset)
749 return aopGetLitWordLong(aop, offset, TRUE);
752 bool isPtr(const char *s)
754 if (!strcmp(s, "hl"))
756 if (!strcmp(s, "ix"))
758 if (!strcmp(s, "iy"))
763 static void adjustPair(const char *pair, int *pold, int new)
767 while (*pold < new) {
768 emitcode("inc", "%s", pair);
771 while (*pold > new) {
772 emitcode("dec", "%s", pair);
777 static void spillPair(PAIR_ID pairId)
779 _G.pairs[pairId].last_type = AOP_INVALID;
780 _G.pairs[pairId].lit = NULL;
783 static void spillCached(void)
789 static bool requiresHL(asmop *aop)
800 static void fetchLitPair(PAIR_ID pairId, asmop *left, int offset)
803 const char *pair = _pairs[pairId].name;
804 l = aopGetLitWordLong(left, offset, FALSE);
808 if (pairId == PAIR_HL || pairId == PAIR_IY) {
809 if (_G.pairs[pairId].last_type == left->type) {
810 if (_G.pairs[pairId].lit && !strcmp(_G.pairs[pairId].lit, l)) {
811 if (pairId == PAIR_HL && abs(_G.pairs[pairId].offset - offset) < 3) {
812 adjustPair(pair, &_G.pairs[pairId].offset, offset);
815 if (pairId == PAIR_IY && abs(offset)<127) {
821 _G.pairs[pairId].last_type = left->type;
822 _G.pairs[pairId].lit = gc_strdup(l);
823 _G.pairs[pairId].offset = offset;
825 /* Both a lit on the right and a true symbol on the left */
826 /* PENDING: for re-target */
829 emit2("ld %s,!hashedstr + %d", pair, l, offset);
832 emit2("ld %s,!hashedstr", pair, l);
835 static void fetchPairLong(PAIR_ID pairId, asmop *aop, int offset)
837 /* if this is remateriazable */
838 if (isLitWord(aop)) {
839 fetchLitPair(pairId, aop, offset);
841 else { /* we need to get it byte by byte */
842 if (pairId == PAIR_HL && IS_GB && requiresHL(aop)) {
843 aopGet(aop, offset, FALSE);
848 else if (IS_Z80 && aop->type == AOP_IY) {
849 /* Instead of fetching relative to IY, just grab directly
850 from the address IY refers to */
851 char *l = aopGetLitWordLong(aop, offset, FALSE);
853 emit2("ld %s,(%s)", _pairs[pairId].name, l);
856 emitcode("ld", "%s,%s", _pairs[pairId].l, aopGet(aop, offset, FALSE));
857 emitcode("ld", "%s,%s", _pairs[pairId].h, aopGet(aop, offset+1, FALSE));
859 /* PENDING: check? */
860 if (pairId == PAIR_HL)
865 static void fetchPair(PAIR_ID pairId, asmop *aop)
867 fetchPairLong(pairId, aop, 0);
870 static void fetchHL(asmop *aop)
872 fetchPair(PAIR_HL, aop);
875 static void setupPair(PAIR_ID pairId, asmop *aop, int offset)
877 assert(pairId == PAIR_HL || pairId == PAIR_IY);
881 fetchLitPair(pairId, aop, 0);
884 fetchLitPair(pairId, aop, offset);
885 _G.pairs[pairId].offset = offset;
888 /* Doesnt include _G.stack.pushed */
889 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
890 assert(pairId == PAIR_HL);
891 /* In some cases we can still inc or dec hl */
892 if (_G.pairs[pairId].last_type == AOP_STK && abs(_G.pairs[pairId].offset - abso) < 3) {
893 adjustPair(_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
896 emit2("!ldahlsp", aop->aopu.aop_stk+offset + _G.stack.pushed + _G.stack.offset);
898 _G.pairs[pairId].offset = abso;
904 _G.pairs[pairId].last_type = aop->type;
907 static void emitLabel(int key)
909 emit2("!tlabeldef", key);
913 /*-----------------------------------------------------------------*/
914 /* aopGet - for fetching value of the aop */
915 /*-----------------------------------------------------------------*/
916 static char *aopGet(asmop *aop, int offset, bool bit16)
921 /* offset is greater than size then zero */
922 /* PENDING: this seems a bit screwed in some pointer cases. */
923 if (offset > (aop->size - 1) &&
924 aop->type != AOP_LIT)
927 /* depending on type */
930 /* PENDING: re-target */
932 tsprintf (s,"!immedwords", aop->aopu.aop_immd);
935 wassert(offset == 1);
936 tsprintf(s, "!lsbimmeds", aop->aopu.aop_immd);
939 tsprintf(s, "!msbimmeds", aop->aopu.aop_immd);
940 ALLOC_ATOMIC(rs,strlen(s)+1);
946 emitcode("ld", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
948 ALLOC_ATOMIC(rs,strlen(s)+1);
954 emitcode("ldh", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
956 ALLOC_ATOMIC(rs,strlen(s)+1);
961 return aop->aopu.aop_reg[offset]->name;
965 setupPair(PAIR_HL, aop, offset);
971 setupPair(PAIR_IY, aop, offset);
972 tsprintf(s,"!*iyx", offset);
973 ALLOC_ATOMIC(rs,strlen(s)+1);
979 setupPair(PAIR_HL, aop, offset);
983 tsprintf(s,"!*ixx", aop->aopu.aop_stk+offset);
985 ALLOC_ATOMIC(rs,strlen(s)+1);
1000 return aop->aopu.aop_str[offset];
1003 return aopLiteral (aop->aopu.aop_lit,offset);
1007 return aop->aopu.aop_str[offset];
1011 wassertl(0, "aopget got unsupported aop->type");
1015 bool isRegString(char *s)
1017 if (!strcmp(s, "b") ||
1028 bool isConstant(const char *s)
1030 /* This is a bit of a hack... */
1031 return (*s == '#' || *s == '$');
1034 bool canAssignToPtr(char *s)
1043 /*-----------------------------------------------------------------*/
1044 /* aopPut - puts a string for a aop */
1045 /*-----------------------------------------------------------------*/
1046 static void aopPut (asmop *aop, char *s, int offset)
1048 if (aop->size && offset > ( aop->size - 1)) {
1049 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1050 "aopPut got offset > aop->size");
1054 /* will assign value to value */
1055 /* depending on where it is ofcourse */
1056 switch (aop->type) {
1061 emitcode("ld", "a,%s", s);
1062 emitcode("ld", "(%s+%d),a", aop->aopu.aop_dir, offset);
1068 emitcode("ld", "a,%s", s);
1069 emitcode("ldh", "(%s+%d),a", aop->aopu.aop_dir, offset);
1073 if (!strcmp(s, "!*hl"))
1074 emit2("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1077 aop->aopu.aop_reg[offset]->name, s);
1082 setupPair(PAIR_IY, aop, offset);
1083 if (!canAssignToPtr(s)) {
1084 emit2("ld a,%s", s);
1085 emit2("ld !*iyx,a", offset);
1088 emit2("ld !*iyx,%s", offset, s);
1093 /* PENDING: for re-target */
1094 if (!strcmp(s, "!*hl") || !strcmp(s, "(hl)") || !strcmp(s, "[hl]")) {
1098 setupPair(PAIR_HL, aop, offset);
1100 emit2("ld !*hl,%s", s);
1105 /* PENDING: re-target */
1106 if (!strcmp(s, "!*hl") || !strcmp(s, "(hl)") || !strcmp(s, "[hl]")) {
1110 setupPair(PAIR_HL, aop, offset);
1111 if (!canAssignToPtr(s)) {
1112 emit2("ld a,%s", s);
1116 emit2("ld !*hl,%s ; 3", s);
1119 if (!canAssignToPtr(s)) {
1120 emit2("ld a,%s", s);
1121 emit2("ld !*ixx,a", aop->aopu.aop_stk+offset);
1124 emit2("ld !*ixx,%s", aop->aopu.aop_stk+offset, s);
1129 /* if bit variable */
1130 if (!aop->aopu.aop_dir) {
1134 /* In bit space but not in C - cant happen */
1141 if (strcmp(aop->aopu.aop_str[offset],s)) {
1142 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1148 if (!offset && (strcmp(s,"acc") == 0))
1152 emitcode("", "; Error aopPut AOP_ACC");
1155 if (strcmp(aop->aopu.aop_str[offset],s))
1156 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1161 wassert(offset < 2);
1162 emit2("ld %s,%s", aop->aopu.aop_str[offset], s);
1166 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1167 "aopPut got unsupported aop->type");
1172 #define AOP(op) op->aop
1173 #define AOP_TYPE(op) AOP(op)->type
1174 #define AOP_SIZE(op) AOP(op)->size
1175 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1177 /*-----------------------------------------------------------------*/
1178 /* getDataSize - get the operand data size */
1179 /*-----------------------------------------------------------------*/
1180 int getDataSize(operand *op)
1183 size = AOP_SIZE(op);
1191 /*-----------------------------------------------------------------*/
1192 /* movLeft2Result - move byte from left to result */
1193 /*-----------------------------------------------------------------*/
1194 static void movLeft2Result (operand *left, int offl,
1195 operand *result, int offr, int sign)
1198 if(!sameRegs(AOP(left),AOP(result)) || (offl != offr)){
1199 l = aopGet(AOP(left),offl,FALSE);
1202 aopPut(AOP(result),l,offr);
1211 /** Put Acc into a register set
1213 void outAcc(operand *result)
1216 size = getDataSize(result);
1218 aopPut(AOP(result),"a",0);
1221 /* unsigned or positive */
1223 aopPut(AOP(result), zero, offset++);
1228 /** Take the value in carry and put it into a register
1230 void outBitC(operand *result)
1232 /* if the result is bit */
1233 if (AOP_TYPE(result) == AOP_CRY) {
1234 emitcode("", "; Note: outBitC form 1");
1235 aopPut(AOP(result),"blah",0);
1238 emit2("ld a,!zero");
1244 /*-----------------------------------------------------------------*/
1245 /* toBoolean - emit code for orl a,operator(sizeop) */
1246 /*-----------------------------------------------------------------*/
1247 void toBoolean(operand *oper)
1249 int size = AOP_SIZE(oper);
1252 emitcode("ld", "a,%s", aopGet(AOP(oper), offset++, FALSE));
1255 emitcode("or","a,%s",aopGet(AOP(oper),offset++,FALSE));
1258 if (AOP(oper)->type != AOP_ACC) {
1260 emitcode("or","a,%s",aopGet(AOP(oper),0,FALSE));
1265 /*-----------------------------------------------------------------*/
1266 /* genNot - generate code for ! operation */
1267 /*-----------------------------------------------------------------*/
1268 static void genNot (iCode *ic)
1270 link *optype = operandType(IC_LEFT(ic));
1272 /* assign asmOps to operand & result */
1273 aopOp (IC_LEFT(ic),ic,FALSE, TRUE);
1274 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1276 /* if in bit space then a special case */
1277 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) {
1281 /* if type float then do float */
1282 if (IS_FLOAT(optype)) {
1286 toBoolean(IC_LEFT(ic));
1291 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1292 emit2("sub a,!one");
1293 outBitC(IC_RESULT(ic));
1295 /* release the aops */
1296 freeAsmop(IC_LEFT(ic),NULL,ic);
1297 freeAsmop(IC_RESULT(ic),NULL,ic);
1300 /*-----------------------------------------------------------------*/
1301 /* genCpl - generate code for complement */
1302 /*-----------------------------------------------------------------*/
1303 static void genCpl (iCode *ic)
1309 /* assign asmOps to operand & result */
1310 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
1311 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1313 /* if both are in bit space then
1315 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1316 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1320 size = AOP_SIZE(IC_RESULT(ic));
1322 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1325 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1328 /* release the aops */
1329 freeAsmop(IC_LEFT(ic),NULL,ic);
1330 freeAsmop(IC_RESULT(ic),NULL,ic);
1333 /*-----------------------------------------------------------------*/
1334 /* genUminus - unary minus code generation */
1335 /*-----------------------------------------------------------------*/
1336 static void genUminus (iCode *ic)
1339 link *optype, *rtype;
1342 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1343 aopOp(IC_RESULT(ic),ic,TRUE, FALSE);
1345 /* if both in bit space then special
1347 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1348 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
1353 optype = operandType(IC_LEFT(ic));
1354 rtype = operandType(IC_RESULT(ic));
1356 /* if float then do float stuff */
1357 if (IS_FLOAT(optype)) {
1362 /* otherwise subtract from zero */
1363 size = AOP_SIZE(IC_LEFT(ic));
1367 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1368 emit2("ld a,!zero");
1369 emit2("sbc a,%s",l);
1370 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1373 /* if any remaining bytes in the result */
1374 /* we just need to propagate the sign */
1375 if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic))))) {
1379 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1383 /* release the aops */
1384 freeAsmop(IC_LEFT(ic),NULL,ic);
1385 freeAsmop(IC_RESULT(ic),NULL,ic);
1388 static void _push(PAIR_ID pairId)
1390 emit2("push %s", _pairs[pairId].name);
1391 _G.stack.pushed += 2;
1394 static void _pop(PAIR_ID pairId)
1396 emit2("pop %s", _pairs[pairId].name);
1397 _G.stack.pushed -= 2;
1401 /*-----------------------------------------------------------------*/
1402 /* assignResultValue - */
1403 /*-----------------------------------------------------------------*/
1404 void assignResultValue(operand * oper)
1406 int size = AOP_SIZE(oper);
1410 topInA = requiresHL(AOP(oper));
1416 if (IS_GB && size == 4 && requiresHL(AOP(oper))) {
1417 /* We do it the hard way here. */
1419 aopPut(AOP(oper), _fReturn[0], 0);
1420 aopPut(AOP(oper), _fReturn[1], 1);
1421 emitcode("pop", "de");
1422 _G.stack.pushed -= 2;
1423 aopPut(AOP(oper), _fReturn[0], 2);
1424 aopPut(AOP(oper), _fReturn[1], 3);
1428 aopPut(AOP(oper), _fReturn[size], size);
1433 /*-----------------------------------------------------------------*/
1434 /* genIpush - genrate code for pushing this gets a little complex */
1435 /*-----------------------------------------------------------------*/
1436 static void genIpush (iCode *ic)
1438 int size, offset = 0 ;
1441 /* if this is not a parm push : ie. it is spill push
1442 and spill push is always done on the local stack */
1443 if (!ic->parmPush) {
1444 /* and the item is spilt then do nothing */
1445 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1448 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1449 size = AOP_SIZE(IC_LEFT(ic));
1450 /* push it on the stack */
1451 if (isPair(AOP(IC_LEFT(ic)))) {
1452 emitcode("push", getPairName(AOP(IC_LEFT(ic))));
1453 _G.stack.pushed += 2;
1458 /* Simple for now - load into A and PUSH AF */
1459 if (AOP(IC_LEFT(ic))->type == AOP_IY) {
1460 char *l = aopGetLitWordLong(AOP(IC_LEFT(ic)), --offset, FALSE);
1462 emit2("ld a,(%s)", l);
1465 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1466 emit2("ld a,%s", l);
1476 /* Hmmm... what about saving the currently used registers
1479 /* then do the push */
1480 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1482 size = AOP_SIZE(IC_LEFT(ic));
1484 if (isPair(AOP(IC_LEFT(ic)))) {
1486 emitcode("push", "%s", getPairName(AOP(IC_LEFT(ic))));
1490 fetchHL(AOP(IC_LEFT(ic)));
1491 emitcode("push", "hl");
1493 _G.stack.pushed += 2;
1497 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
1498 emitcode("push", "hl");
1500 _G.stack.pushed += 2;
1501 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 0);
1502 emitcode("push", "hl");
1504 _G.stack.pushed += 2;
1509 if (AOP(IC_LEFT(ic))->type == AOP_IY) {
1510 char *l = aopGetLitWordLong(AOP(IC_LEFT(ic)), --offset, FALSE);
1512 emit2("ld a,(%s)", l);
1515 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1516 emit2("ld a,%s", l);
1518 emitcode("push", "af");
1519 emitcode("inc", "sp");
1524 freeAsmop(IC_LEFT(ic),NULL,ic);
1527 /*-----------------------------------------------------------------*/
1528 /* genIpop - recover the registers: can happen only for spilling */
1529 /*-----------------------------------------------------------------*/
1530 static void genIpop (iCode *ic)
1535 /* if the temp was not pushed then */
1536 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1539 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1540 size = AOP_SIZE(IC_LEFT(ic));
1542 if (isPair(AOP(IC_LEFT(ic)))) {
1543 emitcode("pop", getPairName(AOP(IC_LEFT(ic))));
1547 emitcode("dec", "sp");
1548 emitcode("pop", "hl");
1550 aopPut(AOP(IC_LEFT(ic)), "l", offset--);
1554 freeAsmop(IC_LEFT(ic),NULL,ic);
1557 static int _isPairUsed(iCode *ic, PAIR_ID pairId)
1562 if (bitVectBitValue(ic->rUsed, D_IDX))
1564 if (bitVectBitValue(ic->rUsed, E_IDX))
1573 static int _opUsesPair(operand *op, iCode *ic, PAIR_ID pairId)
1577 symbol *sym = OP_SYMBOL(op);
1579 if (sym->isspilt || sym->nRegs == 0)
1582 aopOp(op, ic, FALSE, FALSE);
1585 if (aop->type == AOP_REG) {
1587 for (i=0; i < aop->size; i++) {
1588 if (pairId == PAIR_DE) {
1589 emit2("; name %s", aop->aopu.aop_reg[i]->name);
1590 if (!strcmp(aop->aopu.aop_reg[i]->name, "e"))
1592 if (!strcmp(aop->aopu.aop_reg[i]->name, "d"))
1601 freeAsmop(IC_LEFT(ic),NULL,ic);
1605 /** Emit the code for a call statement
1607 static void emitCall(iCode *ic, bool ispcall)
1611 /* if caller saves & we have not saved then */
1612 if (!ic->regsSaved) {
1616 /* if send set is not empty then assign */
1620 int n = elementsInSet(sendSet);
1621 if (IS_Z80 && n == 2 && _isPairUsed(ic, PAIR_DE)) {
1622 /* Only push de if it is used and if it's not used
1623 in the return value */
1624 /* Panic if partly used */
1625 if (_opUsesPair(IC_RESULT(ic), ic, PAIR_DE) == 1) {
1626 emit2("; Warning: de crossover");
1628 else if (!_opUsesPair(IC_RESULT(ic), ic, PAIR_DE)) {
1635 if (IS_Z80 && n == 2 ) {
1636 /* Want to load HL first, then DE as HL may = DE */
1637 sic = setFirstItem(sendSet);
1638 sic = setNextItem(sendSet);
1639 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1640 fetchPair(PAIR_HL, AOP(IC_LEFT(sic)));
1642 freeAsmop (IC_LEFT(sic),NULL,sic);
1643 sic = setFirstItem(sendSet);
1644 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1645 fetchPair(PAIR_DE, AOP(IC_LEFT(sic)));
1647 freeAsmop (IC_LEFT(sic),NULL,sic);
1650 for (sic = setFirstItem(sendSet) ; sic ;
1651 sic = setNextItem(sendSet)) {
1653 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1654 size = AOP_SIZE(IC_LEFT(sic));
1656 /* Always send in pairs */
1659 if (IS_Z80 && n == 1)
1660 fetchPair(PAIR_HL, AOP(IC_LEFT(sic)));
1662 fetchPair(PAIR_DE, AOP(IC_LEFT(sic)));
1665 fetchPair(PAIR_HL, AOP(IC_LEFT(sic)));
1668 /* Send set too big */
1672 freeAsmop (IC_LEFT(sic),NULL,sic);
1681 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1683 if (isLitWord(AOP(IC_LEFT(ic)))) {
1684 emitcode("", "; Special case where the pCall is to a constant");
1685 emitcode("call", aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE));
1688 symbol *rlbl = newiTempLabel(NULL);
1690 emit2("ld hl,#!tlabel", (rlbl->key+100));
1691 emitcode("push", "hl");
1692 _G.stack.pushed += 2;
1694 fetchHL(AOP(IC_LEFT(ic)));
1696 emit2("!tlabeldef", (rlbl->key+100));
1697 _G.stack.pushed -= 2;
1699 freeAsmop(IC_LEFT(ic),NULL,ic);
1703 char *name = OP_SYMBOL(IC_LEFT(ic))->rname[0] ?
1704 OP_SYMBOL(IC_LEFT(ic))->rname :
1705 OP_SYMBOL(IC_LEFT(ic))->name;
1706 emitcode("call", "%s", name);
1710 /* if we need assign a result value */
1711 if ((IS_ITEMP(IC_RESULT(ic)) &&
1712 (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
1713 OP_SYMBOL(IC_RESULT(ic))->spildir )) ||
1714 IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
1717 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
1720 assignResultValue(IC_RESULT(ic));
1722 freeAsmop(IC_RESULT(ic),NULL, ic);
1725 /* adjust the stack for parameters if required */
1726 if (IC_LEFT(ic)->parmBytes) {
1727 int i = IC_LEFT(ic)->parmBytes;
1728 _G.stack.pushed -= i;
1730 emit2("!ldaspsp", i);
1735 emitcode("ld", "hl,#%d", i);
1736 emitcode("add", "hl,sp");
1737 emitcode("ld", "sp,hl");
1741 emitcode("pop", "hl");
1745 emitcode("inc", "sp");
1754 /*-----------------------------------------------------------------*/
1755 /* genCall - generates a call statement */
1756 /*-----------------------------------------------------------------*/
1757 static void genCall (iCode *ic)
1759 link *detype = getSpec(operandType(IC_LEFT(ic)));
1760 if (IS_BANKED(detype)) emit2("; call to a banked function");
1761 emitCall(ic, FALSE);
1764 /*-----------------------------------------------------------------*/
1765 /* genPcall - generates a call by pointer statement */
1766 /*-----------------------------------------------------------------*/
1767 static void genPcall (iCode *ic)
1772 /*-----------------------------------------------------------------*/
1773 /* resultRemat - result is rematerializable */
1774 /*-----------------------------------------------------------------*/
1775 static int resultRemat (iCode *ic)
1777 if (SKIP_IC(ic) || ic->op == IFX)
1780 if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
1781 symbol *sym = OP_SYMBOL(IC_RESULT(ic));
1782 if (sym->remat && !POINTER_SET(ic))
1789 /*-----------------------------------------------------------------*/
1790 /* genFunction - generated code for function entry */
1791 /*-----------------------------------------------------------------*/
1792 static void genFunction (iCode *ic)
1794 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1798 /* create the function header */
1799 emit2("!functionheader", sym->name);
1800 /* PENDING: portability. */
1801 emit2("__%s_start:", sym->rname);
1802 emit2("!functionlabeldef", sym->rname);
1804 fetype = getSpec(operandType(IC_LEFT(ic)));
1806 /* if critical function then turn interrupts off */
1807 if (SPEC_CRTCL(fetype))
1809 if (SPEC_BANKED(fetype)) emit2("; Iam banked");
1811 /* if this is an interrupt service routine then
1812 save acc, b, dpl, dph */
1813 if (IS_ISR(sym->etype)) {
1816 /* PENDING: callee-save etc */
1818 /* adjust the stack for the function */
1819 _G.stack.last = sym->stack;
1822 emit2("!enterx", sym->stack);
1825 _G.stack.offset = sym->stack;
1828 /*-----------------------------------------------------------------*/
1829 /* genEndFunction - generates epilogue for functions */
1830 /*-----------------------------------------------------------------*/
1831 static void genEndFunction (iCode *ic)
1833 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1835 if (IS_ISR(sym->etype)) {
1839 if (SPEC_CRTCL(sym->etype))
1842 /* PENDING: calleeSave */
1844 /* if debug then send end of function */
1845 if (options.debug && currFunc) {
1847 emitcode("","C$%s$%d$%d$%d ==.",
1848 ic->filename,currFunc->lastLine,
1849 ic->level,ic->block);
1850 if (IS_STATIC(currFunc->etype))
1851 emitcode("","XF%s$%s$0$0 ==.",moduleName,currFunc->name);
1853 emitcode("","XG$%s$0$0 ==.",currFunc->name);
1856 if (_G.stack.offset)
1857 emit2("!leavex", _G.stack.offset);
1860 /* PENDING: portability. */
1861 emit2("__%s_end:", sym->rname);
1863 _G.stack.pushed = 0;
1864 _G.stack.offset = 0;
1867 /*-----------------------------------------------------------------*/
1868 /* genRet - generate code for return statement */
1869 /*-----------------------------------------------------------------*/
1870 static void genRet (iCode *ic)
1873 /* Errk. This is a hack until I can figure out how
1874 to cause dehl to spill on a call */
1875 int size,offset = 0;
1877 /* if we have no return value then
1878 just generate the "ret" */
1882 /* we have something to return then
1883 move the return value into place */
1884 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1885 size = AOP_SIZE(IC_LEFT(ic));
1887 if ((size == 2) && ((l = aopGetWord(AOP(IC_LEFT(ic)), 0)))) {
1889 emitcode("ld", "de,%s", l);
1892 emitcode("ld", "hl,%s", l);
1896 if (IS_GB && size == 4 && requiresHL(AOP(IC_LEFT(ic)))) {
1897 fetchPair(PAIR_DE, AOP(IC_LEFT(ic)));
1898 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
1902 l = aopGet(AOP(IC_LEFT(ic)),offset,
1904 if (strcmp(_fReturn[offset],l))
1905 emitcode("ld","%s,%s", _fReturn[offset++],l);
1909 freeAsmop (IC_LEFT(ic),NULL,ic);
1912 /* generate a jump to the return label
1913 if the next is not the return statement */
1914 if (!(ic->next && ic->next->op == LABEL &&
1915 IC_LABEL(ic->next) == returnLabel))
1917 emit2("jp !tlabel", returnLabel->key+100);
1920 /*-----------------------------------------------------------------*/
1921 /* genLabel - generates a label */
1922 /*-----------------------------------------------------------------*/
1923 static void genLabel (iCode *ic)
1925 /* special case never generate */
1926 if (IC_LABEL(ic) == entryLabel)
1929 emitLabel(IC_LABEL(ic)->key+100);
1932 /*-----------------------------------------------------------------*/
1933 /* genGoto - generates a ljmp */
1934 /*-----------------------------------------------------------------*/
1935 static void genGoto (iCode *ic)
1937 emit2("jp !tlabel", IC_LABEL(ic)->key+100);
1940 /*-----------------------------------------------------------------*/
1941 /* genPlusIncr :- does addition with increment if possible */
1942 /*-----------------------------------------------------------------*/
1943 static bool genPlusIncr (iCode *ic)
1945 unsigned int icount ;
1946 unsigned int size = getDataSize(IC_RESULT(ic));
1947 PAIR_ID resultId = getPairId(AOP(IC_RESULT(ic)));
1949 /* will try to generate an increment */
1950 /* if the right side is not a literal
1952 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1955 emitcode("", "; genPlusIncr");
1957 icount = floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
1959 /* If result is a pair */
1960 if (resultId != PAIR_INVALID) {
1961 if (isLitWord(AOP(IC_LEFT(ic)))) {
1962 fetchLitPair(getPairId(AOP(IC_RESULT(ic))), AOP(IC_LEFT(ic)), icount);
1965 if (isPair(AOP(IC_LEFT(ic))) && resultId == PAIR_HL && icount > 2) {
1966 fetchPair(resultId, AOP(IC_RIGHT(ic)));
1967 emitcode("add", "hl,%s", getPairName(AOP(IC_LEFT(ic))));
1973 if (!sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
1976 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
1977 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
1980 emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
1985 /* if the literal value of the right hand side
1986 is greater than 4 then it is not worth it */
1990 /* if increment 16 bits in register */
1991 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1996 symbol *tlbl = NULL;
1997 tlbl = newiTempLabel(NULL);
1999 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)), offset++, FALSE));
2001 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2004 emitLabel(tlbl->key+100);
2008 /* if the sizes are greater than 1 then we cannot */
2009 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2010 AOP_SIZE(IC_LEFT(ic)) > 1 )
2013 /* we can if the aops of the left & result match or
2014 if they are in registers and the registers are the
2016 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
2018 emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0, FALSE));
2025 /*-----------------------------------------------------------------*/
2026 /* outBitAcc - output a bit in acc */
2027 /*-----------------------------------------------------------------*/
2028 void outBitAcc(operand *result)
2030 symbol *tlbl = newiTempLabel(NULL);
2031 /* if the result is a bit */
2032 if (AOP_TYPE(result) == AOP_CRY){
2036 emit2("!shortjp z,!tlabel", tlbl->key+100);
2038 emitLabel(tlbl->key+100);
2043 /*-----------------------------------------------------------------*/
2044 /* genPlus - generates code for addition */
2045 /*-----------------------------------------------------------------*/
2046 static void genPlus (iCode *ic)
2048 int size, offset = 0;
2050 /* special cases :- */
2052 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
2053 aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
2054 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
2056 /* Swap the left and right operands if:
2058 if literal, literal on the right or
2059 if left requires ACC or right is already
2062 if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
2063 (AOP_NEEDSACC(IC_LEFT(ic))) ||
2064 AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
2065 operand *t = IC_RIGHT(ic);
2066 IC_RIGHT(ic) = IC_LEFT(ic);
2070 /* if both left & right are in bit
2072 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2073 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2078 /* if left in bit space & right literal */
2079 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2080 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
2081 /* Can happen I guess */
2085 /* if I can do an increment instead
2086 of add then GOOD for ME */
2087 if (genPlusIncr (ic) == TRUE)
2090 size = getDataSize(IC_RESULT(ic));
2092 /* Special case when left and right are constant */
2093 if (isPair(AOP(IC_RESULT(ic)))) {
2096 left = aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE);
2097 right = aopGetLitWordLong(AOP(IC_RIGHT(ic)), 0, FALSE);
2098 if (left && right) {
2102 sprintf(buffer, "#(%s + %s)", left, right);
2103 emitcode("ld", "%s,%s", getPairName(AOP(IC_RESULT(ic))), buffer);
2108 if (isPair(AOP(IC_RIGHT(ic))) && getPairId(AOP(IC_RESULT(ic))) == PAIR_HL) {
2109 /* Fetch into HL then do the add */
2111 fetchPair(PAIR_HL, AOP(IC_LEFT(ic)));
2112 emitcode("add", "hl,%s", getPairName(AOP(IC_RIGHT(ic))));
2117 if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
2118 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2120 emitcode("add","a,%s",
2121 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2123 emitcode("adc","a,%s",
2124 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2126 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2128 emitcode("add","a,%s",
2129 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2131 emitcode("adc","a,%s",
2132 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2134 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2137 /* Some kind of pointer arith. */
2138 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2139 AOP_SIZE(IC_LEFT(ic)) == 3 &&
2140 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2143 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2144 AOP_SIZE(IC_RIGHT(ic)) == 3 &&
2145 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
2150 freeAsmop(IC_LEFT(ic),NULL,ic);
2151 freeAsmop(IC_RIGHT(ic),NULL,ic);
2152 freeAsmop(IC_RESULT(ic),NULL,ic);
2156 /*-----------------------------------------------------------------*/
2157 /* genMinusDec :- does subtraction with deccrement if possible */
2158 /*-----------------------------------------------------------------*/
2159 static bool genMinusDec (iCode *ic)
2161 unsigned int icount ;
2162 unsigned int size = getDataSize(IC_RESULT(ic));
2164 /* will try to generate an increment */
2165 /* if the right side is not a literal we cannot */
2166 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
2169 /* if the literal value of the right hand side
2170 is greater than 4 then it is not worth it */
2171 if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
2174 size = getDataSize(IC_RESULT(ic));
2177 /* if increment 16 bits in register */
2178 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2181 symbol *tlbl = newiTempLabel(NULL);
2182 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
2183 emitcode("jp", "np," LABEL_STR ,tlbl->key+100);
2185 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
2189 emitLabel(tlbl->key+100);
2194 /* if decrement 16 bits in register */
2195 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2196 (size > 1) && isPair(AOP(IC_RESULT(ic)))) {
2198 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2202 /* If result is a pair */
2203 if (isPair(AOP(IC_RESULT(ic)))) {
2204 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
2205 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
2207 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2211 /* if the sizes are greater than 1 then we cannot */
2212 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2213 AOP_SIZE(IC_LEFT(ic)) > 1 )
2216 /* we can if the aops of the left & result match or if they are in
2217 registers and the registers are the same */
2218 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
2220 emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE));
2227 /*-----------------------------------------------------------------*/
2228 /* genMinus - generates code for subtraction */
2229 /*-----------------------------------------------------------------*/
2230 static void genMinus (iCode *ic)
2232 int size, offset = 0;
2233 unsigned long lit = 0L;
2235 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
2236 aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
2237 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
2239 /* special cases :- */
2240 /* if both left & right are in bit space */
2241 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2242 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2247 /* if I can do an decrement instead of subtract then GOOD for ME */
2248 if (genMinusDec (ic) == TRUE)
2251 size = getDataSize(IC_RESULT(ic));
2253 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
2256 lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
2261 /* if literal, add a,#-lit, else normal subb */
2263 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2264 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) {
2266 emitcode("sub","a,%s",
2267 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2269 emitcode("sbc","a,%s",
2270 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2273 /* first add without previous c */
2275 emit2("add a,!immedbyte", (unsigned int)(lit & 0x0FFL));
2277 emit2("adc a,!immedbyte", (unsigned int)((lit >> (offset*8)) & 0x0FFL));
2279 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2282 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2283 AOP_SIZE(IC_LEFT(ic)) == 3 &&
2284 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2288 freeAsmop(IC_LEFT(ic),NULL,ic);
2289 freeAsmop(IC_RIGHT(ic),NULL,ic);
2290 freeAsmop(IC_RESULT(ic),NULL,ic);
2293 /*-----------------------------------------------------------------*/
2294 /* genMult - generates code for multiplication */
2295 /*-----------------------------------------------------------------*/
2296 static void genMult (iCode *ic)
2298 /* Shouldn't occur - all done through function calls */
2302 /*-----------------------------------------------------------------*/
2303 /* genDiv - generates code for division */
2304 /*-----------------------------------------------------------------*/
2305 static void genDiv (iCode *ic)
2307 /* Shouldn't occur - all done through function calls */
2311 /*-----------------------------------------------------------------*/
2312 /* genMod - generates code for division */
2313 /*-----------------------------------------------------------------*/
2314 static void genMod (iCode *ic)
2316 /* Shouldn't occur - all done through function calls */
2320 /*-----------------------------------------------------------------*/
2321 /* genIfxJump :- will create a jump depending on the ifx */
2322 /*-----------------------------------------------------------------*/
2323 static void genIfxJump (iCode *ic, char *jval)
2328 /* if true label then we jump if condition
2330 if ( IC_TRUE(ic) ) {
2332 if (!strcmp(jval, "a")) {
2335 else if (!strcmp(jval, "c")) {
2339 /* The buffer contains the bit on A that we should test */
2344 /* false label is present */
2345 jlbl = IC_FALSE(ic) ;
2346 if (!strcmp(jval, "a")) {
2349 else if (!strcmp(jval, "c")) {
2353 /* The buffer contains the bit on A that we should test */
2357 /* Z80 can do a conditional long jump */
2358 if (!strcmp(jval, "a")) {
2359 emitcode("or", "a,a");
2361 else if (!strcmp(jval, "c")) {
2364 emitcode("bit", "%s,a", jval);
2366 emit2("jp %s,!tlabel", inst, jlbl->key+100);
2368 /* mark the icode as generated */
2372 /** Generic compare for > or <
2374 static void genCmp (operand *left,operand *right,
2375 operand *result, iCode *ifx, int sign)
2377 int size, offset = 0 ;
2378 unsigned long lit = 0L;
2380 /* if left & right are bit variables */
2381 if (AOP_TYPE(left) == AOP_CRY &&
2382 AOP_TYPE(right) == AOP_CRY ) {
2383 /* Cant happen on the Z80 */
2386 /* subtract right from left if at the
2387 end the carry flag is set then we know that
2388 left is greater than right */
2389 size = max(AOP_SIZE(left),AOP_SIZE(right));
2391 /* if unsigned char cmp with lit, just compare */
2393 (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
2394 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2396 emit2("xor a,!immedbyte", 0x80);
2397 emit2("cp %s^!constbyte", aopGet(AOP(right), offset, FALSE), 0x80);
2400 emitcode("cp", "%s", aopGet(AOP(right), offset, FALSE));
2403 if(AOP_TYPE(right) == AOP_LIT) {
2404 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2405 /* optimize if(x < 0) or if(x >= 0) */
2408 /* No sign so it's always false */
2412 /* Just load in the top most bit */
2413 MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE));
2414 if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx) {
2415 genIfxJump (ifx,"7");
2419 emitcode("rlc","a");
2425 /* First setup h and l contaning the top most bytes XORed */
2426 bool fDidXor = FALSE;
2427 if (AOP_TYPE(left) == AOP_LIT){
2428 unsigned long lit = (unsigned long)
2429 floatFromVal(AOP(left)->aopu.aop_lit);
2430 emit2("ld %s,!immedbyte", _fTmp[0],
2431 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2434 emitcode("ld", "a,%s", aopGet(AOP(left), size-1, FALSE));
2435 emit2("xor a,!immedbyte", 0x80);
2436 emitcode("ld", "%s,a", _fTmp[0]);
2439 if (AOP_TYPE(right) == AOP_LIT) {
2440 unsigned long lit = (unsigned long)
2441 floatFromVal(AOP(right)->aopu.aop_lit);
2442 emit2("ld %s,!immedbyte", _fTmp[1],
2443 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2446 emitcode("ld", "a,%s", aopGet(AOP(right), size-1, FALSE));
2447 emit2("xor a,!immedbyte", 0x80);
2448 emitcode("ld", "%s,a", _fTmp[1]);
2458 /* Do a long subtract */
2459 if (!sign || size ) {
2460 MOVA(aopGet(AOP(left),offset,FALSE));
2462 if (sign && size == 0) {
2463 emitcode("ld", "a,%s", _fTmp[0]);
2464 emitcode("sbc", "a,%s", _fTmp[1]);
2467 /* Subtract through, propagating the carry */
2468 emitcode("sbc","a,%s ; 2",aopGet(AOP(right),offset++,FALSE));
2475 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2478 /* if the result is used in the next
2479 ifx conditional branch then generate
2480 code a little differently */
2482 genIfxJump (ifx,"c");
2485 /* leave the result in acc */
2489 /*-----------------------------------------------------------------*/
2490 /* genCmpGt :- greater than comparison */
2491 /*-----------------------------------------------------------------*/
2492 static void genCmpGt (iCode *ic, iCode *ifx)
2494 operand *left, *right, *result;
2495 link *letype , *retype;
2499 right= IC_RIGHT(ic);
2500 result = IC_RESULT(ic);
2502 letype = getSpec(operandType(left));
2503 retype =getSpec(operandType(right));
2504 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2505 /* assign the amsops */
2506 aopOp (left,ic,FALSE, FALSE);
2507 aopOp (right,ic,FALSE, FALSE);
2508 aopOp (result,ic,TRUE, FALSE);
2510 genCmp(right, left, result, ifx, sign);
2512 freeAsmop(left,NULL,ic);
2513 freeAsmop(right,NULL,ic);
2514 freeAsmop(result,NULL,ic);
2517 /*-----------------------------------------------------------------*/
2518 /* genCmpLt - less than comparisons */
2519 /*-----------------------------------------------------------------*/
2520 static void genCmpLt (iCode *ic, iCode *ifx)
2522 operand *left, *right, *result;
2523 link *letype , *retype;
2527 right= IC_RIGHT(ic);
2528 result = IC_RESULT(ic);
2530 letype = getSpec(operandType(left));
2531 retype =getSpec(operandType(right));
2532 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2534 /* assign the amsops */
2535 aopOp (left,ic,FALSE, FALSE);
2536 aopOp (right,ic,FALSE, FALSE);
2537 aopOp (result,ic,TRUE, FALSE);
2539 genCmp(left, right, result, ifx, sign);
2541 freeAsmop(left,NULL,ic);
2542 freeAsmop(right,NULL,ic);
2543 freeAsmop(result,NULL,ic);
2546 /*-----------------------------------------------------------------*/
2547 /* gencjneshort - compare and jump if not equal */
2548 /*-----------------------------------------------------------------*/
2549 static void gencjneshort(operand *left, operand *right, symbol *lbl)
2551 int size = max(AOP_SIZE(left),AOP_SIZE(right));
2553 unsigned long lit = 0L;
2555 /* Swap the left and right if it makes the computation easier */
2556 if (AOP_TYPE(left) == AOP_LIT) {
2562 if(AOP_TYPE(right) == AOP_LIT)
2563 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2565 /* if the right side is a literal then anything goes */
2566 if (AOP_TYPE(right) == AOP_LIT &&
2567 AOP_TYPE(left) != AOP_DIR ) {
2569 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2574 emitcode("or", "a,%s", aopGet(AOP(left), offset, FALSE));
2578 emitcode("or", "a,a");
2580 emit2("jp nz,!tlabel", lbl->key+100);
2584 emitcode("ld", "a,%s ; 2", aopGet(AOP(left),offset,FALSE));
2585 if ((AOP_TYPE(right) == AOP_LIT) && lit == 0)
2586 emitcode("or", "a,a");
2588 emitcode("cp", "a,%s", aopGet(AOP(right),offset,FALSE));
2589 emit2("jp nz,!tlabel", lbl->key+100);
2594 /* if the right side is in a register or in direct space or
2595 if the left is a pointer register & right is not */
2596 else if (AOP_TYPE(right) == AOP_REG ||
2597 AOP_TYPE(right) == AOP_DIR ||
2598 (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT)) {
2600 MOVA(aopGet(AOP(left),offset,FALSE));
2601 if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
2602 ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
2604 emit2("jp nz,!tlabel", lbl->key+100);
2606 emitcode("cp", "%s ; 4", aopGet(AOP(right),offset,FALSE));
2607 emit2("jp nz,!tlabel", lbl->key+100);
2612 /* right is a pointer reg need both a & b */
2613 /* PENDING: is this required? */
2615 MOVA(aopGet(AOP(right),offset,FALSE));
2616 emitcode("cp", "%s ; 5", aopGet(AOP(left), offset, FALSE));
2617 emit2("!shortjp nz,!tlabel", lbl->key+100);
2623 /*-----------------------------------------------------------------*/
2624 /* gencjne - compare and jump if not equal */
2625 /*-----------------------------------------------------------------*/
2626 static void gencjne(operand *left, operand *right, symbol *lbl)
2628 symbol *tlbl = newiTempLabel(NULL);
2630 gencjneshort(left, right, lbl);
2634 emit2("!shortjp !tlabel", tlbl->key+100);
2635 emitLabel(lbl->key+100);
2636 emitcode("xor","a,a");
2637 emitLabel(tlbl->key+100);
2640 /*-----------------------------------------------------------------*/
2641 /* genCmpEq - generates code for equal to */
2642 /*-----------------------------------------------------------------*/
2643 static void genCmpEq (iCode *ic, iCode *ifx)
2645 operand *left, *right, *result;
2647 aopOp((left=IC_LEFT(ic)),ic,FALSE, FALSE);
2648 aopOp((right=IC_RIGHT(ic)),ic,FALSE, FALSE);
2649 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2651 /* Swap operands if it makes the operation easier. ie if:
2652 1. Left is a literal.
2654 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
2655 operand *t = IC_RIGHT(ic);
2656 IC_RIGHT(ic) = IC_LEFT(ic);
2660 if (ifx && !AOP_SIZE(result)){
2662 /* if they are both bit variables */
2663 if (AOP_TYPE(left) == AOP_CRY &&
2664 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2667 tlbl = newiTempLabel(NULL);
2668 gencjneshort(left, right, tlbl);
2669 if ( IC_TRUE(ifx) ) {
2670 emit2("jp !tlabel", IC_TRUE(ifx)->key+100);
2671 emitLabel(tlbl->key+100);
2673 /* PENDING: do this better */
2674 symbol *lbl = newiTempLabel(NULL);
2675 emit2("!shortjp !tlabel", lbl->key+100);
2676 emitLabel(tlbl->key+100);
2677 emit2("jp !tlabel", IC_FALSE(ifx)->key+100);
2678 emitLabel(lbl->key+100);
2681 /* mark the icode as generated */
2686 /* if they are both bit variables */
2687 if (AOP_TYPE(left) == AOP_CRY &&
2688 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2691 gencjne(left,right,newiTempLabel(NULL));
2692 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2696 genIfxJump(ifx,"a");
2699 /* if the result is used in an arithmetic operation
2700 then put the result in place */
2701 if (AOP_TYPE(result) != AOP_CRY) {
2704 /* leave the result in acc */
2708 freeAsmop(left,NULL,ic);
2709 freeAsmop(right,NULL,ic);
2710 freeAsmop(result,NULL,ic);
2713 /*-----------------------------------------------------------------*/
2714 /* ifxForOp - returns the icode containing the ifx for operand */
2715 /*-----------------------------------------------------------------*/
2716 static iCode *ifxForOp ( operand *op, iCode *ic )
2718 /* if true symbol then needs to be assigned */
2719 if (IS_TRUE_SYMOP(op))
2722 /* if this has register type condition and
2723 the next instruction is ifx with the same operand
2724 and live to of the operand is upto the ifx only then */
2726 ic->next->op == IFX &&
2727 IC_COND(ic->next)->key == op->key &&
2728 OP_SYMBOL(op)->liveTo <= ic->next->seq )
2734 /*-----------------------------------------------------------------*/
2735 /* genAndOp - for && operation */
2736 /*-----------------------------------------------------------------*/
2737 static void genAndOp (iCode *ic)
2739 operand *left,*right, *result;
2742 /* note here that && operations that are in an if statement are
2743 taken away by backPatchLabels only those used in arthmetic
2744 operations remain */
2745 aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2746 aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2747 aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2749 /* if both are bit variables */
2750 if (AOP_TYPE(left) == AOP_CRY &&
2751 AOP_TYPE(right) == AOP_CRY ) {
2754 tlbl = newiTempLabel(NULL);
2756 emit2("!shortjp z,!tlabel", tlbl->key+100);
2758 emitLabel(tlbl->key+100);
2762 freeAsmop(left,NULL,ic);
2763 freeAsmop(right,NULL,ic);
2764 freeAsmop(result,NULL,ic);
2767 /*-----------------------------------------------------------------*/
2768 /* genOrOp - for || operation */
2769 /*-----------------------------------------------------------------*/
2770 static void genOrOp (iCode *ic)
2772 operand *left,*right, *result;
2775 /* note here that || operations that are in an
2776 if statement are taken away by backPatchLabels
2777 only those used in arthmetic operations remain */
2778 aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2779 aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2780 aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2782 /* if both are bit variables */
2783 if (AOP_TYPE(left) == AOP_CRY &&
2784 AOP_TYPE(right) == AOP_CRY ) {
2787 tlbl = newiTempLabel(NULL);
2789 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2791 emitLabel(tlbl->key+100);
2795 freeAsmop(left,NULL,ic);
2796 freeAsmop(right,NULL,ic);
2797 freeAsmop(result,NULL,ic);
2800 /*-----------------------------------------------------------------*/
2801 /* isLiteralBit - test if lit == 2^n */
2802 /*-----------------------------------------------------------------*/
2803 int isLiteralBit(unsigned long lit)
2805 unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
2806 0x100L,0x200L,0x400L,0x800L,
2807 0x1000L,0x2000L,0x4000L,0x8000L,
2808 0x10000L,0x20000L,0x40000L,0x80000L,
2809 0x100000L,0x200000L,0x400000L,0x800000L,
2810 0x1000000L,0x2000000L,0x4000000L,0x8000000L,
2811 0x10000000L,0x20000000L,0x40000000L,0x80000000L};
2814 for(idx = 0; idx < 32; idx++)
2820 /*-----------------------------------------------------------------*/
2821 /* jmpTrueOrFalse - */
2822 /*-----------------------------------------------------------------*/
2823 static void jmpTrueOrFalse (iCode *ic, symbol *tlbl)
2825 // ugly but optimized by peephole
2827 symbol *nlbl = newiTempLabel(NULL);
2828 emit2("jp !tlabel", nlbl->key+100);
2829 emitLabel(tlbl->key+100);
2830 emit2("jp !tlabel", IC_TRUE(ic)->key+100);
2831 emitLabel(nlbl->key+100);
2834 emit2("jp !tlabel", IC_FALSE(ic)->key+100);
2835 emitLabel(tlbl->key+100);
2840 /*-----------------------------------------------------------------*/
2841 /* genAnd - code for and */
2842 /*-----------------------------------------------------------------*/
2843 static void genAnd (iCode *ic, iCode *ifx)
2845 operand *left, *right, *result;
2847 unsigned long lit = 0L;
2850 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
2851 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
2852 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2855 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2857 AOP_TYPE(left), AOP_TYPE(right));
2858 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2860 AOP_SIZE(left), AOP_SIZE(right));
2863 /* if left is a literal & right is not then exchange them */
2864 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2865 AOP_NEEDSACC(left)) {
2866 operand *tmp = right ;
2871 /* if result = right then exchange them */
2872 if(sameRegs(AOP(result),AOP(right))){
2873 operand *tmp = right ;
2878 /* if right is bit then exchange them */
2879 if (AOP_TYPE(right) == AOP_CRY &&
2880 AOP_TYPE(left) != AOP_CRY){
2881 operand *tmp = right ;
2885 if(AOP_TYPE(right) == AOP_LIT)
2886 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2888 size = AOP_SIZE(result);
2890 if (AOP_TYPE(left) == AOP_CRY){
2895 // if(val & 0xZZ) - size = 0, ifx != FALSE -
2896 // bit = val & 0xZZ - size = 1, ifx = FALSE -
2897 if((AOP_TYPE(right) == AOP_LIT) &&
2898 (AOP_TYPE(result) == AOP_CRY) &&
2899 (AOP_TYPE(left) != AOP_CRY)) {
2900 int posbit = isLiteralBit(lit);
2904 MOVA(aopGet(AOP(left),posbit>>3,FALSE));
2908 emitcode("mov","c,acc.%d",posbit&0x07);
2913 sprintf(buffer, "%d", posbit&0x07);
2914 genIfxJump(ifx, buffer);
2922 symbol *tlbl = newiTempLabel(NULL);
2923 int sizel = AOP_SIZE(left);
2926 emitcode("setb","c");
2929 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
2930 MOVA( aopGet(AOP(left),offset,FALSE));
2932 if((posbit = isLiteralBit(bytelit)) != 0) {
2934 emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
2937 if(bytelit != 0x0FFL)
2938 emitcode("and","a,%s",
2939 aopGet(AOP(right),offset,FALSE));
2943 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2948 // bit = left & literal
2950 emitcode("clr","c");
2951 emit2("!tlabeldef", tlbl->key+100);
2953 // if(left & literal)
2956 jmpTrueOrFalse(ifx, tlbl);
2964 /* if left is same as result */
2965 if(sameRegs(AOP(result),AOP(left))){
2966 for(;size--; offset++) {
2967 if(AOP_TYPE(right) == AOP_LIT){
2968 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
2972 aopPut(AOP(result),zero,offset);
2974 MOVA(aopGet(AOP(left),offset,FALSE));
2975 emitcode("and","a,%s",
2976 aopGet(AOP(right),offset,FALSE));
2977 aopPut(AOP(left), "a", offset);
2982 if (AOP_TYPE(left) == AOP_ACC) {
2986 MOVA(aopGet(AOP(left),offset,FALSE));
2987 emitcode("and","a,%s",
2988 aopGet(AOP(right),offset,FALSE));
2989 aopPut(AOP(left), "a", offset);
2994 // left & result in different registers
2995 if(AOP_TYPE(result) == AOP_CRY){
2998 for(;(size--);offset++) {
3000 // result = left & right
3001 if(AOP_TYPE(right) == AOP_LIT){
3002 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
3004 aopGet(AOP(left),offset,FALSE),
3007 } else if(bytelit == 0){
3008 aopPut(AOP(result),zero,offset);
3012 // faster than result <- left, anl result,right
3013 // and better if result is SFR
3014 if (AOP_TYPE(left) == AOP_ACC)
3015 emitcode("and","a,%s",aopGet(AOP(right),offset,FALSE));
3017 MOVA(aopGet(AOP(left),offset,FALSE));
3018 emitcode("and","a,%s",
3019 aopGet(AOP(right),offset,FALSE));
3021 aopPut(AOP(result),"a",offset);
3028 freeAsmop(left,NULL,ic);
3029 freeAsmop(right,NULL,ic);
3030 freeAsmop(result,NULL,ic);
3033 /*-----------------------------------------------------------------*/
3034 /* genOr - code for or */
3035 /*-----------------------------------------------------------------*/
3036 static void genOr (iCode *ic, iCode *ifx)
3038 operand *left, *right, *result;
3040 unsigned long lit = 0L;
3042 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3043 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3044 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3047 emitcode("","; Type res[%d] = l[%d]&r[%d]",
3049 AOP_TYPE(left), AOP_TYPE(right));
3050 emitcode("","; Size res[%d] = l[%d]&r[%d]",
3052 AOP_SIZE(left), AOP_SIZE(right));
3055 /* if left is a literal & right is not then exchange them */
3056 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3057 AOP_NEEDSACC(left)) {
3058 operand *tmp = right ;
3063 /* if result = right then exchange them */
3064 if(sameRegs(AOP(result),AOP(right))){
3065 operand *tmp = right ;
3070 /* if right is bit then exchange them */
3071 if (AOP_TYPE(right) == AOP_CRY &&
3072 AOP_TYPE(left) != AOP_CRY){
3073 operand *tmp = right ;
3077 if(AOP_TYPE(right) == AOP_LIT)
3078 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3080 size = AOP_SIZE(result);
3082 if (AOP_TYPE(left) == AOP_CRY){
3087 if((AOP_TYPE(right) == AOP_LIT) &&
3088 (AOP_TYPE(result) == AOP_CRY) &&
3089 (AOP_TYPE(left) != AOP_CRY)){
3094 /* if left is same as result */
3095 if(sameRegs(AOP(result),AOP(left))){
3096 for(;size--; offset++) {
3097 if(AOP_TYPE(right) == AOP_LIT){
3098 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3101 MOVA(aopGet(AOP(left),offset,FALSE));
3102 emitcode("or","a,%s",
3103 aopGet(AOP(right),offset,FALSE));
3104 aopPut(AOP(result),"a", offset);
3107 if (AOP_TYPE(left) == AOP_ACC)
3108 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
3110 MOVA(aopGet(AOP(left),offset,FALSE));
3111 emitcode("or","a,%s",
3112 aopGet(AOP(right),offset,FALSE));
3113 aopPut(AOP(result),"a", offset);
3118 // left & result in different registers
3119 if(AOP_TYPE(result) == AOP_CRY){
3121 } else for(;(size--);offset++){
3123 // result = left & right
3124 if(AOP_TYPE(right) == AOP_LIT){
3125 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3127 aopGet(AOP(left),offset,FALSE),
3132 // faster than result <- left, anl result,right
3133 // and better if result is SFR
3134 if (AOP_TYPE(left) == AOP_ACC)
3135 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
3137 MOVA(aopGet(AOP(left),offset,FALSE));
3138 emitcode("or","a,%s",
3139 aopGet(AOP(right),offset,FALSE));
3141 aopPut(AOP(result),"a",offset);
3142 /* PENDING: something weird is going on here. Add exception. */
3143 if (AOP_TYPE(result) == AOP_ACC)
3149 freeAsmop(left,NULL,ic);
3150 freeAsmop(right,NULL,ic);
3151 freeAsmop(result,NULL,ic);
3154 /*-----------------------------------------------------------------*/
3155 /* genXor - code for xclusive or */
3156 /*-----------------------------------------------------------------*/
3157 static void genXor (iCode *ic, iCode *ifx)
3159 operand *left, *right, *result;
3161 unsigned long lit = 0L;
3163 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3164 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3165 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3167 /* if left is a literal & right is not then exchange them */
3168 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3169 AOP_NEEDSACC(left)) {
3170 operand *tmp = right ;
3175 /* if result = right then exchange them */
3176 if(sameRegs(AOP(result),AOP(right))){
3177 operand *tmp = right ;
3182 /* if right is bit then exchange them */
3183 if (AOP_TYPE(right) == AOP_CRY &&
3184 AOP_TYPE(left) != AOP_CRY){
3185 operand *tmp = right ;
3189 if(AOP_TYPE(right) == AOP_LIT)
3190 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3192 size = AOP_SIZE(result);
3194 if (AOP_TYPE(left) == AOP_CRY){
3199 if((AOP_TYPE(right) == AOP_LIT) &&
3200 (AOP_TYPE(result) == AOP_CRY) &&
3201 (AOP_TYPE(left) != AOP_CRY)){
3206 /* if left is same as result */
3207 if(sameRegs(AOP(result),AOP(left))){
3208 for(;size--; offset++) {
3209 if(AOP_TYPE(right) == AOP_LIT){
3210 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3213 MOVA(aopGet(AOP(right),offset,FALSE));
3214 emitcode("xor","a,%s",
3215 aopGet(AOP(left),offset,FALSE));
3216 aopPut(AOP(result),"a",0);
3219 if (AOP_TYPE(left) == AOP_ACC)
3220 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3222 MOVA(aopGet(AOP(right),offset,FALSE));
3223 emitcode("xor","a,%s",
3224 aopGet(AOP(left),offset,FALSE));
3225 aopPut(AOP(result),"a",0);
3230 // left & result in different registers
3231 if(AOP_TYPE(result) == AOP_CRY){
3233 } else for(;(size--);offset++){
3235 // result = left & right
3236 if(AOP_TYPE(right) == AOP_LIT){
3237 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3239 aopGet(AOP(left),offset,FALSE),
3244 // faster than result <- left, anl result,right
3245 // and better if result is SFR
3246 if (AOP_TYPE(left) == AOP_ACC)
3247 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3249 MOVA(aopGet(AOP(right),offset,FALSE));
3250 emitcode("xor","a,%s",
3251 aopGet(AOP(left),offset,FALSE));
3252 aopPut(AOP(result),"a",0);
3254 aopPut(AOP(result),"a",offset);
3259 freeAsmop(left,NULL,ic);
3260 freeAsmop(right,NULL,ic);
3261 freeAsmop(result,NULL,ic);
3264 /*-----------------------------------------------------------------*/
3265 /* genInline - write the inline code out */
3266 /*-----------------------------------------------------------------*/
3267 static void genInline (iCode *ic)
3269 char buffer[MAX_INLINEASM];
3273 inLine += (!options.asmpeep);
3274 strcpy(buffer,IC_INLINE(ic));
3276 /* emit each line as a code */
3295 /* emitcode("",buffer); */
3296 inLine -= (!options.asmpeep);
3299 /*-----------------------------------------------------------------*/
3300 /* genRRC - rotate right with carry */
3301 /*-----------------------------------------------------------------*/
3302 static void genRRC (iCode *ic)
3307 /*-----------------------------------------------------------------*/
3308 /* genRLC - generate code for rotate left with carry */
3309 /*-----------------------------------------------------------------*/
3310 static void genRLC (iCode *ic)
3315 /*-----------------------------------------------------------------*/
3316 /* shiftR2Left2Result - shift right two bytes from left to result */
3317 /*-----------------------------------------------------------------*/
3318 static void shiftR2Left2Result (operand *left, int offl,
3319 operand *result, int offr,
3320 int shCount, int sign)
3322 movLeft2Result(left, offl, result, offr, 0);
3323 movLeft2Result(left, offl+1, result, offr+1, 0);
3329 /* if (AOP(result)->type == AOP_REG) {*/
3332 symbol *tlbl , *tlbl1;
3335 tlbl = newiTempLabel(NULL);
3336 tlbl1 = newiTempLabel(NULL);
3338 /* Left is already in result - so now do the shift */
3340 emit2("ld a,!immedbyte+1", shCount);
3341 emit2("!shortjp !tlabel", tlbl1->key+100);
3342 emitLabel(tlbl->key+100);
3345 emitcode("or", "a,a");
3348 l = aopGet(AOP(result), --offset, FALSE);
3349 emitcode("rr","%s", l);
3352 emitLabel(tlbl1->key+100);
3353 emitcode("dec", "a");
3354 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3359 /*-----------------------------------------------------------------*/
3360 /* shiftL2Left2Result - shift left two bytes from left to result */
3361 /*-----------------------------------------------------------------*/
3362 static void shiftL2Left2Result (operand *left, int offl,
3363 operand *result, int offr, int shCount)
3365 if(sameRegs(AOP(result), AOP(left)) &&
3366 ((offl + MSB16) == offr)){
3369 /* Copy left into result */
3370 movLeft2Result(left, offl, result, offr, 0);
3371 movLeft2Result(left, offl+1, result, offr+1, 0);
3373 /* PENDING: for now just see if it'll work. */
3374 /*if (AOP(result)->type == AOP_REG) { */
3378 symbol *tlbl , *tlbl1;
3381 tlbl = newiTempLabel(NULL);
3382 tlbl1 = newiTempLabel(NULL);
3384 /* Left is already in result - so now do the shift */
3386 emit2("ld a,!immedbyte+1", shCount);
3387 emit2("!shortjp !tlabel", tlbl1->key+100);
3388 emitLabel(tlbl->key+100);
3391 emitcode("or", "a,a");
3393 l = aopGet(AOP(result),offset++,FALSE);
3394 emitcode("rl","%s", l);
3397 emitLabel(tlbl1->key+100);
3398 emitcode("dec", "a");
3399 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3404 /*-----------------------------------------------------------------*/
3405 /* AccRol - rotate left accumulator by known count */
3406 /*-----------------------------------------------------------------*/
3407 static void AccRol (int shCount)
3409 shCount &= 0x0007; // shCount : 0..7
3446 /*-----------------------------------------------------------------*/
3447 /* AccLsh - left shift accumulator by known count */
3448 /*-----------------------------------------------------------------*/
3449 static void AccLsh (int shCount)
3453 emitcode("add","a,a");
3455 else if(shCount == 2) {
3456 emitcode("add","a,a");
3457 emitcode("add","a,a");
3459 /* rotate left accumulator */
3461 /* and kill the lower order bits */
3462 emit2("and a,!immedbyte", SLMask[shCount]);
3467 /*-----------------------------------------------------------------*/
3468 /* shiftL1Left2Result - shift left one byte from left to result */
3469 /*-----------------------------------------------------------------*/
3470 static void shiftL1Left2Result (operand *left, int offl,
3471 operand *result, int offr, int shCount)
3474 l = aopGet(AOP(left),offl,FALSE);
3476 /* shift left accumulator */
3478 aopPut(AOP(result),"a",offr);
3482 /*-----------------------------------------------------------------*/
3483 /* genlshTwo - left shift two bytes by known amount != 0 */
3484 /*-----------------------------------------------------------------*/
3485 static void genlshTwo (operand *result,operand *left, int shCount)
3487 int size = AOP_SIZE(result);
3491 /* if shCount >= 8 */
3496 movLeft2Result(left, LSB, result, MSB16, 0);
3497 aopPut(AOP(result),zero, 0);
3498 shiftL1Left2Result(left, MSB16, result, MSB16, shCount);
3501 movLeft2Result(left, LSB, result, MSB16, 0);
3502 aopPut(AOP(result),zero, 0);
3506 aopPut(AOP(result),zero,LSB);
3509 /* 1 <= shCount <= 7 */
3515 shiftL2Left2Result(left, LSB, result, LSB, shCount);
3520 /*-----------------------------------------------------------------*/
3521 /* genlshOne - left shift a one byte quantity by known count */
3522 /*-----------------------------------------------------------------*/
3523 static void genlshOne (operand *result, operand *left, int shCount)
3525 shiftL1Left2Result(left, LSB, result, LSB, shCount);
3528 /*-----------------------------------------------------------------*/
3529 /* genLeftShiftLiteral - left shifting by known count */
3530 /*-----------------------------------------------------------------*/
3531 static void genLeftShiftLiteral (operand *left,
3536 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3539 freeAsmop(right,NULL,ic);
3541 aopOp(left,ic,FALSE, FALSE);
3542 aopOp(result,ic,FALSE, FALSE);
3544 size = getSize(operandType(result));
3547 emitcode("; shift left ","result %d, left %d",size,
3551 /* I suppose that the left size >= result size */
3556 else if(shCount >= (size * 8))
3558 aopPut(AOP(result),zero,size);
3562 genlshOne (result,left,shCount);
3565 genlshTwo (result,left,shCount);
3574 freeAsmop(left,NULL,ic);
3575 freeAsmop(result,NULL,ic);
3578 /*-----------------------------------------------------------------*/
3579 /* genLeftShift - generates code for left shifting */
3580 /*-----------------------------------------------------------------*/
3581 static void genLeftShift (iCode *ic)
3585 symbol *tlbl , *tlbl1;
3586 operand *left,*right, *result;
3588 right = IC_RIGHT(ic);
3590 result = IC_RESULT(ic);
3592 aopOp(right,ic,FALSE, FALSE);
3594 /* if the shift count is known then do it
3595 as efficiently as possible */
3596 if (AOP_TYPE(right) == AOP_LIT) {
3597 genLeftShiftLiteral (left,right,result,ic);
3601 /* shift count is unknown then we have to form a loop get the loop
3602 count in B : Note: we take only the lower order byte since
3603 shifting more that 32 bits make no sense anyway, ( the largest
3604 size of an object can be only 32 bits ) */
3605 emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE));
3606 emitcode("inc","a");
3607 freeAsmop (right,NULL,ic);
3608 aopOp(left,ic,FALSE, FALSE);
3609 aopOp(result,ic,FALSE, FALSE);
3611 /* now move the left to the result if they are not the
3614 if (!sameRegs(AOP(left),AOP(result))) {
3616 size = AOP_SIZE(result);
3619 l = aopGet(AOP(left),offset,FALSE);
3620 aopPut(AOP(result),l,offset);
3625 size = AOP_SIZE(result);
3628 l = aopGet(AOP(left),offset,FALSE);
3629 aopPut(AOP(result),l,offset);
3635 tlbl = newiTempLabel(NULL);
3636 size = AOP_SIZE(result);
3638 tlbl1 = newiTempLabel(NULL);
3640 emit2("!shortjp !tlabel", tlbl1->key+100);
3641 emitLabel(tlbl->key+100);
3642 l = aopGet(AOP(result),offset,FALSE);
3643 emitcode("or", "a,a");
3645 l = aopGet(AOP(result),offset++,FALSE);
3646 emitcode("rl","%s", l);
3648 emitLabel(tlbl1->key+100);
3649 emitcode("dec", "a");
3650 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3652 freeAsmop(left,NULL,ic);
3653 freeAsmop(result,NULL,ic);
3656 /*-----------------------------------------------------------------*/
3657 /* genrshOne - left shift two bytes by known amount != 0 */
3658 /*-----------------------------------------------------------------*/
3659 static void genrshOne (operand *result,operand *left, int shCount)
3662 int size = AOP_SIZE(result);
3668 l = aopGet(AOP(left),0,FALSE);
3669 if (AOP(result)->type == AOP_REG) {
3670 aopPut(AOP(result), l, 0);
3671 l = aopGet(AOP(result), 0, FALSE);
3673 emitcode("srl", "%s", l);
3678 emitcode("srl", "a");
3680 aopPut(AOP(result),"a",0);
3684 /*-----------------------------------------------------------------*/
3685 /* AccRsh - right shift accumulator by known count */
3686 /*-----------------------------------------------------------------*/
3687 static void AccRsh (int shCount)
3690 /* rotate right accumulator */
3691 AccRol(8 - shCount);
3692 /* and kill the higher order bits */
3693 emit2("and a,!immedbyte", SRMask[shCount]);
3697 /*-----------------------------------------------------------------*/
3698 /* shiftR1Left2Result - shift right one byte from left to result */
3699 /*-----------------------------------------------------------------*/
3700 static void shiftR1Left2Result (operand *left, int offl,
3701 operand *result, int offr,
3702 int shCount, int sign)
3704 MOVA(aopGet(AOP(left),offl,FALSE));
3711 aopPut(AOP(result),"a",offr);
3714 /*-----------------------------------------------------------------*/
3715 /* genrshTwo - right shift two bytes by known amount != 0 */
3716 /*-----------------------------------------------------------------*/
3717 static void genrshTwo (operand *result,operand *left,
3718 int shCount, int sign)
3720 /* if shCount >= 8 */
3724 shiftR1Left2Result(left, MSB16, result, LSB,
3728 movLeft2Result(left, MSB16, result, LSB, sign);
3730 aopPut(AOP(result),zero,1);
3732 /* 1 <= shCount <= 7 */
3734 shiftR2Left2Result(left, LSB, result, LSB, shCount, sign);
3738 /*-----------------------------------------------------------------*/
3739 /* genRightShiftLiteral - left shifting by known count */
3740 /*-----------------------------------------------------------------*/
3741 static void genRightShiftLiteral (operand *left,
3746 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3749 freeAsmop(right,NULL,ic);
3751 aopOp(left,ic,FALSE, FALSE);
3752 aopOp(result,ic,FALSE, FALSE);
3754 size = getSize(operandType(result));
3756 emitcode("; shift right ","result %d, left %d",size,
3759 /* I suppose that the left size >= result size */
3764 else if(shCount >= (size * 8))
3766 aopPut(AOP(result),zero,size);
3770 genrshOne(result, left, shCount);
3773 /* PENDING: sign support */
3774 genrshTwo(result, left, shCount, FALSE);
3783 freeAsmop(left,NULL,ic);
3784 freeAsmop(result,NULL,ic);
3787 /*-----------------------------------------------------------------*/
3788 /* genRightShift - generate code for right shifting */
3789 /*-----------------------------------------------------------------*/
3790 static void genRightShift (iCode *ic)
3792 operand *right, *left, *result;
3794 int size, offset, first = 1;
3798 symbol *tlbl, *tlbl1 ;
3800 /* if signed then we do it the hard way preserve the
3801 sign bit moving it inwards */
3802 retype = getSpec(operandType(IC_RESULT(ic)));
3804 is_signed = !SPEC_USIGN(retype);
3806 /* signed & unsigned types are treated the same : i.e. the
3807 signed is NOT propagated inwards : quoting from the
3808 ANSI - standard : "for E1 >> E2, is equivalent to division
3809 by 2**E2 if unsigned or if it has a non-negative value,
3810 otherwise the result is implementation defined ", MY definition
3811 is that the sign does not get propagated */
3813 right = IC_RIGHT(ic);
3815 result = IC_RESULT(ic);
3817 aopOp(right,ic,FALSE, FALSE);
3819 /* if the shift count is known then do it
3820 as efficiently as possible */
3821 if (AOP_TYPE(right) == AOP_LIT) {
3822 genRightShiftLiteral(left,right,result,ic);
3826 aopOp(left,ic,FALSE, FALSE);
3827 aopOp(result,ic,FALSE, FALSE);
3829 /* now move the left to the result if they are not the
3831 if (!sameRegs(AOP(left),AOP(result)) &&
3832 AOP_SIZE(result) > 1) {
3834 size = AOP_SIZE(result);
3837 l = aopGet(AOP(left),offset,FALSE);
3838 aopPut(AOP(result),l,offset);
3843 emitcode("ld", "a,%s",aopGet(AOP(right),0,FALSE));
3844 emitcode("inc","a");
3845 freeAsmop (right, NULL, ic);
3847 tlbl = newiTempLabel(NULL);
3848 tlbl1= newiTempLabel(NULL);
3849 size = AOP_SIZE(result);
3852 emit2("!shortjp !tlabel", tlbl1->key+100);
3853 emitLabel(tlbl->key+100);
3855 l = aopGet(AOP(result),offset--,FALSE);
3858 emitcode("sra", "%s", l);
3860 emitcode("srl", "%s", l);
3864 emitcode("rr", "%s", l);
3866 emitLabel(tlbl1->key+100);
3867 emitcode("dec", "a");
3868 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3870 freeAsmop(left,NULL,ic);
3871 freeAsmop(result,NULL,ic);
3874 /*-----------------------------------------------------------------*/
3875 /* genGenPointerGet - get value from generic pointer space */
3876 /*-----------------------------------------------------------------*/
3877 static void genGenPointerGet (operand *left,
3878 operand *result, iCode *ic)
3881 link *retype = getSpec(operandType(result));
3887 aopOp(left,ic,FALSE, FALSE);
3888 aopOp(result,ic,FALSE, FALSE);
3890 if (isPair(AOP(left)) && AOP_SIZE(result)==1) {
3892 if (isPtrPair(AOP(left)))
3894 tsprintf(buffer, "!*pair", getPairName(AOP(left)));
3895 aopPut(AOP(result), buffer, 0);
3898 emit2("ld a,!*pair", getPairName(AOP(left)));
3899 aopPut(AOP(result),"a", 0);
3901 freeAsmop(left,NULL,ic);
3905 /* For now we always load into IY */
3906 /* if this is remateriazable */
3907 fetchPair(pair, AOP(left));
3909 /* so iy now contains the address */
3910 freeAsmop(left,NULL,ic);
3912 /* if bit then unpack */
3913 if (IS_BITVAR(retype)) {
3917 size = AOP_SIZE(result);
3921 /* PENDING: make this better */
3922 if (!IS_GB && AOP(result)->type == AOP_REG) {
3923 aopPut(AOP(result), "!*hl", offset++);
3926 emit2("ld a,!*pair", _pairs[pair].name);
3927 aopPut(AOP(result),"a",offset++);
3930 emit2("inc %s", _pairs[pair].name);
3936 freeAsmop(result,NULL,ic);
3939 /*-----------------------------------------------------------------*/
3940 /* genPointerGet - generate code for pointer get */
3941 /*-----------------------------------------------------------------*/
3942 static void genPointerGet (iCode *ic)
3944 operand *left, *result ;
3948 result = IC_RESULT(ic) ;
3950 /* depending on the type of pointer we need to
3951 move it to the correct pointer register */
3952 type = operandType(left);
3953 etype = getSpec(type);
3955 genGenPointerGet (left,result,ic);
3958 bool isRegOrLit(asmop *aop)
3960 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
3965 /*-----------------------------------------------------------------*/
3966 /* genGenPointerSet - stores the value into a pointer location */
3967 /*-----------------------------------------------------------------*/
3968 static void genGenPointerSet (operand *right,
3969 operand *result, iCode *ic)
3972 link *retype = getSpec(operandType(right));
3973 PAIR_ID pairId = PAIR_HL;
3975 aopOp(result,ic,FALSE, FALSE);
3976 aopOp(right,ic,FALSE, FALSE);
3981 /* Handle the exceptions first */
3982 if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
3984 char *l = aopGet(AOP(right), 0, FALSE);
3985 const char *pair = getPairName(AOP(result));
3986 if (canAssignToPtr(l) && isPtr(pair)) {
3987 emit2("ld !*pair,%s", pair, l);
3991 emit2("ld !*pair,a", pair);
3996 /* if the operand is already in dptr
3997 then we do nothing else we move the value to dptr */
3998 if (AOP_TYPE(result) != AOP_STR) {
3999 fetchPair(pairId, AOP(result));
4001 /* so hl know contains the address */
4002 freeAsmop(result,NULL,ic);
4004 /* if bit then unpack */
4005 if (IS_BITVAR(retype)) {
4009 size = AOP_SIZE(right);
4013 char *l = aopGet(AOP(right),offset,FALSE);
4014 if (isRegOrLit(AOP(right)) && !IS_GB) {
4015 emit2("ld !*pair,%s", _pairs[pairId].name, l);
4019 emit2("ld !*pair,a", _pairs[pairId].name);
4022 emitcode("inc", _pairs[pairId].name);
4028 freeAsmop(right,NULL,ic);
4031 /*-----------------------------------------------------------------*/
4032 /* genPointerSet - stores the value into a pointer location */
4033 /*-----------------------------------------------------------------*/
4034 static void genPointerSet (iCode *ic)
4036 operand *right, *result ;
4039 right = IC_RIGHT(ic);
4040 result = IC_RESULT(ic) ;
4042 /* depending on the type of pointer we need to
4043 move it to the correct pointer register */
4044 type = operandType(result);
4045 etype = getSpec(type);
4047 genGenPointerSet (right,result,ic);
4050 /*-----------------------------------------------------------------*/
4051 /* genIfx - generate code for Ifx statement */
4052 /*-----------------------------------------------------------------*/
4053 static void genIfx (iCode *ic, iCode *popIc)
4055 operand *cond = IC_COND(ic);
4058 aopOp(cond,ic,FALSE, TRUE);
4060 /* get the value into acc */
4061 if (AOP_TYPE(cond) != AOP_CRY)
4065 /* the result is now in the accumulator */
4066 freeAsmop(cond,NULL,ic);
4068 /* if there was something to be popped then do it */
4072 /* if the condition is a bit variable */
4073 if (isbit && IS_ITEMP(cond) &&
4075 genIfxJump(ic,SPIL_LOC(cond)->rname);
4077 if (isbit && !IS_ITEMP(cond))
4078 genIfxJump(ic,OP_SYMBOL(cond)->rname);
4085 /*-----------------------------------------------------------------*/
4086 /* genAddrOf - generates code for address of */
4087 /*-----------------------------------------------------------------*/
4088 static void genAddrOf (iCode *ic)
4090 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
4092 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
4094 /* if the operand is on the stack then we
4095 need to get the stack offset of this
4100 emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
4101 emitcode("ld", "d,h");
4102 emitcode("ld", "e,l");
4105 emitcode("ld", "de,#%s", sym->rname);
4107 aopPut(AOP(IC_RESULT(ic)), "e", 0);
4108 aopPut(AOP(IC_RESULT(ic)), "d", 1);
4113 /* if it has an offset then we need to compute it */
4114 emitcode("ld", "hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
4115 emitcode("add", "hl,sp");
4118 emitcode("ld", "hl,#%s", sym->rname);
4120 aopPut(AOP(IC_RESULT(ic)), "l", 0);
4121 aopPut(AOP(IC_RESULT(ic)), "h", 1);
4123 freeAsmop(IC_RESULT(ic),NULL,ic);
4126 /*-----------------------------------------------------------------*/
4127 /* genAssign - generate code for assignment */
4128 /*-----------------------------------------------------------------*/
4129 static void genAssign (iCode *ic)
4131 operand *result, *right;
4133 unsigned long lit = 0L;
4135 result = IC_RESULT(ic);
4136 right = IC_RIGHT(ic) ;
4139 /* Dont bother assigning if they are the same */
4140 if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) {
4141 emitcode("", "; (operands are equal %u)", operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)));
4146 aopOp(right,ic,FALSE, FALSE);
4147 aopOp(result,ic,TRUE, FALSE);
4149 /* if they are the same registers */
4150 if (sameRegs(AOP(right),AOP(result))) {
4151 emitcode("", "; (registers are the same)");
4155 /* if the result is a bit */
4156 if (AOP_TYPE(result) == AOP_CRY) {
4161 size = AOP_SIZE(result);
4164 if(AOP_TYPE(right) == AOP_LIT)
4165 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
4166 if (isPair(AOP(result))) {
4167 fetchPair(getPairId(AOP(result)), AOP(right));
4169 else if((size > 1) &&
4170 (AOP_TYPE(result) != AOP_REG) &&
4171 (AOP_TYPE(right) == AOP_LIT) &&
4172 !IS_FLOAT(operandType(right)) &&
4174 bool fXored = FALSE;
4176 /* Work from the top down.
4177 Done this way so that we can use the cached copy of 0
4178 in A for a fast clear */
4180 if((unsigned int)((lit >> (offset*8)) & 0x0FFL)== 0) {
4181 if (!fXored && size>1) {
4182 emitcode("xor", "a,a");
4186 aopPut(AOP(result),"a",offset);
4189 aopPut(AOP(result), zero, offset);
4194 aopGet(AOP(right),offset,FALSE),
4199 else if (size == 2 && requiresHL(AOP(right)) && requiresHL(AOP(result)) && IS_GB) {
4200 /* Special case. Load into a and d, then load out. */
4201 MOVA(aopGet(AOP(right), 0, FALSE));
4202 emitcode("ld", "e,%s", aopGet(AOP(right), 1, FALSE));
4203 aopPut(AOP(result), "a", 0);
4204 aopPut(AOP(result), "e", 1);
4207 /* PENDING: do this check better */
4208 if (requiresHL(AOP(right)) && requiresHL(AOP(result))) {
4209 MOVA(aopGet(AOP(right), offset, FALSE));
4210 aopPut(AOP(result), "a", offset);
4214 aopGet(AOP(right),offset,FALSE),
4221 freeAsmop(right,NULL,ic);
4222 freeAsmop(result,NULL,ic);
4225 /*-----------------------------------------------------------------*/
4226 /* genJumpTab - genrates code for jump table */
4227 /*-----------------------------------------------------------------*/
4228 static void genJumpTab (iCode *ic)
4233 aopOp(IC_JTCOND(ic),ic,FALSE, FALSE);
4234 /* get the condition into accumulator */
4235 l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE);
4237 emitcode("push", "de");
4238 emitcode("ld", "e,%s", l);
4239 emit2("ld d,!zero");
4240 jtab = newiTempLabel(NULL);
4242 emit2("ld hl,!immed!tlabel", jtab->key+100);
4243 emitcode("add", "hl,de");
4244 emitcode("add", "hl,de");
4245 emitcode("add", "hl,de");
4246 freeAsmop(IC_JTCOND(ic),NULL,ic);
4248 emitcode("pop", "de");
4250 emitLabel(jtab->key+100);
4251 /* now generate the jump labels */
4252 for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
4253 jtab = setNextItem(IC_JTLABELS(ic)))
4254 emit2("jp !tlabel", jtab->key+100);
4257 /*-----------------------------------------------------------------*/
4258 /* genCast - gen code for casting */
4259 /*-----------------------------------------------------------------*/
4260 static void genCast (iCode *ic)
4262 operand *result = IC_RESULT(ic);
4263 link *ctype = operandType(IC_LEFT(ic));
4264 operand *right = IC_RIGHT(ic);
4267 /* if they are equivalent then do nothing */
4268 if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
4271 aopOp(right,ic,FALSE, FALSE);
4272 aopOp(result,ic,FALSE, FALSE);
4274 /* if the result is a bit */
4275 if (AOP_TYPE(result) == AOP_CRY) {
4279 /* if they are the same size : or less */
4280 if (AOP_SIZE(result) <= AOP_SIZE(right)) {
4282 /* if they are in the same place */
4283 if (sameRegs(AOP(right),AOP(result)))
4286 /* if they in different places then copy */
4287 size = AOP_SIZE(result);
4291 aopGet(AOP(right),offset,FALSE),
4298 /* PENDING: should be OK. */
4300 /* if the result is of type pointer */
4301 if (IS_PTR(ctype)) {
4306 /* so we now know that the size of destination is greater
4307 than the size of the source */
4308 /* we move to result for the size of source */
4309 size = AOP_SIZE(right);
4313 aopGet(AOP(right),offset,FALSE),
4318 /* now depending on the sign of the destination */
4319 size = AOP_SIZE(result) - AOP_SIZE(right);
4320 /* Unsigned or not an integral type - right fill with zeros */
4321 if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) {
4323 aopPut(AOP(result),zero,offset++);
4325 /* we need to extend the sign :{ */
4326 char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
4329 emitcode("", "; genCast: sign extend untested.");
4330 emitcode("rla", "");
4331 emitcode("sbc", "a,a");
4333 aopPut(AOP(result),"a",offset++);
4337 freeAsmop(right, NULL, ic);
4338 freeAsmop(result, NULL, ic);
4341 /*-----------------------------------------------------------------*/
4342 /* genReceive - generate code for a receive iCode */
4343 /*-----------------------------------------------------------------*/
4344 static void genReceive (iCode *ic)
4346 if (isOperandInFarSpace(IC_RESULT(ic)) &&
4347 ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
4348 IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
4352 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
4354 assignResultValue(IC_RESULT(ic));
4357 freeAsmop(IC_RESULT(ic),NULL,ic);
4360 /*-----------------------------------------------------------------*/
4361 /* genZ80Code - generate code for Z80 based controllers */
4362 /*-----------------------------------------------------------------*/
4363 void genZ80Code (iCode *lic)
4370 _fReturn = _gbz80_return;
4371 _fTmp = _gbz80_return;
4374 _fReturn = _z80_return;
4375 _fTmp = _z80_return;
4377 tsprintf(zero, "!zero");
4379 lineHead = lineCurr = NULL;
4381 /* if debug information required */
4382 if (options.debug && currFunc) {
4383 cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
4385 if (IS_STATIC(currFunc->etype))
4386 emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name);
4388 emitcode("","G$%s$0$0 ==.",currFunc->name);
4391 /* stack pointer name */
4395 for (ic = lic ; ic ; ic = ic->next ) {
4397 if ( cln != ic->lineno ) {
4398 if ( options.debug ) {
4400 emitcode("","C$%s$%d$%d$%d ==.",
4401 ic->filename,ic->lineno,
4402 ic->level,ic->block);
4405 emitcode(";","%s %d",ic->filename,ic->lineno);
4408 /* if the result is marked as
4409 spilt and rematerializable or code for
4410 this has already been generated then
4412 if (resultRemat(ic) || ic->generated )
4415 /* depending on the operation */
4418 emitcode("", "; genNot");
4423 emitcode("", "; genCpl");
4428 emitcode("", "; genUminus");
4433 emitcode("", "; genIpush");
4438 /* IPOP happens only when trying to restore a
4439 spilt live range, if there is an ifx statement
4440 following this pop then the if statement might
4441 be using some of the registers being popped which
4442 would destory the contents of the register so
4443 we need to check for this condition and handle it */
4445 ic->next->op == IFX &&
4446 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) {
4447 emitcode("", "; genIfx");
4448 genIfx (ic->next,ic);
4451 emitcode("", "; genIpop");
4457 emitcode("", "; genCall");
4462 emitcode("", "; genPcall");
4467 emitcode("", "; genFunction");
4472 emitcode("", "; genEndFunction");
4473 genEndFunction (ic);
4477 emitcode("", "; genRet");
4482 emitcode("", "; genLabel");
4487 emitcode("", "; genGoto");
4492 emitcode("", "; genPlus");
4497 emitcode("", "; genMinus");
4502 emitcode("", "; genMult");
4507 emitcode("", "; genDiv");
4512 emitcode("", "; genMod");
4517 emitcode("", "; genCmpGt");
4518 genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));
4522 emitcode("", "; genCmpLt");
4523 genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
4530 /* note these two are xlated by algebraic equivalence
4531 during parsing SDCC.y */
4532 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
4533 "got '>=' or '<=' shouldn't have come here");
4537 emitcode("", "; genCmpEq");
4538 genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
4542 emitcode("", "; genAndOp");
4547 emitcode("", "; genOrOp");
4552 emitcode("", "; genXor");
4553 genXor (ic,ifxForOp(IC_RESULT(ic),ic));
4557 emitcode("", "; genOr");
4558 genOr (ic,ifxForOp(IC_RESULT(ic),ic));
4562 emitcode("", "; genAnd");
4563 genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
4567 emitcode("", "; genInline");
4572 emitcode("", "; genRRC");
4577 emitcode("", "; genRLC");
4582 emitcode("", "; genHBIT");
4586 emitcode("", "; genLeftShift");
4591 emitcode("", "; genRightShift");
4595 case GET_VALUE_AT_ADDRESS:
4596 emitcode("", "; genPointerGet");
4602 if (POINTER_SET(ic)) {
4603 emitcode("", "; genAssign (pointer)");
4607 emitcode("", "; genAssign");
4613 emitcode("", "; genIfx");
4618 emitcode("", "; genAddrOf");
4623 emitcode("", "; genJumpTab");
4628 emitcode("", "; genCast");
4633 emitcode("", "; genReceive");
4638 emitcode("", "; addSet");
4639 addSet(&sendSet,ic);
4644 /* piCode(ic,stdout); */
4650 /* now we are ready to call the
4651 peep hole optimizer */
4652 if (!options.nopeep)
4653 peepHole (&lineHead);
4655 /* now do the actual printing */
4656 printLine (lineHead,codeOutFile);