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 emitCall(ic, FALSE);
1762 /*-----------------------------------------------------------------*/
1763 /* genPcall - generates a call by pointer statement */
1764 /*-----------------------------------------------------------------*/
1765 static void genPcall (iCode *ic)
1770 /*-----------------------------------------------------------------*/
1771 /* resultRemat - result is rematerializable */
1772 /*-----------------------------------------------------------------*/
1773 static int resultRemat (iCode *ic)
1775 if (SKIP_IC(ic) || ic->op == IFX)
1778 if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
1779 symbol *sym = OP_SYMBOL(IC_RESULT(ic));
1780 if (sym->remat && !POINTER_SET(ic))
1787 /*-----------------------------------------------------------------*/
1788 /* genFunction - generated code for function entry */
1789 /*-----------------------------------------------------------------*/
1790 static void genFunction (iCode *ic)
1792 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1796 /* create the function header */
1797 emit2("!functionheader", sym->name);
1798 /* PENDING: portability. */
1799 emit2("__%s_start:", sym->rname);
1800 emit2("!functionlabeldef", sym->rname);
1802 fetype = getSpec(operandType(IC_LEFT(ic)));
1804 /* if critical function then turn interrupts off */
1805 if (SPEC_CRTCL(fetype))
1808 /* if this is an interrupt service routine then
1809 save acc, b, dpl, dph */
1810 if (IS_ISR(sym->etype)) {
1813 /* PENDING: callee-save etc */
1815 /* adjust the stack for the function */
1816 _G.stack.last = sym->stack;
1819 emit2("!enterx", sym->stack);
1822 _G.stack.offset = sym->stack;
1825 /*-----------------------------------------------------------------*/
1826 /* genEndFunction - generates epilogue for functions */
1827 /*-----------------------------------------------------------------*/
1828 static void genEndFunction (iCode *ic)
1830 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1832 if (IS_ISR(sym->etype)) {
1836 if (SPEC_CRTCL(sym->etype))
1839 /* PENDING: calleeSave */
1841 /* if debug then send end of function */
1842 if (options.debug && currFunc) {
1844 emitcode("","C$%s$%d$%d$%d ==.",
1845 ic->filename,currFunc->lastLine,
1846 ic->level,ic->block);
1847 if (IS_STATIC(currFunc->etype))
1848 emitcode("","XF%s$%s$0$0 ==.",moduleName,currFunc->name);
1850 emitcode("","XG$%s$0$0 ==.",currFunc->name);
1853 if (_G.stack.offset)
1854 emit2("!leavex", _G.stack.offset);
1857 /* PENDING: portability. */
1858 emit2("__%s_end:", sym->rname);
1860 _G.stack.pushed = 0;
1861 _G.stack.offset = 0;
1864 /*-----------------------------------------------------------------*/
1865 /* genRet - generate code for return statement */
1866 /*-----------------------------------------------------------------*/
1867 static void genRet (iCode *ic)
1870 /* Errk. This is a hack until I can figure out how
1871 to cause dehl to spill on a call */
1872 int size,offset = 0;
1874 /* if we have no return value then
1875 just generate the "ret" */
1879 /* we have something to return then
1880 move the return value into place */
1881 aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1882 size = AOP_SIZE(IC_LEFT(ic));
1884 if ((size == 2) && ((l = aopGetWord(AOP(IC_LEFT(ic)), 0)))) {
1886 emitcode("ld", "de,%s", l);
1889 emitcode("ld", "hl,%s", l);
1893 if (IS_GB && size == 4 && requiresHL(AOP(IC_LEFT(ic)))) {
1894 fetchPair(PAIR_DE, AOP(IC_LEFT(ic)));
1895 fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
1899 l = aopGet(AOP(IC_LEFT(ic)),offset,
1901 if (strcmp(_fReturn[offset],l))
1902 emitcode("ld","%s,%s", _fReturn[offset++],l);
1906 freeAsmop (IC_LEFT(ic),NULL,ic);
1909 /* generate a jump to the return label
1910 if the next is not the return statement */
1911 if (!(ic->next && ic->next->op == LABEL &&
1912 IC_LABEL(ic->next) == returnLabel))
1914 emit2("jp !tlabel", returnLabel->key+100);
1917 /*-----------------------------------------------------------------*/
1918 /* genLabel - generates a label */
1919 /*-----------------------------------------------------------------*/
1920 static void genLabel (iCode *ic)
1922 /* special case never generate */
1923 if (IC_LABEL(ic) == entryLabel)
1926 emitLabel(IC_LABEL(ic)->key+100);
1929 /*-----------------------------------------------------------------*/
1930 /* genGoto - generates a ljmp */
1931 /*-----------------------------------------------------------------*/
1932 static void genGoto (iCode *ic)
1934 emit2("jp !tlabel", IC_LABEL(ic)->key+100);
1937 /*-----------------------------------------------------------------*/
1938 /* genPlusIncr :- does addition with increment if possible */
1939 /*-----------------------------------------------------------------*/
1940 static bool genPlusIncr (iCode *ic)
1942 unsigned int icount ;
1943 unsigned int size = getDataSize(IC_RESULT(ic));
1944 PAIR_ID resultId = getPairId(AOP(IC_RESULT(ic)));
1946 /* will try to generate an increment */
1947 /* if the right side is not a literal
1949 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1952 emitcode("", "; genPlusIncr");
1954 icount = floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
1956 /* If result is a pair */
1957 if (resultId != PAIR_INVALID) {
1958 if (isLitWord(AOP(IC_LEFT(ic)))) {
1959 fetchLitPair(getPairId(AOP(IC_RESULT(ic))), AOP(IC_LEFT(ic)), icount);
1962 if (isPair(AOP(IC_LEFT(ic))) && resultId == PAIR_HL && icount > 2) {
1963 fetchPair(resultId, AOP(IC_RIGHT(ic)));
1964 emitcode("add", "hl,%s", getPairName(AOP(IC_LEFT(ic))));
1970 if (!sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
1973 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
1974 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
1977 emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
1982 /* if the literal value of the right hand side
1983 is greater than 4 then it is not worth it */
1987 /* if increment 16 bits in register */
1988 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1993 symbol *tlbl = NULL;
1994 tlbl = newiTempLabel(NULL);
1996 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)), offset++, FALSE));
1998 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2001 emitLabel(tlbl->key+100);
2005 /* if the sizes are greater than 1 then we cannot */
2006 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2007 AOP_SIZE(IC_LEFT(ic)) > 1 )
2010 /* we can if the aops of the left & result match or
2011 if they are in registers and the registers are the
2013 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
2015 emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0, FALSE));
2022 /*-----------------------------------------------------------------*/
2023 /* outBitAcc - output a bit in acc */
2024 /*-----------------------------------------------------------------*/
2025 void outBitAcc(operand *result)
2027 symbol *tlbl = newiTempLabel(NULL);
2028 /* if the result is a bit */
2029 if (AOP_TYPE(result) == AOP_CRY){
2033 emit2("!shortjp z,!tlabel", tlbl->key+100);
2035 emitLabel(tlbl->key+100);
2040 /*-----------------------------------------------------------------*/
2041 /* genPlus - generates code for addition */
2042 /*-----------------------------------------------------------------*/
2043 static void genPlus (iCode *ic)
2045 int size, offset = 0;
2047 /* special cases :- */
2049 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
2050 aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
2051 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
2053 /* Swap the left and right operands if:
2055 if literal, literal on the right or
2056 if left requires ACC or right is already
2059 if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
2060 (AOP_NEEDSACC(IC_LEFT(ic))) ||
2061 AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
2062 operand *t = IC_RIGHT(ic);
2063 IC_RIGHT(ic) = IC_LEFT(ic);
2067 /* if both left & right are in bit
2069 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2070 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2075 /* if left in bit space & right literal */
2076 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2077 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
2078 /* Can happen I guess */
2082 /* if I can do an increment instead
2083 of add then GOOD for ME */
2084 if (genPlusIncr (ic) == TRUE)
2087 size = getDataSize(IC_RESULT(ic));
2089 /* Special case when left and right are constant */
2090 if (isPair(AOP(IC_RESULT(ic)))) {
2093 left = aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE);
2094 right = aopGetLitWordLong(AOP(IC_RIGHT(ic)), 0, FALSE);
2095 if (left && right) {
2099 sprintf(buffer, "#(%s + %s)", left, right);
2100 emitcode("ld", "%s,%s", getPairName(AOP(IC_RESULT(ic))), buffer);
2105 if (isPair(AOP(IC_RIGHT(ic))) && getPairId(AOP(IC_RESULT(ic))) == PAIR_HL) {
2106 /* Fetch into HL then do the add */
2108 fetchPair(PAIR_HL, AOP(IC_LEFT(ic)));
2109 emitcode("add", "hl,%s", getPairName(AOP(IC_RIGHT(ic))));
2114 if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
2115 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2117 emitcode("add","a,%s",
2118 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2120 emitcode("adc","a,%s",
2121 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2123 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2125 emitcode("add","a,%s",
2126 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2128 emitcode("adc","a,%s",
2129 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2131 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2134 /* Some kind of pointer arith. */
2135 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2136 AOP_SIZE(IC_LEFT(ic)) == 3 &&
2137 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2140 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2141 AOP_SIZE(IC_RIGHT(ic)) == 3 &&
2142 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
2147 freeAsmop(IC_LEFT(ic),NULL,ic);
2148 freeAsmop(IC_RIGHT(ic),NULL,ic);
2149 freeAsmop(IC_RESULT(ic),NULL,ic);
2153 /*-----------------------------------------------------------------*/
2154 /* genMinusDec :- does subtraction with deccrement if possible */
2155 /*-----------------------------------------------------------------*/
2156 static bool genMinusDec (iCode *ic)
2158 unsigned int icount ;
2159 unsigned int size = getDataSize(IC_RESULT(ic));
2161 /* will try to generate an increment */
2162 /* if the right side is not a literal we cannot */
2163 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
2166 /* if the literal value of the right hand side
2167 is greater than 4 then it is not worth it */
2168 if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
2171 size = getDataSize(IC_RESULT(ic));
2174 /* if increment 16 bits in register */
2175 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2178 symbol *tlbl = newiTempLabel(NULL);
2179 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
2180 emitcode("jp", "np," LABEL_STR ,tlbl->key+100);
2182 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
2186 emitLabel(tlbl->key+100);
2191 /* if decrement 16 bits in register */
2192 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2193 (size > 1) && isPair(AOP(IC_RESULT(ic)))) {
2195 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2199 /* If result is a pair */
2200 if (isPair(AOP(IC_RESULT(ic)))) {
2201 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
2202 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
2204 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2208 /* if the sizes are greater than 1 then we cannot */
2209 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2210 AOP_SIZE(IC_LEFT(ic)) > 1 )
2213 /* we can if the aops of the left & result match or if they are in
2214 registers and the registers are the same */
2215 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
2217 emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE));
2224 /*-----------------------------------------------------------------*/
2225 /* genMinus - generates code for subtraction */
2226 /*-----------------------------------------------------------------*/
2227 static void genMinus (iCode *ic)
2229 int size, offset = 0;
2230 unsigned long lit = 0L;
2232 aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
2233 aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
2234 aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
2236 /* special cases :- */
2237 /* if both left & right are in bit space */
2238 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2239 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2244 /* if I can do an decrement instead of subtract then GOOD for ME */
2245 if (genMinusDec (ic) == TRUE)
2248 size = getDataSize(IC_RESULT(ic));
2250 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
2253 lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
2258 /* if literal, add a,#-lit, else normal subb */
2260 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2261 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) {
2263 emitcode("sub","a,%s",
2264 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2266 emitcode("sbc","a,%s",
2267 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2270 /* first add without previous c */
2272 emit2("add a,!immedbyte", (unsigned int)(lit & 0x0FFL));
2274 emit2("adc a,!immedbyte", (unsigned int)((lit >> (offset*8)) & 0x0FFL));
2276 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2279 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
2280 AOP_SIZE(IC_LEFT(ic)) == 3 &&
2281 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2285 freeAsmop(IC_LEFT(ic),NULL,ic);
2286 freeAsmop(IC_RIGHT(ic),NULL,ic);
2287 freeAsmop(IC_RESULT(ic),NULL,ic);
2290 /*-----------------------------------------------------------------*/
2291 /* genMult - generates code for multiplication */
2292 /*-----------------------------------------------------------------*/
2293 static void genMult (iCode *ic)
2295 /* Shouldn't occur - all done through function calls */
2299 /*-----------------------------------------------------------------*/
2300 /* genDiv - generates code for division */
2301 /*-----------------------------------------------------------------*/
2302 static void genDiv (iCode *ic)
2304 /* Shouldn't occur - all done through function calls */
2308 /*-----------------------------------------------------------------*/
2309 /* genMod - generates code for division */
2310 /*-----------------------------------------------------------------*/
2311 static void genMod (iCode *ic)
2313 /* Shouldn't occur - all done through function calls */
2317 /*-----------------------------------------------------------------*/
2318 /* genIfxJump :- will create a jump depending on the ifx */
2319 /*-----------------------------------------------------------------*/
2320 static void genIfxJump (iCode *ic, char *jval)
2325 /* if true label then we jump if condition
2327 if ( IC_TRUE(ic) ) {
2329 if (!strcmp(jval, "a")) {
2332 else if (!strcmp(jval, "c")) {
2336 /* The buffer contains the bit on A that we should test */
2341 /* false label is present */
2342 jlbl = IC_FALSE(ic) ;
2343 if (!strcmp(jval, "a")) {
2346 else if (!strcmp(jval, "c")) {
2350 /* The buffer contains the bit on A that we should test */
2354 /* Z80 can do a conditional long jump */
2355 if (!strcmp(jval, "a")) {
2356 emitcode("or", "a,a");
2358 else if (!strcmp(jval, "c")) {
2361 emitcode("bit", "%s,a", jval);
2363 emit2("jp %s,!tlabel", inst, jlbl->key+100);
2365 /* mark the icode as generated */
2369 /** Generic compare for > or <
2371 static void genCmp (operand *left,operand *right,
2372 operand *result, iCode *ifx, int sign)
2374 int size, offset = 0 ;
2375 unsigned long lit = 0L;
2377 /* if left & right are bit variables */
2378 if (AOP_TYPE(left) == AOP_CRY &&
2379 AOP_TYPE(right) == AOP_CRY ) {
2380 /* Cant happen on the Z80 */
2383 /* subtract right from left if at the
2384 end the carry flag is set then we know that
2385 left is greater than right */
2386 size = max(AOP_SIZE(left),AOP_SIZE(right));
2388 /* if unsigned char cmp with lit, just compare */
2390 (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
2391 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2393 emit2("xor a,!immedbyte", 0x80);
2394 emit2("cp %s^!constbyte", aopGet(AOP(right), offset, FALSE), 0x80);
2397 emitcode("cp", "%s", aopGet(AOP(right), offset, FALSE));
2400 if(AOP_TYPE(right) == AOP_LIT) {
2401 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2402 /* optimize if(x < 0) or if(x >= 0) */
2405 /* No sign so it's always false */
2409 /* Just load in the top most bit */
2410 MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE));
2411 if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx) {
2412 genIfxJump (ifx,"7");
2416 emitcode("rlc","a");
2422 /* First setup h and l contaning the top most bytes XORed */
2423 bool fDidXor = FALSE;
2424 if (AOP_TYPE(left) == AOP_LIT){
2425 unsigned long lit = (unsigned long)
2426 floatFromVal(AOP(left)->aopu.aop_lit);
2427 emit2("ld %s,!immedbyte", _fTmp[0],
2428 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2431 emitcode("ld", "a,%s", aopGet(AOP(left), size-1, FALSE));
2432 emit2("xor a,!immedbyte", 0x80);
2433 emitcode("ld", "%s,a", _fTmp[0]);
2436 if (AOP_TYPE(right) == AOP_LIT) {
2437 unsigned long lit = (unsigned long)
2438 floatFromVal(AOP(right)->aopu.aop_lit);
2439 emit2("ld %s,!immedbyte", _fTmp[1],
2440 0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2443 emitcode("ld", "a,%s", aopGet(AOP(right), size-1, FALSE));
2444 emit2("xor a,!immedbyte", 0x80);
2445 emitcode("ld", "%s,a", _fTmp[1]);
2455 /* Do a long subtract */
2456 if (!sign || size ) {
2457 MOVA(aopGet(AOP(left),offset,FALSE));
2459 if (sign && size == 0) {
2460 emitcode("ld", "a,%s", _fTmp[0]);
2461 emitcode("sbc", "a,%s", _fTmp[1]);
2464 /* Subtract through, propagating the carry */
2465 emitcode("sbc","a,%s ; 2",aopGet(AOP(right),offset++,FALSE));
2472 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2475 /* if the result is used in the next
2476 ifx conditional branch then generate
2477 code a little differently */
2479 genIfxJump (ifx,"c");
2482 /* leave the result in acc */
2486 /*-----------------------------------------------------------------*/
2487 /* genCmpGt :- greater than comparison */
2488 /*-----------------------------------------------------------------*/
2489 static void genCmpGt (iCode *ic, iCode *ifx)
2491 operand *left, *right, *result;
2492 link *letype , *retype;
2496 right= IC_RIGHT(ic);
2497 result = IC_RESULT(ic);
2499 letype = getSpec(operandType(left));
2500 retype =getSpec(operandType(right));
2501 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2502 /* assign the amsops */
2503 aopOp (left,ic,FALSE, FALSE);
2504 aopOp (right,ic,FALSE, FALSE);
2505 aopOp (result,ic,TRUE, FALSE);
2507 genCmp(right, left, result, ifx, sign);
2509 freeAsmop(left,NULL,ic);
2510 freeAsmop(right,NULL,ic);
2511 freeAsmop(result,NULL,ic);
2514 /*-----------------------------------------------------------------*/
2515 /* genCmpLt - less than comparisons */
2516 /*-----------------------------------------------------------------*/
2517 static void genCmpLt (iCode *ic, iCode *ifx)
2519 operand *left, *right, *result;
2520 link *letype , *retype;
2524 right= IC_RIGHT(ic);
2525 result = IC_RESULT(ic);
2527 letype = getSpec(operandType(left));
2528 retype =getSpec(operandType(right));
2529 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2531 /* assign the amsops */
2532 aopOp (left,ic,FALSE, FALSE);
2533 aopOp (right,ic,FALSE, FALSE);
2534 aopOp (result,ic,TRUE, FALSE);
2536 genCmp(left, right, result, ifx, sign);
2538 freeAsmop(left,NULL,ic);
2539 freeAsmop(right,NULL,ic);
2540 freeAsmop(result,NULL,ic);
2543 /*-----------------------------------------------------------------*/
2544 /* gencjneshort - compare and jump if not equal */
2545 /*-----------------------------------------------------------------*/
2546 static void gencjneshort(operand *left, operand *right, symbol *lbl)
2548 int size = max(AOP_SIZE(left),AOP_SIZE(right));
2550 unsigned long lit = 0L;
2552 /* Swap the left and right if it makes the computation easier */
2553 if (AOP_TYPE(left) == AOP_LIT) {
2559 if(AOP_TYPE(right) == AOP_LIT)
2560 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2562 /* if the right side is a literal then anything goes */
2563 if (AOP_TYPE(right) == AOP_LIT &&
2564 AOP_TYPE(left) != AOP_DIR ) {
2566 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2571 emitcode("or", "a,%s", aopGet(AOP(left), offset, FALSE));
2575 emitcode("or", "a,a");
2577 emit2("jp nz,!tlabel", lbl->key+100);
2581 emitcode("ld", "a,%s ; 2", aopGet(AOP(left),offset,FALSE));
2582 if ((AOP_TYPE(right) == AOP_LIT) && lit == 0)
2583 emitcode("or", "a,a");
2585 emitcode("cp", "a,%s", aopGet(AOP(right),offset,FALSE));
2586 emit2("jp nz,!tlabel", lbl->key+100);
2591 /* if the right side is in a register or in direct space or
2592 if the left is a pointer register & right is not */
2593 else if (AOP_TYPE(right) == AOP_REG ||
2594 AOP_TYPE(right) == AOP_DIR ||
2595 (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT)) {
2597 MOVA(aopGet(AOP(left),offset,FALSE));
2598 if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
2599 ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
2601 emit2("jp nz,!tlabel", lbl->key+100);
2603 emitcode("cp", "%s ; 4", aopGet(AOP(right),offset,FALSE));
2604 emit2("jp nz,!tlabel", lbl->key+100);
2609 /* right is a pointer reg need both a & b */
2610 /* PENDING: is this required? */
2612 MOVA(aopGet(AOP(right),offset,FALSE));
2613 emitcode("cp", "%s ; 5", aopGet(AOP(left), offset, FALSE));
2614 emit2("!shortjp nz,!tlabel", lbl->key+100);
2620 /*-----------------------------------------------------------------*/
2621 /* gencjne - compare and jump if not equal */
2622 /*-----------------------------------------------------------------*/
2623 static void gencjne(operand *left, operand *right, symbol *lbl)
2625 symbol *tlbl = newiTempLabel(NULL);
2627 gencjneshort(left, right, lbl);
2631 emit2("!shortjp !tlabel", tlbl->key+100);
2632 emitLabel(lbl->key+100);
2633 emitcode("xor","a,a");
2634 emitLabel(tlbl->key+100);
2637 /*-----------------------------------------------------------------*/
2638 /* genCmpEq - generates code for equal to */
2639 /*-----------------------------------------------------------------*/
2640 static void genCmpEq (iCode *ic, iCode *ifx)
2642 operand *left, *right, *result;
2644 aopOp((left=IC_LEFT(ic)),ic,FALSE, FALSE);
2645 aopOp((right=IC_RIGHT(ic)),ic,FALSE, FALSE);
2646 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2648 /* Swap operands if it makes the operation easier. ie if:
2649 1. Left is a literal.
2651 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
2652 operand *t = IC_RIGHT(ic);
2653 IC_RIGHT(ic) = IC_LEFT(ic);
2657 if (ifx && !AOP_SIZE(result)){
2659 /* if they are both bit variables */
2660 if (AOP_TYPE(left) == AOP_CRY &&
2661 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2664 tlbl = newiTempLabel(NULL);
2665 gencjneshort(left, right, tlbl);
2666 if ( IC_TRUE(ifx) ) {
2667 emit2("jp !tlabel", IC_TRUE(ifx)->key+100);
2668 emitLabel(tlbl->key+100);
2670 /* PENDING: do this better */
2671 symbol *lbl = newiTempLabel(NULL);
2672 emit2("!shortjp !tlabel", lbl->key+100);
2673 emitLabel(tlbl->key+100);
2674 emit2("jp !tlabel", IC_FALSE(ifx)->key+100);
2675 emitLabel(lbl->key+100);
2678 /* mark the icode as generated */
2683 /* if they are both bit variables */
2684 if (AOP_TYPE(left) == AOP_CRY &&
2685 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2688 gencjne(left,right,newiTempLabel(NULL));
2689 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2693 genIfxJump(ifx,"a");
2696 /* if the result is used in an arithmetic operation
2697 then put the result in place */
2698 if (AOP_TYPE(result) != AOP_CRY) {
2701 /* leave the result in acc */
2705 freeAsmop(left,NULL,ic);
2706 freeAsmop(right,NULL,ic);
2707 freeAsmop(result,NULL,ic);
2710 /*-----------------------------------------------------------------*/
2711 /* ifxForOp - returns the icode containing the ifx for operand */
2712 /*-----------------------------------------------------------------*/
2713 static iCode *ifxForOp ( operand *op, iCode *ic )
2715 /* if true symbol then needs to be assigned */
2716 if (IS_TRUE_SYMOP(op))
2719 /* if this has register type condition and
2720 the next instruction is ifx with the same operand
2721 and live to of the operand is upto the ifx only then */
2723 ic->next->op == IFX &&
2724 IC_COND(ic->next)->key == op->key &&
2725 OP_SYMBOL(op)->liveTo <= ic->next->seq )
2731 /*-----------------------------------------------------------------*/
2732 /* genAndOp - for && operation */
2733 /*-----------------------------------------------------------------*/
2734 static void genAndOp (iCode *ic)
2736 operand *left,*right, *result;
2739 /* note here that && operations that are in an if statement are
2740 taken away by backPatchLabels only those used in arthmetic
2741 operations remain */
2742 aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2743 aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2744 aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2746 /* if both are bit variables */
2747 if (AOP_TYPE(left) == AOP_CRY &&
2748 AOP_TYPE(right) == AOP_CRY ) {
2751 tlbl = newiTempLabel(NULL);
2753 emit2("!shortjp z,!tlabel", tlbl->key+100);
2755 emitLabel(tlbl->key+100);
2759 freeAsmop(left,NULL,ic);
2760 freeAsmop(right,NULL,ic);
2761 freeAsmop(result,NULL,ic);
2764 /*-----------------------------------------------------------------*/
2765 /* genOrOp - for || operation */
2766 /*-----------------------------------------------------------------*/
2767 static void genOrOp (iCode *ic)
2769 operand *left,*right, *result;
2772 /* note here that || operations that are in an
2773 if statement are taken away by backPatchLabels
2774 only those used in arthmetic operations remain */
2775 aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2776 aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2777 aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2779 /* if both are bit variables */
2780 if (AOP_TYPE(left) == AOP_CRY &&
2781 AOP_TYPE(right) == AOP_CRY ) {
2784 tlbl = newiTempLabel(NULL);
2786 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2788 emitLabel(tlbl->key+100);
2792 freeAsmop(left,NULL,ic);
2793 freeAsmop(right,NULL,ic);
2794 freeAsmop(result,NULL,ic);
2797 /*-----------------------------------------------------------------*/
2798 /* isLiteralBit - test if lit == 2^n */
2799 /*-----------------------------------------------------------------*/
2800 int isLiteralBit(unsigned long lit)
2802 unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
2803 0x100L,0x200L,0x400L,0x800L,
2804 0x1000L,0x2000L,0x4000L,0x8000L,
2805 0x10000L,0x20000L,0x40000L,0x80000L,
2806 0x100000L,0x200000L,0x400000L,0x800000L,
2807 0x1000000L,0x2000000L,0x4000000L,0x8000000L,
2808 0x10000000L,0x20000000L,0x40000000L,0x80000000L};
2811 for(idx = 0; idx < 32; idx++)
2817 /*-----------------------------------------------------------------*/
2818 /* jmpTrueOrFalse - */
2819 /*-----------------------------------------------------------------*/
2820 static void jmpTrueOrFalse (iCode *ic, symbol *tlbl)
2822 // ugly but optimized by peephole
2824 symbol *nlbl = newiTempLabel(NULL);
2825 emit2("jp !tlabel", nlbl->key+100);
2826 emitLabel(tlbl->key+100);
2827 emit2("jp !tlabel", IC_TRUE(ic)->key+100);
2828 emitLabel(nlbl->key+100);
2831 emit2("jp !tlabel", IC_FALSE(ic)->key+100);
2832 emitLabel(tlbl->key+100);
2837 /*-----------------------------------------------------------------*/
2838 /* genAnd - code for and */
2839 /*-----------------------------------------------------------------*/
2840 static void genAnd (iCode *ic, iCode *ifx)
2842 operand *left, *right, *result;
2844 unsigned long lit = 0L;
2847 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
2848 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
2849 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2852 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2854 AOP_TYPE(left), AOP_TYPE(right));
2855 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2857 AOP_SIZE(left), AOP_SIZE(right));
2860 /* if left is a literal & right is not then exchange them */
2861 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2862 AOP_NEEDSACC(left)) {
2863 operand *tmp = right ;
2868 /* if result = right then exchange them */
2869 if(sameRegs(AOP(result),AOP(right))){
2870 operand *tmp = right ;
2875 /* if right is bit then exchange them */
2876 if (AOP_TYPE(right) == AOP_CRY &&
2877 AOP_TYPE(left) != AOP_CRY){
2878 operand *tmp = right ;
2882 if(AOP_TYPE(right) == AOP_LIT)
2883 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2885 size = AOP_SIZE(result);
2887 if (AOP_TYPE(left) == AOP_CRY){
2892 // if(val & 0xZZ) - size = 0, ifx != FALSE -
2893 // bit = val & 0xZZ - size = 1, ifx = FALSE -
2894 if((AOP_TYPE(right) == AOP_LIT) &&
2895 (AOP_TYPE(result) == AOP_CRY) &&
2896 (AOP_TYPE(left) != AOP_CRY)) {
2897 int posbit = isLiteralBit(lit);
2901 MOVA(aopGet(AOP(left),posbit>>3,FALSE));
2905 emitcode("mov","c,acc.%d",posbit&0x07);
2910 sprintf(buffer, "%d", posbit&0x07);
2911 genIfxJump(ifx, buffer);
2919 symbol *tlbl = newiTempLabel(NULL);
2920 int sizel = AOP_SIZE(left);
2923 emitcode("setb","c");
2926 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
2927 MOVA( aopGet(AOP(left),offset,FALSE));
2929 if((posbit = isLiteralBit(bytelit)) != 0) {
2931 emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
2934 if(bytelit != 0x0FFL)
2935 emitcode("and","a,%s",
2936 aopGet(AOP(right),offset,FALSE));
2940 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2945 // bit = left & literal
2947 emitcode("clr","c");
2948 emit2("!tlabeldef", tlbl->key+100);
2950 // if(left & literal)
2953 jmpTrueOrFalse(ifx, tlbl);
2961 /* if left is same as result */
2962 if(sameRegs(AOP(result),AOP(left))){
2963 for(;size--; offset++) {
2964 if(AOP_TYPE(right) == AOP_LIT){
2965 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
2969 aopPut(AOP(result),zero,offset);
2971 MOVA(aopGet(AOP(left),offset,FALSE));
2972 emitcode("and","a,%s",
2973 aopGet(AOP(right),offset,FALSE));
2974 aopPut(AOP(left), "a", offset);
2979 if (AOP_TYPE(left) == AOP_ACC) {
2983 MOVA(aopGet(AOP(left),offset,FALSE));
2984 emitcode("and","a,%s",
2985 aopGet(AOP(right),offset,FALSE));
2986 aopPut(AOP(left), "a", offset);
2991 // left & result in different registers
2992 if(AOP_TYPE(result) == AOP_CRY){
2995 for(;(size--);offset++) {
2997 // result = left & right
2998 if(AOP_TYPE(right) == AOP_LIT){
2999 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
3001 aopGet(AOP(left),offset,FALSE),
3004 } else if(bytelit == 0){
3005 aopPut(AOP(result),zero,offset);
3009 // faster than result <- left, anl result,right
3010 // and better if result is SFR
3011 if (AOP_TYPE(left) == AOP_ACC)
3012 emitcode("and","a,%s",aopGet(AOP(right),offset,FALSE));
3014 MOVA(aopGet(AOP(left),offset,FALSE));
3015 emitcode("and","a,%s",
3016 aopGet(AOP(right),offset,FALSE));
3018 aopPut(AOP(result),"a",offset);
3025 freeAsmop(left,NULL,ic);
3026 freeAsmop(right,NULL,ic);
3027 freeAsmop(result,NULL,ic);
3030 /*-----------------------------------------------------------------*/
3031 /* genOr - code for or */
3032 /*-----------------------------------------------------------------*/
3033 static void genOr (iCode *ic, iCode *ifx)
3035 operand *left, *right, *result;
3037 unsigned long lit = 0L;
3039 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3040 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3041 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3044 emitcode("","; Type res[%d] = l[%d]&r[%d]",
3046 AOP_TYPE(left), AOP_TYPE(right));
3047 emitcode("","; Size res[%d] = l[%d]&r[%d]",
3049 AOP_SIZE(left), AOP_SIZE(right));
3052 /* if left is a literal & right is not then exchange them */
3053 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3054 AOP_NEEDSACC(left)) {
3055 operand *tmp = right ;
3060 /* if result = right then exchange them */
3061 if(sameRegs(AOP(result),AOP(right))){
3062 operand *tmp = right ;
3067 /* if right is bit then exchange them */
3068 if (AOP_TYPE(right) == AOP_CRY &&
3069 AOP_TYPE(left) != AOP_CRY){
3070 operand *tmp = right ;
3074 if(AOP_TYPE(right) == AOP_LIT)
3075 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3077 size = AOP_SIZE(result);
3079 if (AOP_TYPE(left) == AOP_CRY){
3084 if((AOP_TYPE(right) == AOP_LIT) &&
3085 (AOP_TYPE(result) == AOP_CRY) &&
3086 (AOP_TYPE(left) != AOP_CRY)){
3091 /* if left is same as result */
3092 if(sameRegs(AOP(result),AOP(left))){
3093 for(;size--; offset++) {
3094 if(AOP_TYPE(right) == AOP_LIT){
3095 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3098 MOVA(aopGet(AOP(left),offset,FALSE));
3099 emitcode("or","a,%s",
3100 aopGet(AOP(right),offset,FALSE));
3101 aopPut(AOP(result),"a", offset);
3104 if (AOP_TYPE(left) == AOP_ACC)
3105 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
3107 MOVA(aopGet(AOP(left),offset,FALSE));
3108 emitcode("or","a,%s",
3109 aopGet(AOP(right),offset,FALSE));
3110 aopPut(AOP(result),"a", offset);
3115 // left & result in different registers
3116 if(AOP_TYPE(result) == AOP_CRY){
3118 } else for(;(size--);offset++){
3120 // result = left & right
3121 if(AOP_TYPE(right) == AOP_LIT){
3122 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3124 aopGet(AOP(left),offset,FALSE),
3129 // faster than result <- left, anl result,right
3130 // and better if result is SFR
3131 if (AOP_TYPE(left) == AOP_ACC)
3132 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
3134 MOVA(aopGet(AOP(left),offset,FALSE));
3135 emitcode("or","a,%s",
3136 aopGet(AOP(right),offset,FALSE));
3138 aopPut(AOP(result),"a",offset);
3139 /* PENDING: something weird is going on here. Add exception. */
3140 if (AOP_TYPE(result) == AOP_ACC)
3146 freeAsmop(left,NULL,ic);
3147 freeAsmop(right,NULL,ic);
3148 freeAsmop(result,NULL,ic);
3151 /*-----------------------------------------------------------------*/
3152 /* genXor - code for xclusive or */
3153 /*-----------------------------------------------------------------*/
3154 static void genXor (iCode *ic, iCode *ifx)
3156 operand *left, *right, *result;
3158 unsigned long lit = 0L;
3160 aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3161 aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3162 aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3164 /* if left is a literal & right is not then exchange them */
3165 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3166 AOP_NEEDSACC(left)) {
3167 operand *tmp = right ;
3172 /* if result = right then exchange them */
3173 if(sameRegs(AOP(result),AOP(right))){
3174 operand *tmp = right ;
3179 /* if right is bit then exchange them */
3180 if (AOP_TYPE(right) == AOP_CRY &&
3181 AOP_TYPE(left) != AOP_CRY){
3182 operand *tmp = right ;
3186 if(AOP_TYPE(right) == AOP_LIT)
3187 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3189 size = AOP_SIZE(result);
3191 if (AOP_TYPE(left) == AOP_CRY){
3196 if((AOP_TYPE(right) == AOP_LIT) &&
3197 (AOP_TYPE(result) == AOP_CRY) &&
3198 (AOP_TYPE(left) != AOP_CRY)){
3203 /* if left is same as result */
3204 if(sameRegs(AOP(result),AOP(left))){
3205 for(;size--; offset++) {
3206 if(AOP_TYPE(right) == AOP_LIT){
3207 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3210 MOVA(aopGet(AOP(right),offset,FALSE));
3211 emitcode("xor","a,%s",
3212 aopGet(AOP(left),offset,FALSE));
3213 aopPut(AOP(result),"a",0);
3216 if (AOP_TYPE(left) == AOP_ACC)
3217 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3219 MOVA(aopGet(AOP(right),offset,FALSE));
3220 emitcode("xor","a,%s",
3221 aopGet(AOP(left),offset,FALSE));
3222 aopPut(AOP(result),"a",0);
3227 // left & result in different registers
3228 if(AOP_TYPE(result) == AOP_CRY){
3230 } else for(;(size--);offset++){
3232 // result = left & right
3233 if(AOP_TYPE(right) == AOP_LIT){
3234 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3236 aopGet(AOP(left),offset,FALSE),
3241 // faster than result <- left, anl result,right
3242 // and better if result is SFR
3243 if (AOP_TYPE(left) == AOP_ACC)
3244 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3246 MOVA(aopGet(AOP(right),offset,FALSE));
3247 emitcode("xor","a,%s",
3248 aopGet(AOP(left),offset,FALSE));
3249 aopPut(AOP(result),"a",0);
3251 aopPut(AOP(result),"a",offset);
3256 freeAsmop(left,NULL,ic);
3257 freeAsmop(right,NULL,ic);
3258 freeAsmop(result,NULL,ic);
3261 /*-----------------------------------------------------------------*/
3262 /* genInline - write the inline code out */
3263 /*-----------------------------------------------------------------*/
3264 static void genInline (iCode *ic)
3266 char buffer[MAX_INLINEASM];
3270 inLine += (!options.asmpeep);
3271 strcpy(buffer,IC_INLINE(ic));
3273 /* emit each line as a code */
3292 /* emitcode("",buffer); */
3293 inLine -= (!options.asmpeep);
3296 /*-----------------------------------------------------------------*/
3297 /* genRRC - rotate right with carry */
3298 /*-----------------------------------------------------------------*/
3299 static void genRRC (iCode *ic)
3304 /*-----------------------------------------------------------------*/
3305 /* genRLC - generate code for rotate left with carry */
3306 /*-----------------------------------------------------------------*/
3307 static void genRLC (iCode *ic)
3312 /*-----------------------------------------------------------------*/
3313 /* shiftR2Left2Result - shift right two bytes from left to result */
3314 /*-----------------------------------------------------------------*/
3315 static void shiftR2Left2Result (operand *left, int offl,
3316 operand *result, int offr,
3317 int shCount, int sign)
3319 movLeft2Result(left, offl, result, offr, 0);
3320 movLeft2Result(left, offl+1, result, offr+1, 0);
3326 /* if (AOP(result)->type == AOP_REG) {*/
3329 symbol *tlbl , *tlbl1;
3332 tlbl = newiTempLabel(NULL);
3333 tlbl1 = newiTempLabel(NULL);
3335 /* Left is already in result - so now do the shift */
3337 emit2("ld a,!immedbyte+1", shCount);
3338 emit2("!shortjp !tlabel", tlbl1->key+100);
3339 emitLabel(tlbl->key+100);
3342 emitcode("or", "a,a");
3345 l = aopGet(AOP(result), --offset, FALSE);
3346 emitcode("rr","%s", l);
3349 emitLabel(tlbl1->key+100);
3350 emitcode("dec", "a");
3351 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3356 /*-----------------------------------------------------------------*/
3357 /* shiftL2Left2Result - shift left two bytes from left to result */
3358 /*-----------------------------------------------------------------*/
3359 static void shiftL2Left2Result (operand *left, int offl,
3360 operand *result, int offr, int shCount)
3362 if(sameRegs(AOP(result), AOP(left)) &&
3363 ((offl + MSB16) == offr)){
3366 /* Copy left into result */
3367 movLeft2Result(left, offl, result, offr, 0);
3368 movLeft2Result(left, offl+1, result, offr+1, 0);
3370 /* PENDING: for now just see if it'll work. */
3371 /*if (AOP(result)->type == AOP_REG) { */
3375 symbol *tlbl , *tlbl1;
3378 tlbl = newiTempLabel(NULL);
3379 tlbl1 = newiTempLabel(NULL);
3381 /* Left is already in result - so now do the shift */
3383 emit2("ld a,!immedbyte+1", shCount);
3384 emit2("!shortjp !tlabel", tlbl1->key+100);
3385 emitLabel(tlbl->key+100);
3388 emitcode("or", "a,a");
3390 l = aopGet(AOP(result),offset++,FALSE);
3391 emitcode("rl","%s", l);
3394 emitLabel(tlbl1->key+100);
3395 emitcode("dec", "a");
3396 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3401 /*-----------------------------------------------------------------*/
3402 /* AccRol - rotate left accumulator by known count */
3403 /*-----------------------------------------------------------------*/
3404 static void AccRol (int shCount)
3406 shCount &= 0x0007; // shCount : 0..7
3443 /*-----------------------------------------------------------------*/
3444 /* AccLsh - left shift accumulator by known count */
3445 /*-----------------------------------------------------------------*/
3446 static void AccLsh (int shCount)
3450 emitcode("add","a,a");
3452 else if(shCount == 2) {
3453 emitcode("add","a,a");
3454 emitcode("add","a,a");
3456 /* rotate left accumulator */
3458 /* and kill the lower order bits */
3459 emit2("and a,!immedbyte", SLMask[shCount]);
3464 /*-----------------------------------------------------------------*/
3465 /* shiftL1Left2Result - shift left one byte from left to result */
3466 /*-----------------------------------------------------------------*/
3467 static void shiftL1Left2Result (operand *left, int offl,
3468 operand *result, int offr, int shCount)
3471 l = aopGet(AOP(left),offl,FALSE);
3473 /* shift left accumulator */
3475 aopPut(AOP(result),"a",offr);
3479 /*-----------------------------------------------------------------*/
3480 /* genlshTwo - left shift two bytes by known amount != 0 */
3481 /*-----------------------------------------------------------------*/
3482 static void genlshTwo (operand *result,operand *left, int shCount)
3484 int size = AOP_SIZE(result);
3488 /* if shCount >= 8 */
3493 movLeft2Result(left, LSB, result, MSB16, 0);
3494 aopPut(AOP(result),zero, 0);
3495 shiftL1Left2Result(left, MSB16, result, MSB16, shCount);
3498 movLeft2Result(left, LSB, result, MSB16, 0);
3499 aopPut(AOP(result),zero, 0);
3503 aopPut(AOP(result),zero,LSB);
3506 /* 1 <= shCount <= 7 */
3512 shiftL2Left2Result(left, LSB, result, LSB, shCount);
3517 /*-----------------------------------------------------------------*/
3518 /* genlshOne - left shift a one byte quantity by known count */
3519 /*-----------------------------------------------------------------*/
3520 static void genlshOne (operand *result, operand *left, int shCount)
3522 shiftL1Left2Result(left, LSB, result, LSB, shCount);
3525 /*-----------------------------------------------------------------*/
3526 /* genLeftShiftLiteral - left shifting by known count */
3527 /*-----------------------------------------------------------------*/
3528 static void genLeftShiftLiteral (operand *left,
3533 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3536 freeAsmop(right,NULL,ic);
3538 aopOp(left,ic,FALSE, FALSE);
3539 aopOp(result,ic,FALSE, FALSE);
3541 size = getSize(operandType(result));
3544 emitcode("; shift left ","result %d, left %d",size,
3548 /* I suppose that the left size >= result size */
3553 else if(shCount >= (size * 8))
3555 aopPut(AOP(result),zero,size);
3559 genlshOne (result,left,shCount);
3562 genlshTwo (result,left,shCount);
3571 freeAsmop(left,NULL,ic);
3572 freeAsmop(result,NULL,ic);
3575 /*-----------------------------------------------------------------*/
3576 /* genLeftShift - generates code for left shifting */
3577 /*-----------------------------------------------------------------*/
3578 static void genLeftShift (iCode *ic)
3582 symbol *tlbl , *tlbl1;
3583 operand *left,*right, *result;
3585 right = IC_RIGHT(ic);
3587 result = IC_RESULT(ic);
3589 aopOp(right,ic,FALSE, FALSE);
3591 /* if the shift count is known then do it
3592 as efficiently as possible */
3593 if (AOP_TYPE(right) == AOP_LIT) {
3594 genLeftShiftLiteral (left,right,result,ic);
3598 /* shift count is unknown then we have to form a loop get the loop
3599 count in B : Note: we take only the lower order byte since
3600 shifting more that 32 bits make no sense anyway, ( the largest
3601 size of an object can be only 32 bits ) */
3602 emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE));
3603 emitcode("inc","a");
3604 freeAsmop (right,NULL,ic);
3605 aopOp(left,ic,FALSE, FALSE);
3606 aopOp(result,ic,FALSE, FALSE);
3608 /* now move the left to the result if they are not the
3611 if (!sameRegs(AOP(left),AOP(result))) {
3613 size = AOP_SIZE(result);
3616 l = aopGet(AOP(left),offset,FALSE);
3617 aopPut(AOP(result),l,offset);
3622 size = AOP_SIZE(result);
3625 l = aopGet(AOP(left),offset,FALSE);
3626 aopPut(AOP(result),l,offset);
3632 tlbl = newiTempLabel(NULL);
3633 size = AOP_SIZE(result);
3635 tlbl1 = newiTempLabel(NULL);
3637 emit2("!shortjp !tlabel", tlbl1->key+100);
3638 emitLabel(tlbl->key+100);
3639 l = aopGet(AOP(result),offset,FALSE);
3640 emitcode("or", "a,a");
3642 l = aopGet(AOP(result),offset++,FALSE);
3643 emitcode("rl","%s", l);
3645 emitLabel(tlbl1->key+100);
3646 emitcode("dec", "a");
3647 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3649 freeAsmop(left,NULL,ic);
3650 freeAsmop(result,NULL,ic);
3653 /*-----------------------------------------------------------------*/
3654 /* genrshOne - left shift two bytes by known amount != 0 */
3655 /*-----------------------------------------------------------------*/
3656 static void genrshOne (operand *result,operand *left, int shCount)
3659 int size = AOP_SIZE(result);
3665 l = aopGet(AOP(left),0,FALSE);
3666 if (AOP(result)->type == AOP_REG) {
3667 aopPut(AOP(result), l, 0);
3668 l = aopGet(AOP(result), 0, FALSE);
3670 emitcode("srl", "%s", l);
3675 emitcode("srl", "a");
3677 aopPut(AOP(result),"a",0);
3681 /*-----------------------------------------------------------------*/
3682 /* AccRsh - right shift accumulator by known count */
3683 /*-----------------------------------------------------------------*/
3684 static void AccRsh (int shCount)
3687 /* rotate right accumulator */
3688 AccRol(8 - shCount);
3689 /* and kill the higher order bits */
3690 emit2("and a,!immedbyte", SRMask[shCount]);
3694 /*-----------------------------------------------------------------*/
3695 /* shiftR1Left2Result - shift right one byte from left to result */
3696 /*-----------------------------------------------------------------*/
3697 static void shiftR1Left2Result (operand *left, int offl,
3698 operand *result, int offr,
3699 int shCount, int sign)
3701 MOVA(aopGet(AOP(left),offl,FALSE));
3708 aopPut(AOP(result),"a",offr);
3711 /*-----------------------------------------------------------------*/
3712 /* genrshTwo - right shift two bytes by known amount != 0 */
3713 /*-----------------------------------------------------------------*/
3714 static void genrshTwo (operand *result,operand *left,
3715 int shCount, int sign)
3717 /* if shCount >= 8 */
3721 shiftR1Left2Result(left, MSB16, result, LSB,
3725 movLeft2Result(left, MSB16, result, LSB, sign);
3727 aopPut(AOP(result),zero,1);
3729 /* 1 <= shCount <= 7 */
3731 shiftR2Left2Result(left, LSB, result, LSB, shCount, sign);
3735 /*-----------------------------------------------------------------*/
3736 /* genRightShiftLiteral - left shifting by known count */
3737 /*-----------------------------------------------------------------*/
3738 static void genRightShiftLiteral (operand *left,
3743 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3746 freeAsmop(right,NULL,ic);
3748 aopOp(left,ic,FALSE, FALSE);
3749 aopOp(result,ic,FALSE, FALSE);
3751 size = getSize(operandType(result));
3753 emitcode("; shift right ","result %d, left %d",size,
3756 /* I suppose that the left size >= result size */
3761 else if(shCount >= (size * 8))
3763 aopPut(AOP(result),zero,size);
3767 genrshOne(result, left, shCount);
3770 /* PENDING: sign support */
3771 genrshTwo(result, left, shCount, FALSE);
3780 freeAsmop(left,NULL,ic);
3781 freeAsmop(result,NULL,ic);
3784 /*-----------------------------------------------------------------*/
3785 /* genRightShift - generate code for right shifting */
3786 /*-----------------------------------------------------------------*/
3787 static void genRightShift (iCode *ic)
3789 operand *right, *left, *result;
3791 int size, offset, first = 1;
3795 symbol *tlbl, *tlbl1 ;
3797 /* if signed then we do it the hard way preserve the
3798 sign bit moving it inwards */
3799 retype = getSpec(operandType(IC_RESULT(ic)));
3801 is_signed = !SPEC_USIGN(retype);
3803 /* signed & unsigned types are treated the same : i.e. the
3804 signed is NOT propagated inwards : quoting from the
3805 ANSI - standard : "for E1 >> E2, is equivalent to division
3806 by 2**E2 if unsigned or if it has a non-negative value,
3807 otherwise the result is implementation defined ", MY definition
3808 is that the sign does not get propagated */
3810 right = IC_RIGHT(ic);
3812 result = IC_RESULT(ic);
3814 aopOp(right,ic,FALSE, FALSE);
3816 /* if the shift count is known then do it
3817 as efficiently as possible */
3818 if (AOP_TYPE(right) == AOP_LIT) {
3819 genRightShiftLiteral(left,right,result,ic);
3823 aopOp(left,ic,FALSE, FALSE);
3824 aopOp(result,ic,FALSE, FALSE);
3826 /* now move the left to the result if they are not the
3828 if (!sameRegs(AOP(left),AOP(result)) &&
3829 AOP_SIZE(result) > 1) {
3831 size = AOP_SIZE(result);
3834 l = aopGet(AOP(left),offset,FALSE);
3835 aopPut(AOP(result),l,offset);
3840 emitcode("ld", "a,%s",aopGet(AOP(right),0,FALSE));
3841 emitcode("inc","a");
3842 freeAsmop (right, NULL, ic);
3844 tlbl = newiTempLabel(NULL);
3845 tlbl1= newiTempLabel(NULL);
3846 size = AOP_SIZE(result);
3849 emit2("!shortjp !tlabel", tlbl1->key+100);
3850 emitLabel(tlbl->key+100);
3852 l = aopGet(AOP(result),offset--,FALSE);
3855 emitcode("sra", "%s", l);
3857 emitcode("srl", "%s", l);
3861 emitcode("rr", "%s", l);
3863 emitLabel(tlbl1->key+100);
3864 emitcode("dec", "a");
3865 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3867 freeAsmop(left,NULL,ic);
3868 freeAsmop(result,NULL,ic);
3871 /*-----------------------------------------------------------------*/
3872 /* genGenPointerGet - get value from generic pointer space */
3873 /*-----------------------------------------------------------------*/
3874 static void genGenPointerGet (operand *left,
3875 operand *result, iCode *ic)
3878 link *retype = getSpec(operandType(result));
3884 aopOp(left,ic,FALSE, FALSE);
3885 aopOp(result,ic,FALSE, FALSE);
3887 if (isPair(AOP(left)) && AOP_SIZE(result)==1) {
3889 if (isPtrPair(AOP(left)))
3891 tsprintf(buffer, "!*pair", getPairName(AOP(left)));
3892 aopPut(AOP(result), buffer, 0);
3895 emit2("ld a,!*pair", getPairName(AOP(left)));
3896 aopPut(AOP(result),"a", 0);
3898 freeAsmop(left,NULL,ic);
3902 /* For now we always load into IY */
3903 /* if this is remateriazable */
3904 fetchPair(pair, AOP(left));
3906 /* so iy now contains the address */
3907 freeAsmop(left,NULL,ic);
3909 /* if bit then unpack */
3910 if (IS_BITVAR(retype)) {
3914 size = AOP_SIZE(result);
3918 /* PENDING: make this better */
3919 if (!IS_GB && AOP(result)->type == AOP_REG) {
3920 aopPut(AOP(result), "!*hl", offset++);
3923 emit2("ld a,!*pair", _pairs[pair].name);
3924 aopPut(AOP(result),"a",offset++);
3927 emit2("inc %s", _pairs[pair].name);
3933 freeAsmop(result,NULL,ic);
3936 /*-----------------------------------------------------------------*/
3937 /* genPointerGet - generate code for pointer get */
3938 /*-----------------------------------------------------------------*/
3939 static void genPointerGet (iCode *ic)
3941 operand *left, *result ;
3945 result = IC_RESULT(ic) ;
3947 /* depending on the type of pointer we need to
3948 move it to the correct pointer register */
3949 type = operandType(left);
3950 etype = getSpec(type);
3952 genGenPointerGet (left,result,ic);
3955 bool isRegOrLit(asmop *aop)
3957 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
3962 /*-----------------------------------------------------------------*/
3963 /* genGenPointerSet - stores the value into a pointer location */
3964 /*-----------------------------------------------------------------*/
3965 static void genGenPointerSet (operand *right,
3966 operand *result, iCode *ic)
3969 link *retype = getSpec(operandType(right));
3970 PAIR_ID pairId = PAIR_HL;
3972 aopOp(result,ic,FALSE, FALSE);
3973 aopOp(right,ic,FALSE, FALSE);
3978 /* Handle the exceptions first */
3979 if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
3981 char *l = aopGet(AOP(right), 0, FALSE);
3982 const char *pair = getPairName(AOP(result));
3983 if (canAssignToPtr(l) && isPtr(pair)) {
3984 emit2("ld !*pair,%s", pair, l);
3988 emit2("ld !*pair,a", pair);
3993 /* if the operand is already in dptr
3994 then we do nothing else we move the value to dptr */
3995 if (AOP_TYPE(result) != AOP_STR) {
3996 fetchPair(pairId, AOP(result));
3998 /* so hl know contains the address */
3999 freeAsmop(result,NULL,ic);
4001 /* if bit then unpack */
4002 if (IS_BITVAR(retype)) {
4006 size = AOP_SIZE(right);
4010 char *l = aopGet(AOP(right),offset,FALSE);
4011 if (isRegOrLit(AOP(right)) && !IS_GB) {
4012 emit2("ld !*pair,%s", _pairs[pairId].name, l);
4016 emit2("ld !*pair,a", _pairs[pairId].name);
4019 emitcode("inc", _pairs[pairId].name);
4025 freeAsmop(right,NULL,ic);
4028 /*-----------------------------------------------------------------*/
4029 /* genPointerSet - stores the value into a pointer location */
4030 /*-----------------------------------------------------------------*/
4031 static void genPointerSet (iCode *ic)
4033 operand *right, *result ;
4036 right = IC_RIGHT(ic);
4037 result = IC_RESULT(ic) ;
4039 /* depending on the type of pointer we need to
4040 move it to the correct pointer register */
4041 type = operandType(result);
4042 etype = getSpec(type);
4044 genGenPointerSet (right,result,ic);
4047 /*-----------------------------------------------------------------*/
4048 /* genIfx - generate code for Ifx statement */
4049 /*-----------------------------------------------------------------*/
4050 static void genIfx (iCode *ic, iCode *popIc)
4052 operand *cond = IC_COND(ic);
4055 aopOp(cond,ic,FALSE, TRUE);
4057 /* get the value into acc */
4058 if (AOP_TYPE(cond) != AOP_CRY)
4062 /* the result is now in the accumulator */
4063 freeAsmop(cond,NULL,ic);
4065 /* if there was something to be popped then do it */
4069 /* if the condition is a bit variable */
4070 if (isbit && IS_ITEMP(cond) &&
4072 genIfxJump(ic,SPIL_LOC(cond)->rname);
4074 if (isbit && !IS_ITEMP(cond))
4075 genIfxJump(ic,OP_SYMBOL(cond)->rname);
4082 /*-----------------------------------------------------------------*/
4083 /* genAddrOf - generates code for address of */
4084 /*-----------------------------------------------------------------*/
4085 static void genAddrOf (iCode *ic)
4087 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
4089 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
4091 /* if the operand is on the stack then we
4092 need to get the stack offset of this
4097 emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
4098 emitcode("ld", "d,h");
4099 emitcode("ld", "e,l");
4102 emitcode("ld", "de,#%s", sym->rname);
4104 aopPut(AOP(IC_RESULT(ic)), "e", 0);
4105 aopPut(AOP(IC_RESULT(ic)), "d", 1);
4110 /* if it has an offset then we need to compute it */
4111 emitcode("ld", "hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
4112 emitcode("add", "hl,sp");
4115 emitcode("ld", "hl,#%s", sym->rname);
4117 aopPut(AOP(IC_RESULT(ic)), "l", 0);
4118 aopPut(AOP(IC_RESULT(ic)), "h", 1);
4120 freeAsmop(IC_RESULT(ic),NULL,ic);
4123 /*-----------------------------------------------------------------*/
4124 /* genAssign - generate code for assignment */
4125 /*-----------------------------------------------------------------*/
4126 static void genAssign (iCode *ic)
4128 operand *result, *right;
4130 unsigned long lit = 0L;
4132 result = IC_RESULT(ic);
4133 right = IC_RIGHT(ic) ;
4136 /* Dont bother assigning if they are the same */
4137 if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) {
4138 emitcode("", "; (operands are equal %u)", operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)));
4143 aopOp(right,ic,FALSE, FALSE);
4144 aopOp(result,ic,TRUE, FALSE);
4146 /* if they are the same registers */
4147 if (sameRegs(AOP(right),AOP(result))) {
4148 emitcode("", "; (registers are the same)");
4152 /* if the result is a bit */
4153 if (AOP_TYPE(result) == AOP_CRY) {
4158 size = AOP_SIZE(result);
4161 if(AOP_TYPE(right) == AOP_LIT)
4162 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
4163 if (isPair(AOP(result))) {
4164 fetchPair(getPairId(AOP(result)), AOP(right));
4166 else if((size > 1) &&
4167 (AOP_TYPE(result) != AOP_REG) &&
4168 (AOP_TYPE(right) == AOP_LIT) &&
4169 !IS_FLOAT(operandType(right)) &&
4171 bool fXored = FALSE;
4173 /* Work from the top down.
4174 Done this way so that we can use the cached copy of 0
4175 in A for a fast clear */
4177 if((unsigned int)((lit >> (offset*8)) & 0x0FFL)== 0) {
4178 if (!fXored && size>1) {
4179 emitcode("xor", "a,a");
4183 aopPut(AOP(result),"a",offset);
4186 aopPut(AOP(result), zero, offset);
4191 aopGet(AOP(right),offset,FALSE),
4196 else if (size == 2 && requiresHL(AOP(right)) && requiresHL(AOP(result)) && IS_GB) {
4197 /* Special case. Load into a and d, then load out. */
4198 MOVA(aopGet(AOP(right), 0, FALSE));
4199 emitcode("ld", "e,%s", aopGet(AOP(right), 1, FALSE));
4200 aopPut(AOP(result), "a", 0);
4201 aopPut(AOP(result), "e", 1);
4204 /* PENDING: do this check better */
4205 if (requiresHL(AOP(right)) && requiresHL(AOP(result))) {
4206 MOVA(aopGet(AOP(right), offset, FALSE));
4207 aopPut(AOP(result), "a", offset);
4211 aopGet(AOP(right),offset,FALSE),
4218 freeAsmop(right,NULL,ic);
4219 freeAsmop(result,NULL,ic);
4222 /*-----------------------------------------------------------------*/
4223 /* genJumpTab - genrates code for jump table */
4224 /*-----------------------------------------------------------------*/
4225 static void genJumpTab (iCode *ic)
4230 aopOp(IC_JTCOND(ic),ic,FALSE, FALSE);
4231 /* get the condition into accumulator */
4232 l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE);
4234 emitcode("push", "de");
4235 emitcode("ld", "e,%s", l);
4236 emit2("ld d,!zero");
4237 jtab = newiTempLabel(NULL);
4239 emit2("ld hl,!immed!tlabel", jtab->key+100);
4240 emitcode("add", "hl,de");
4241 emitcode("add", "hl,de");
4242 emitcode("add", "hl,de");
4243 freeAsmop(IC_JTCOND(ic),NULL,ic);
4245 emitcode("pop", "de");
4247 emitLabel(jtab->key+100);
4248 /* now generate the jump labels */
4249 for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
4250 jtab = setNextItem(IC_JTLABELS(ic)))
4251 emit2("jp !tlabel", jtab->key+100);
4254 /*-----------------------------------------------------------------*/
4255 /* genCast - gen code for casting */
4256 /*-----------------------------------------------------------------*/
4257 static void genCast (iCode *ic)
4259 operand *result = IC_RESULT(ic);
4260 link *ctype = operandType(IC_LEFT(ic));
4261 operand *right = IC_RIGHT(ic);
4264 /* if they are equivalent then do nothing */
4265 if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
4268 aopOp(right,ic,FALSE, FALSE);
4269 aopOp(result,ic,FALSE, FALSE);
4271 /* if the result is a bit */
4272 if (AOP_TYPE(result) == AOP_CRY) {
4276 /* if they are the same size : or less */
4277 if (AOP_SIZE(result) <= AOP_SIZE(right)) {
4279 /* if they are in the same place */
4280 if (sameRegs(AOP(right),AOP(result)))
4283 /* if they in different places then copy */
4284 size = AOP_SIZE(result);
4288 aopGet(AOP(right),offset,FALSE),
4295 /* PENDING: should be OK. */
4297 /* if the result is of type pointer */
4298 if (IS_PTR(ctype)) {
4303 /* so we now know that the size of destination is greater
4304 than the size of the source */
4305 /* we move to result for the size of source */
4306 size = AOP_SIZE(right);
4310 aopGet(AOP(right),offset,FALSE),
4315 /* now depending on the sign of the destination */
4316 size = AOP_SIZE(result) - AOP_SIZE(right);
4317 /* Unsigned or not an integral type - right fill with zeros */
4318 if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) {
4320 aopPut(AOP(result),zero,offset++);
4322 /* we need to extend the sign :{ */
4323 char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
4326 emitcode("", "; genCast: sign extend untested.");
4327 emitcode("rla", "");
4328 emitcode("sbc", "a,a");
4330 aopPut(AOP(result),"a",offset++);
4334 freeAsmop(right, NULL, ic);
4335 freeAsmop(result, NULL, ic);
4338 /*-----------------------------------------------------------------*/
4339 /* genReceive - generate code for a receive iCode */
4340 /*-----------------------------------------------------------------*/
4341 static void genReceive (iCode *ic)
4343 if (isOperandInFarSpace(IC_RESULT(ic)) &&
4344 ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
4345 IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
4349 aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
4351 assignResultValue(IC_RESULT(ic));
4354 freeAsmop(IC_RESULT(ic),NULL,ic);
4357 /*-----------------------------------------------------------------*/
4358 /* genZ80Code - generate code for Z80 based controllers */
4359 /*-----------------------------------------------------------------*/
4360 void genZ80Code (iCode *lic)
4367 _fReturn = _gbz80_return;
4368 _fTmp = _gbz80_return;
4371 _fReturn = _z80_return;
4372 _fTmp = _z80_return;
4374 tsprintf(zero, "!zero");
4376 lineHead = lineCurr = NULL;
4378 /* if debug information required */
4379 if (options.debug && currFunc) {
4380 cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
4382 if (IS_STATIC(currFunc->etype))
4383 emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name);
4385 emitcode("","G$%s$0$0 ==.",currFunc->name);
4388 /* stack pointer name */
4392 for (ic = lic ; ic ; ic = ic->next ) {
4394 if ( cln != ic->lineno ) {
4395 if ( options.debug ) {
4397 emitcode("","C$%s$%d$%d$%d ==.",
4398 ic->filename,ic->lineno,
4399 ic->level,ic->block);
4402 emitcode(";","%s %d",ic->filename,ic->lineno);
4405 /* if the result is marked as
4406 spilt and rematerializable or code for
4407 this has already been generated then
4409 if (resultRemat(ic) || ic->generated )
4412 /* depending on the operation */
4415 emitcode("", "; genNot");
4420 emitcode("", "; genCpl");
4425 emitcode("", "; genUminus");
4430 emitcode("", "; genIpush");
4435 /* IPOP happens only when trying to restore a
4436 spilt live range, if there is an ifx statement
4437 following this pop then the if statement might
4438 be using some of the registers being popped which
4439 would destory the contents of the register so
4440 we need to check for this condition and handle it */
4442 ic->next->op == IFX &&
4443 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) {
4444 emitcode("", "; genIfx");
4445 genIfx (ic->next,ic);
4448 emitcode("", "; genIpop");
4454 emitcode("", "; genCall");
4459 emitcode("", "; genPcall");
4464 emitcode("", "; genFunction");
4469 emitcode("", "; genEndFunction");
4470 genEndFunction (ic);
4474 emitcode("", "; genRet");
4479 emitcode("", "; genLabel");
4484 emitcode("", "; genGoto");
4489 emitcode("", "; genPlus");
4494 emitcode("", "; genMinus");
4499 emitcode("", "; genMult");
4504 emitcode("", "; genDiv");
4509 emitcode("", "; genMod");
4514 emitcode("", "; genCmpGt");
4515 genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));
4519 emitcode("", "; genCmpLt");
4520 genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
4527 /* note these two are xlated by algebraic equivalence
4528 during parsing SDCC.y */
4529 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
4530 "got '>=' or '<=' shouldn't have come here");
4534 emitcode("", "; genCmpEq");
4535 genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
4539 emitcode("", "; genAndOp");
4544 emitcode("", "; genOrOp");
4549 emitcode("", "; genXor");
4550 genXor (ic,ifxForOp(IC_RESULT(ic),ic));
4554 emitcode("", "; genOr");
4555 genOr (ic,ifxForOp(IC_RESULT(ic),ic));
4559 emitcode("", "; genAnd");
4560 genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
4564 emitcode("", "; genInline");
4569 emitcode("", "; genRRC");
4574 emitcode("", "; genRLC");
4579 emitcode("", "; genHBIT");
4583 emitcode("", "; genLeftShift");
4588 emitcode("", "; genRightShift");
4592 case GET_VALUE_AT_ADDRESS:
4593 emitcode("", "; genPointerGet");
4599 if (POINTER_SET(ic)) {
4600 emitcode("", "; genAssign (pointer)");
4604 emitcode("", "; genAssign");
4610 emitcode("", "; genIfx");
4615 emitcode("", "; genAddrOf");
4620 emitcode("", "; genJumpTab");
4625 emitcode("", "; genCast");
4630 emitcode("", "; genReceive");
4635 emitcode("", "; addSet");
4636 addSet(&sendSet,ic);
4641 /* piCode(ic,stdout); */
4647 /* now we are ready to call the
4648 peep hole optimizer */
4649 if (!options.nopeep)
4650 peepHole (&lineHead);
4652 /* now do the actual printing */
4653 printLine (lineHead,codeOutFile);