1 /*-------------------------------------------------------------------------
2 SDCCgen51.c - source file for code generation for 8051
4 Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998)
5 and - Jean-Louis VERN.jlvern@writeme.com (1999)
7 This program is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 In other words, you are welcome to use, share and improve this program.
22 You are forbidden to forbid anyone else to use, share and improve
23 what you give them. Help stamp out software-hoarding!
25 -------------------------------------------------------------------------*/
31 #include "SDCCglobl.h"
33 #ifdef HAVE_SYS_ISA_DEFS_H
34 #include <sys/isa_defs.h>
40 #include "SDCChasht.h"
43 #include "SDCCicode.h"
44 #include "SDCClabel.h"
45 #include "SDCCBBlock.h"
48 #include "SDCCcflow.h"
49 #include "SDCCdflow.h"
50 #include "SDCClrange.h"
53 #include "SDCCpeeph.h"
54 #include "SDCCglue.h" /* drdani Jan 30 2000 */
56 /* this is the down and dirty file with all kinds of kludgy & hacky
57 stuff. This is what it is all about CODE GENERATION for a specific MCU.
58 Some of the routines may be reusable, will have to see */
60 static char *zero = "#0x00";
61 static char *one = "#0x01";
63 static char *fReturn[] = {"l", "h", "e", "d" };
64 static char *accUse[] = {"a" };
70 extern int ptrRegReq ;
72 extern FILE *codeOutFile;
74 #define RESULTONSTACK(x) \
75 (IC_RESULT(x) && IC_RESULT(x)->aop && \
76 IC_RESULT(x)->aop->type == AOP_STK )
78 #define MOVA(x) if (strcmp(x,"a")) emitcode("ld","a,%s",x);
79 #define CLRC emitcode("xor","a,a");
81 #define LABEL_STR "%05d$"
83 lineNode *lineHead = NULL;
84 lineNode *lineCurr = NULL;
86 unsigned char SLMask[] = {0xFF ,0xFE, 0xFC, 0xF8, 0xF0,
87 0xE0, 0xC0, 0x80, 0x00};
88 unsigned char SRMask[] = {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
89 0x07, 0x03, 0x01, 0x00};
91 static int _lastStack = 0;
106 /*-----------------------------------------------------------------*/
107 /* emitcode - writes the code into a file : for now it is simple */
108 /*-----------------------------------------------------------------*/
109 void emitcode (const char *inst, const char *fmt, ...)
112 char lb[MAX_INLINEASM];
118 sprintf(lb,"%s\t",inst);
119 vsprintf(lb+(strlen(lb)),fmt,ap);
123 while (isspace(*lbp)) lbp++;
126 lineCurr = (lineCurr ?
127 connectLine(lineCurr,newLineNode(lb)) :
128 (lineHead = newLineNode(lb)));
129 lineCurr->isInline = inLine;
130 lineCurr->isDebug = debugLine;
134 const char *getPairName(asmop *aop)
136 if (aop->type == AOP_REG) {
137 switch (aop->aopu.aop_reg[0]->rIdx) {
149 else if (aop->type == AOP_STR) {
150 switch (*aop->aopu.aop_str[0]) {
166 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
167 bool isPair(asmop *aop)
169 if (aop->size == 2) {
170 if (aop->type == AOP_REG) {
171 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX)&&(aop->aopu.aop_reg[1]->rIdx == B_IDX)) {
174 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX)&&(aop->aopu.aop_reg[1]->rIdx == D_IDX)) {
177 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX)&&(aop->aopu.aop_reg[1]->rIdx == H_IDX)) {
181 if (aop->type == AOP_STR) {
182 if (!strcmp(aop->aopu.aop_str[0], "c")&&!strcmp(aop->aopu.aop_str[1], "b")) {
185 if (!strcmp(aop->aopu.aop_str[0], "e")&&!strcmp(aop->aopu.aop_str[1], "d")) {
188 if (!strcmp(aop->aopu.aop_str[0], "l")&&!strcmp(aop->aopu.aop_str[1], "h")) {
196 /** Push a register pair onto the stack */
197 void genPairPush(asmop *aop)
199 emitcode("push", "%s", getPairName(aop));
202 /*-----------------------------------------------------------------*/
203 /* newAsmop - creates a new asmOp */
204 /*-----------------------------------------------------------------*/
205 static asmop *newAsmop (short type)
209 ALLOC(aop,sizeof(asmop));
214 /*-----------------------------------------------------------------*/
215 /* aopForSym - for a true symbol */
216 /*-----------------------------------------------------------------*/
217 static asmop *aopForSym (iCode *ic,symbol *sym,bool result)
220 memmap *space= SPEC_OCLS(sym->etype);
222 /* if already has one */
226 /* Assign depending on the storage class */
227 if (sym->onStack || sym->iaccess) {
228 sym->aop = aop = newAsmop(AOP_STK);
229 aop->size = getSize(sym->type);
231 aop->aopu.aop_stk = sym->stack;
235 /* special case for a function */
236 if (IS_FUNC(sym->type)) {
237 sym->aop = aop = newAsmop(AOP_IMMD);
238 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(sym->rname)+1);
239 strcpy(aop->aopu.aop_immd,sym->rname);
244 /* only remaining is far space */
245 /* in which case DPTR gets the address */
246 sym->aop = aop = newAsmop(AOP_IY);
247 emitcode ("ld","iy,#%s", sym->rname);
248 aop->size = getSize(sym->type);
249 aop->aopu.aop_dir = sym->rname;
251 /* if it is in code space */
252 if (IN_CODESPACE(space))
258 /*-----------------------------------------------------------------*/
259 /* aopForRemat - rematerialzes an object */
260 /*-----------------------------------------------------------------*/
261 static asmop *aopForRemat (symbol *sym)
264 iCode *ic = sym->rematiCode;
265 asmop *aop = newAsmop(AOP_IMMD);
268 /* if plus or minus print the right hand side */
269 if (ic->op == '+' || ic->op == '-') {
270 sprintf(s,"0x%04x %c ",(int) operandLitValue(IC_RIGHT(ic)),
273 ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode;
276 /* we reached the end */
277 sprintf(s,"%s",OP_SYMBOL(IC_LEFT(ic))->rname);
281 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(buffer)+1);
282 strcpy(aop->aopu.aop_immd,buffer);
286 /*-----------------------------------------------------------------*/
287 /* regsInCommon - two operands have some registers in common */
288 /*-----------------------------------------------------------------*/
289 bool regsInCommon (operand *op1, operand *op2)
294 /* if they have registers in common */
295 if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
298 sym1 = OP_SYMBOL(op1);
299 sym2 = OP_SYMBOL(op2);
301 if (sym1->nRegs == 0 || sym2->nRegs == 0)
304 for (i = 0 ; i < sym1->nRegs ; i++) {
309 for (j = 0 ; j < sym2->nRegs ;j++ ) {
313 if (sym2->regs[j] == sym1->regs[i])
321 /*-----------------------------------------------------------------*/
322 /* operandsEqu - equivalent */
323 /*-----------------------------------------------------------------*/
324 bool operandsEqu ( operand *op1, operand *op2)
328 /* if they not symbols */
329 if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
332 sym1 = OP_SYMBOL(op1);
333 sym2 = OP_SYMBOL(op2);
335 /* if both are itemps & one is spilt
336 and the other is not then false */
337 if (IS_ITEMP(op1) && IS_ITEMP(op2) &&
338 sym1->isspilt != sym2->isspilt )
341 /* if they are the same */
345 if (strcmp(sym1->rname,sym2->rname) == 0)
349 /* if left is a tmp & right is not */
353 (sym1->usl.spillLoc == sym2))
359 (sym2->usl.spillLoc == sym1))
365 /*-----------------------------------------------------------------*/
366 /* sameRegs - two asmops have the same registers */
367 /*-----------------------------------------------------------------*/
368 bool sameRegs (asmop *aop1, asmop *aop2 )
375 if (aop1->type != AOP_REG ||
376 aop2->type != AOP_REG )
379 if (aop1->size != aop2->size)
382 for (i = 0 ; i < aop1->size ; i++ )
383 if (aop1->aopu.aop_reg[i] !=
384 aop2->aopu.aop_reg[i] )
390 /*-----------------------------------------------------------------*/
391 /* aopOp - allocates an asmop for an operand : */
392 /*-----------------------------------------------------------------*/
393 static void aopOp (operand *op, iCode *ic, bool result)
402 /* if this a literal */
403 if (IS_OP_LITERAL(op)) {
404 op->aop = aop = newAsmop(AOP_LIT);
405 aop->aopu.aop_lit = op->operand.valOperand;
406 aop->size = getSize(operandType(op));
410 /* if already has a asmop then continue */
414 /* if the underlying symbol has a aop */
415 if (IS_SYMOP(op) && OP_SYMBOL(op)->aop) {
416 op->aop = OP_SYMBOL(op)->aop;
420 /* if this is a true symbol */
421 if (IS_TRUE_SYMOP(op)) {
422 op->aop = aopForSym(ic,OP_SYMBOL(op),result);
426 /* this is a temporary : this has
432 e) can be a return use only */
436 /* if the type is a conditional */
437 if (sym->regType == REG_CND) {
438 aop = op->aop = sym->aop = newAsmop(AOP_CRY);
443 /* if it is spilt then two situations
445 b) has a spill location */
446 if (sym->isspilt || sym->nRegs == 0) {
447 /* rematerialize it NOW */
449 sym->aop = op->aop = aop =
451 aop->size = getSize(sym->type);
457 aop = op->aop = sym->aop = newAsmop(AOP_ACC);
458 aop->size = getSize(sym->type);
459 for ( i = 0 ; i < 2 ; i++ )
460 aop->aopu.aop_str[i] = accUse[i];
466 aop = op->aop = sym->aop = newAsmop(AOP_STR);
467 aop->size = getSize(sym->type);
468 for ( i = 0 ; i < 4 ; i++ )
469 aop->aopu.aop_str[i] = fReturn[i];
473 /* else spill location */
474 sym->aop = op->aop = aop =
475 aopForSym(ic,sym->usl.spillLoc,result);
476 aop->size = getSize(sym->type);
480 /* must be in a register */
481 sym->aop = op->aop = aop = newAsmop(AOP_REG);
482 aop->size = sym->nRegs;
483 for ( i = 0 ; i < sym->nRegs ;i++)
484 aop->aopu.aop_reg[i] = sym->regs[i];
487 /*-----------------------------------------------------------------*/
488 /* freeAsmop - free up the asmop given to an operand */
489 /*----------------------------------------------------------------*/
490 static void freeAsmop (operand *op, asmop *aaop, iCode *ic)
513 /* all other cases just dealloc */
517 OP_SYMBOL(op)->aop = NULL;
518 /* if the symbol has a spill */
520 SPIL_LOC(op)->aop = NULL;
525 char *aopGetWord(asmop *aop, int offset)
530 assert(aop->size == 2);
533 /* depending on type */
536 sprintf (s,"#%s",aop->aopu.aop_immd);
537 ALLOC_ATOMIC(rs,strlen(s)+1);
542 value * val = aop->aopu.aop_lit;
543 /* if it is a float then it gets tricky */
544 /* otherwise it is fairly simple */
545 if (!IS_FLOAT(val->type)) {
546 unsigned long v = floatFromVal(val);
548 sprintf(buffer,"#0x%04lx", v);
549 ALLOC_ATOMIC(rs,strlen(buffer)+1);
550 return strcpy (rs,buffer);
559 /*-----------------------------------------------------------------*/
560 /* aopGet - for fetching value of the aop */
561 /*-----------------------------------------------------------------*/
562 static char *aopGet (asmop *aop, int offset, bool bit16)
567 /* offset is greater than size then zero */
568 if (offset > (aop->size - 1) &&
569 aop->type != AOP_LIT)
572 /* depending on type */
576 sprintf (s,"#%s",aop->aopu.aop_immd);
586 ALLOC_ATOMIC(rs,strlen(s)+1);
592 emitcode("ld", "a,(%s+%d)", aop->aopu.aop_dir, offset);
594 ALLOC_ATOMIC(rs,strlen(s)+1);
599 return aop->aopu.aop_reg[offset]->name;
602 sprintf(s,"%d(iy)", offset);
603 ALLOC_ATOMIC(rs,strlen(s)+1);
608 sprintf(s,"%d(ix) ; %u", aop->aopu.aop_stk+offset, offset);
609 ALLOC_ATOMIC(rs,strlen(s)+1);
623 return aopLiteral (aop->aopu.aop_lit,offset);
627 return aop->aopu.aop_str[offset];
630 fprintf(stderr, "Type %u\n", aop->type);
632 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
633 "aopget got unsupported aop->type");
637 bool isRegString(char *s)
639 if (!strcmp(s, "b") ||
650 bool isConstant(char *s)
655 bool canAssignToPtr(char *s)
664 /*-----------------------------------------------------------------*/
665 /* aopPut - puts a string for a aop */
666 /*-----------------------------------------------------------------*/
667 static void aopPut (asmop *aop, char *s, int offset)
671 if (aop->size && offset > ( aop->size - 1)) {
672 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
673 "aopPut got offset > aop->size");
677 /* will assign value to value */
678 /* depending on where it is ofcourse */
683 emitcode("ld", "a,%s", s);
684 emitcode("ld", "(%s+%d),a", d, offset);
688 /* Dont bother if it's a ld x,x */
689 if (strcmp(aop->aopu.aop_reg[offset]->name,s) != 0) {
690 emitcode("ld","%s,%s",
691 aop->aopu.aop_reg[offset]->name,s);
696 if (!canAssignToPtr(s)) {
697 emitcode("ld", "a,%s", s);
698 emitcode("ld", "%d(iy),a", offset);
701 emitcode("ld", "%d(iy),%s", offset, s);
705 if (!canAssignToPtr(s)) {
706 emitcode("ld", "a,%s", s);
707 emitcode("ld", "%d(ix),a", aop->aopu.aop_stk+offset);
710 emitcode("ld", "%d(ix),%s", aop->aopu.aop_stk+offset, s);
714 /* if bit variable */
715 if (!aop->aopu.aop_dir) {
716 emitcode("ld", "a,#0");
719 /* In bit space but not in C - cant happen */
726 if (strcmp(aop->aopu.aop_str[offset],s)) {
727 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
733 if (!offset && (strcmp(s,"acc") == 0))
736 emitcode("", "; Error aopPut AOP_ACC");
739 if (strcmp(aop->aopu.aop_str[offset],s))
740 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
745 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
746 "aopPut got unsupported aop->type");
751 #define AOP(op) op->aop
752 #define AOP_TYPE(op) AOP(op)->type
753 #define AOP_SIZE(op) AOP(op)->size
754 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
756 /*-----------------------------------------------------------------*/
757 /* getDataSize - get the operand data size */
758 /*-----------------------------------------------------------------*/
759 int getDataSize(operand *op)
770 /*-----------------------------------------------------------------*/
771 /* movLeft2Result - move byte from left to result */
772 /*-----------------------------------------------------------------*/
773 static void movLeft2Result (operand *left, int offl,
774 operand *result, int offr, int sign)
777 if(!sameRegs(AOP(left),AOP(result)) || (offl != offr)){
778 l = aopGet(AOP(left),offl,FALSE);
781 aopPut(AOP(result),l,offr);
790 /** Put Acc into a register set
792 void outAcc(operand *result)
795 size = getDataSize(result);
797 aopPut(AOP(result),"a",0);
800 /* unsigned or positive */
802 aopPut(AOP(result),zero,offset++);
807 /** Take the value in carry and put it into a register
809 void outBitC(operand *result)
811 /* if the result is bit */
812 if (AOP_TYPE(result) == AOP_CRY) {
813 emitcode("", "; Note: outBitC form 1");
814 aopPut(AOP(result),"blah",0);
817 emitcode("ld", "a,#0");
823 /*-----------------------------------------------------------------*/
824 /* toBoolean - emit code for orl a,operator(sizeop) */
825 /*-----------------------------------------------------------------*/
826 void toBoolean(operand *oper)
828 int size = AOP_SIZE(oper);
831 emitcode("ld", "a,%s", aopGet(AOP(oper), offset++, FALSE));
834 emitcode("or","a,%s",aopGet(AOP(oper),offset++,FALSE));
838 emitcode("or","a,%s",aopGet(AOP(oper),0,FALSE));
842 /*-----------------------------------------------------------------*/
843 /* genNot - generate code for ! operation */
844 /*-----------------------------------------------------------------*/
845 static void genNot (iCode *ic)
847 link *optype = operandType(IC_LEFT(ic));
849 /* assign asmOps to operand & result */
850 aopOp (IC_LEFT(ic),ic,FALSE);
851 aopOp (IC_RESULT(ic),ic,TRUE);
853 /* if in bit space then a special case */
854 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) {
858 /* if type float then do float */
859 if (IS_FLOAT(optype)) {
863 toBoolean(IC_LEFT(ic));
868 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
869 emitcode("sub", "a,#0x01");
870 outBitC(IC_RESULT(ic));
872 /* release the aops */
873 freeAsmop(IC_LEFT(ic),NULL,ic);
874 freeAsmop(IC_RESULT(ic),NULL,ic);
877 /*-----------------------------------------------------------------*/
878 /* genCpl - generate code for complement */
879 /*-----------------------------------------------------------------*/
880 static void genCpl (iCode *ic)
886 /* assign asmOps to operand & result */
887 aopOp (IC_LEFT(ic),ic,FALSE);
888 aopOp (IC_RESULT(ic),ic,TRUE);
890 /* if both are in bit space then
892 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
893 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
897 size = AOP_SIZE(IC_RESULT(ic));
899 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
902 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
905 /* release the aops */
906 freeAsmop(IC_LEFT(ic),NULL,ic);
907 freeAsmop(IC_RESULT(ic),NULL,ic);
910 /*-----------------------------------------------------------------*/
911 /* genUminus - unary minus code generation */
912 /*-----------------------------------------------------------------*/
913 static void genUminus (iCode *ic)
919 /*-----------------------------------------------------------------*/
920 /* assignResultValue - */
921 /*-----------------------------------------------------------------*/
922 void assignResultValue(operand * oper)
925 int size = AOP_SIZE(oper);
927 aopPut(AOP(oper),fReturn[offset],offset);
932 /*-----------------------------------------------------------------*/
933 /* genIpush - genrate code for pushing this gets a little complex */
934 /*-----------------------------------------------------------------*/
935 static void genIpush (iCode *ic)
937 int size, offset = 0 ;
941 /* if this is not a parm push : ie. it is spill push
942 and spill push is always done on the local stack */
944 /* and the item is spilt then do nothing */
945 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
948 aopOp(IC_LEFT(ic),ic,FALSE);
949 size = AOP_SIZE(IC_LEFT(ic));
950 /* push it on the stack */
951 if (isPair(AOP(IC_LEFT(ic)))) {
952 emitcode("push", getPairName(AOP(IC_LEFT(ic))));
957 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
958 /* Simple for now - load into A and PUSH AF */
959 emitcode("ld", "a,%s", l);
960 emitcode("push", "af");
961 emitcode("inc", "sp");
967 /* Hmmm... what about saving the currently used registers
970 /* then do the push */
971 aopOp(IC_LEFT(ic),ic,FALSE);
973 size = AOP_SIZE(IC_LEFT(ic));
975 if (isPair(AOP(IC_LEFT(ic)))) {
976 emitcode("push", "%s", getPairName(AOP(IC_LEFT(ic))));
980 char *s = aopGetWord(AOP(IC_LEFT(ic)), 0);
982 emitcode("ld", "hl,%s", s);
983 emitcode("push", "hl");
989 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
990 emitcode("ld", "a,%s", l);
991 emitcode("push", "af");
992 emitcode("inc", "sp");
996 freeAsmop(IC_LEFT(ic),NULL,ic);
999 /*-----------------------------------------------------------------*/
1000 /* genIpop - recover the registers: can happen only for spilling */
1001 /*-----------------------------------------------------------------*/
1002 static void genIpop (iCode *ic)
1007 /* if the temp was not pushed then */
1008 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1011 aopOp(IC_LEFT(ic),ic,FALSE);
1012 size = AOP_SIZE(IC_LEFT(ic));
1014 if (isPair(AOP(IC_LEFT(ic)))) {
1015 emitcode("pop", getPairName(AOP(IC_LEFT(ic))));
1019 emitcode("dec", "sp");
1020 emitcode("pop", "hl");
1021 aopPut(AOP(IC_LEFT(ic)), "l", offset--);
1025 freeAsmop(IC_LEFT(ic),NULL,ic);
1028 /** Emit the code for a call statement
1030 static void emitCall (iCode *ic, bool ispcall)
1032 /* if caller saves & we have not saved then */
1033 if (!ic->regsSaved) {
1037 /* if send set is not empty then assign */
1041 for (sic = setFirstItem(sendSet) ; sic ;
1042 sic = setNextItem(sendSet)) {
1043 int size, offset = 0;
1044 aopOp(IC_LEFT(sic),sic,FALSE);
1045 size = AOP_SIZE(IC_LEFT(sic));
1047 char *l = aopGet(AOP(IC_LEFT(sic)),offset,
1049 if (strcmp(l,fReturn[offset]))
1050 emitcode("ld","%s,%s",
1055 freeAsmop (IC_LEFT(sic),NULL,sic);
1061 symbol *rlbl = newiTempLabel(NULL);
1063 emitcode("ld", "hl,#" LABEL_STR, (rlbl->key+100));
1064 emitcode("push", "hl");
1066 aopOp(IC_LEFT(ic),ic,FALSE);
1067 emitcode("ld", "l,%s", aopGet(AOP(IC_LEFT(ic)), 0,FALSE));
1068 emitcode("ld", "h,%s", aopGet(AOP(IC_LEFT(ic)), 1,FALSE));
1069 freeAsmop(IC_LEFT(ic),NULL,ic);
1071 emitcode("jp", "(hl)");
1072 emitcode("","%05d$:",(rlbl->key+100));
1076 emitcode("call", "%s", (OP_SYMBOL(IC_LEFT(ic))->rname[0] ?
1077 OP_SYMBOL(IC_LEFT(ic))->rname :
1078 OP_SYMBOL(IC_LEFT(ic))->name));
1081 /* if we need assign a result value */
1082 if ((IS_ITEMP(IC_RESULT(ic)) &&
1083 (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
1084 OP_SYMBOL(IC_RESULT(ic))->spildir )) ||
1085 IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
1088 aopOp(IC_RESULT(ic),ic,FALSE);
1091 assignResultValue(IC_RESULT(ic));
1093 freeAsmop(IC_RESULT(ic),NULL, ic);
1096 /* adjust the stack for parameters if required */
1097 if (IC_LEFT(ic)->parmBytes) {
1098 int i = IC_LEFT(ic)->parmBytes;
1099 /* PENDING: do better */
1101 emitcode("pop", "hl");
1105 emitcode("inc", "sp");
1110 /*-----------------------------------------------------------------*/
1111 /* genCall - generates a call statement */
1112 /*-----------------------------------------------------------------*/
1113 static void genCall (iCode *ic)
1115 emitCall(ic, FALSE);
1118 /*-----------------------------------------------------------------*/
1119 /* genPcall - generates a call by pointer statement */
1120 /*-----------------------------------------------------------------*/
1121 static void genPcall (iCode *ic)
1126 /*-----------------------------------------------------------------*/
1127 /* resultRemat - result is rematerializable */
1128 /*-----------------------------------------------------------------*/
1129 static int resultRemat (iCode *ic)
1131 if (SKIP_IC(ic) || ic->op == IFX)
1134 if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
1135 symbol *sym = OP_SYMBOL(IC_RESULT(ic));
1136 if (sym->remat && !POINTER_SET(ic))
1143 /*-----------------------------------------------------------------*/
1144 /* genFunction - generated code for function entry */
1145 /*-----------------------------------------------------------------*/
1146 static void genFunction (iCode *ic)
1152 /* create the function header */
1153 emitcode(";","-----------------------------------------");
1154 emitcode(";"," function %s",(sym = OP_SYMBOL(IC_LEFT(ic)))->name);
1155 emitcode(";","-----------------------------------------");
1157 emitcode("","%s:",sym->rname);
1158 fetype = getSpec(operandType(IC_LEFT(ic)));
1160 /* if critical function then turn interrupts off */
1161 if (SPEC_CRTCL(fetype))
1164 /* if this is an interrupt service routine then
1165 save acc, b, dpl, dph */
1166 if (IS_ISR(sym->etype)) {
1167 emitcode("push", "af");
1168 emitcode("push", "bc");
1169 emitcode("push", "de");
1170 emitcode("push", "hl");
1172 /* PENDING: callee-save etc */
1174 /* adjust the stack for the function */
1175 emitcode("push", "de");
1176 emitcode("push", "bc");
1177 emitcode("push", "ix");
1178 emitcode("ld", "ix,#0");
1179 emitcode("add", "ix,sp");
1181 _lastStack = sym->stack;
1184 emitcode("ld", "hl,#-%d", sym->stack);
1185 emitcode("add", "hl,sp");
1186 emitcode("ld", "sp,hl");
1190 /*-----------------------------------------------------------------*/
1191 /* genEndFunction - generates epilogue for functions */
1192 /*-----------------------------------------------------------------*/
1193 static void genEndFunction (iCode *ic)
1195 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1197 if (IS_ISR(sym->etype)) {
1201 if (SPEC_CRTCL(sym->etype))
1204 /* PENDING: calleeSave */
1206 /* if debug then send end of function */
1207 if (options.debug && currFunc) {
1209 emitcode("","C$%s$%d$%d$%d ==.",
1210 ic->filename,currFunc->lastLine,
1211 ic->level,ic->block);
1212 if (IS_STATIC(currFunc->etype))
1213 emitcode("","XF%s$%s$0$0 ==.",moduleName,currFunc->name);
1215 emitcode("","XG$%s$0$0 ==.",currFunc->name);
1218 emitcode("ld", "sp,ix");
1219 emitcode("pop", "ix");
1220 emitcode("pop", "bc");
1221 emitcode("pop", "de");
1222 emitcode("ret", "");
1227 /*-----------------------------------------------------------------*/
1228 /* genRet - generate code for return statement */
1229 /*-----------------------------------------------------------------*/
1230 static void genRet (iCode *ic)
1233 /* Errk. This is a hack until I can figure out how
1234 to cause dehl to spill on a call */
1235 int size,offset = 0;
1237 /* if we have no return value then
1238 just generate the "ret" */
1242 /* we have something to return then
1243 move the return value into place */
1244 aopOp(IC_LEFT(ic),ic,FALSE);
1245 size = AOP_SIZE(IC_LEFT(ic));
1247 if ((size == 2) && ((l = aopGetWord(AOP(IC_LEFT(ic)), 0)))) {
1248 emitcode("ld", "hl,%s", l);
1252 l = aopGet(AOP(IC_LEFT(ic)),offset,
1254 if (strcmp(fReturn[offset],l))
1255 emitcode("ld","%s,%s",fReturn[offset++],l);
1258 freeAsmop (IC_LEFT(ic),NULL,ic);
1261 /* generate a jump to the return label
1262 if the next is not the return statement */
1263 if (!(ic->next && ic->next->op == LABEL &&
1264 IC_LABEL(ic->next) == returnLabel))
1266 emitcode("jp", LABEL_STR ,(returnLabel->key+100));
1269 /*-----------------------------------------------------------------*/
1270 /* genLabel - generates a label */
1271 /*-----------------------------------------------------------------*/
1272 static void genLabel (iCode *ic)
1274 /* special case never generate */
1275 if (IC_LABEL(ic) == entryLabel)
1278 emitcode("", LABEL_STR ":",(IC_LABEL(ic)->key+100));
1281 /*-----------------------------------------------------------------*/
1282 /* genGoto - generates a ljmp */
1283 /*-----------------------------------------------------------------*/
1284 static void genGoto (iCode *ic)
1286 emitcode ("jp", LABEL_STR ,(IC_LABEL(ic)->key+100));
1289 /*-----------------------------------------------------------------*/
1290 /* genPlusIncr :- does addition with increment if possible */
1291 /*-----------------------------------------------------------------*/
1292 static bool genPlusIncr (iCode *ic)
1294 unsigned int icount ;
1295 unsigned int size = getDataSize(IC_RESULT(ic));
1297 /* will try to generate an increment */
1298 /* if the right side is not a literal
1300 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1303 /* if the literal value of the right hand side
1304 is greater than 4 then it is not worth it */
1305 if ((icount = floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 4)
1309 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1310 isPair(AOP(IC_RESULT(ic)))) {
1312 emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
1316 /* if increment 16 bits in register */
1317 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1320 symbol *tlbl = newiTempLabel(NULL);
1321 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
1322 emitcode("jp", "nz," LABEL_STR ,tlbl->key+100);
1324 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
1328 emitcode("", LABEL_STR ":",tlbl->key+100);
1332 /* If result is a pair */
1333 if (isPair(AOP(IC_RESULT(ic)))) {
1334 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
1335 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
1337 emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
1341 /* if the sizes are greater than 1 then we cannot */
1342 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
1343 AOP_SIZE(IC_LEFT(ic)) > 1 )
1346 /* we can if the aops of the left & result match or
1347 if they are in registers and the registers are the
1349 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
1351 emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0, FALSE));
1359 /*-----------------------------------------------------------------*/
1360 /* outBitAcc - output a bit in acc */
1361 /*-----------------------------------------------------------------*/
1362 void outBitAcc(operand *result)
1364 symbol *tlbl = newiTempLabel(NULL);
1365 /* if the result is a bit */
1366 if (AOP_TYPE(result) == AOP_CRY){
1370 emitcode("jp","z," LABEL_STR ,tlbl->key+100);
1371 emitcode("ld","a,%s",one);
1372 emitcode("", LABEL_STR ":",tlbl->key+100);
1377 /*-----------------------------------------------------------------*/
1378 /* genPlus - generates code for addition */
1379 /*-----------------------------------------------------------------*/
1380 static void genPlus (iCode *ic)
1382 int size, offset = 0;
1384 /* special cases :- */
1386 aopOp (IC_LEFT(ic),ic,FALSE);
1387 aopOp (IC_RIGHT(ic),ic,FALSE);
1388 aopOp (IC_RESULT(ic),ic,TRUE);
1390 /* Swap the left and right operands if:
1392 if literal, literal on the right or
1393 if left requires ACC or right is already
1396 if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
1397 (AOP_NEEDSACC(IC_LEFT(ic))) ||
1398 AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
1399 operand *t = IC_RIGHT(ic);
1400 IC_RIGHT(ic) = IC_LEFT(ic);
1404 /* if both left & right are in bit
1406 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1407 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
1412 /* if left in bit space & right literal */
1413 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1414 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
1415 /* Can happen I guess */
1419 /* if I can do an increment instead
1420 of add then GOOD for ME */
1421 if (genPlusIncr (ic) == TRUE)
1424 size = getDataSize(IC_RESULT(ic));
1427 if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
1428 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1430 emitcode("add","a,%s",
1431 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1433 emitcode("adc","a,%s",
1434 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1436 MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1438 emitcode("add","a,%s",
1439 aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1441 emitcode("adc","a,%s",
1442 aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1444 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1447 /* Some kind of pointer arith. */
1448 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
1449 AOP_SIZE(IC_LEFT(ic)) == 3 &&
1450 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
1453 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
1454 AOP_SIZE(IC_RIGHT(ic)) == 3 &&
1455 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
1460 freeAsmop(IC_LEFT(ic),NULL,ic);
1461 freeAsmop(IC_RIGHT(ic),NULL,ic);
1462 freeAsmop(IC_RESULT(ic),NULL,ic);
1466 /*-----------------------------------------------------------------*/
1467 /* genMinusDec :- does subtraction with deccrement if possible */
1468 /*-----------------------------------------------------------------*/
1469 static bool genMinusDec (iCode *ic)
1471 unsigned int icount ;
1472 unsigned int size = getDataSize(IC_RESULT(ic));
1474 /* will try to generate an increment */
1475 /* if the right side is not a literal we cannot */
1476 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1479 /* if the literal value of the right hand side
1480 is greater than 4 then it is not worth it */
1481 if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
1484 size = getDataSize(IC_RESULT(ic));
1485 /* if decrement 16 bits in register */
1486 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1487 (size > 1) && isPair(AOP(IC_RESULT(ic)))) {
1489 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
1493 /* If result is a pair */
1494 if (isPair(AOP(IC_RESULT(ic)))) {
1495 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
1496 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
1498 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
1502 /* if the sizes are greater than 1 then we cannot */
1503 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
1504 AOP_SIZE(IC_LEFT(ic)) > 1 )
1507 /* we can if the aops of the left & result match or if they are in
1508 registers and the registers are the same */
1509 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
1511 emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE));
1518 /*-----------------------------------------------------------------*/
1519 /* genMinus - generates code for subtraction */
1520 /*-----------------------------------------------------------------*/
1521 static void genMinus (iCode *ic)
1523 int size, offset = 0;
1524 unsigned long lit = 0L;
1526 aopOp (IC_LEFT(ic),ic,FALSE);
1527 aopOp (IC_RIGHT(ic),ic,FALSE);
1528 aopOp (IC_RESULT(ic),ic,TRUE);
1530 /* special cases :- */
1531 /* if both left & right are in bit space */
1532 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1533 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
1538 /* if I can do an decrement instead of subtract then GOOD for ME */
1539 if (genMinusDec (ic) == TRUE)
1542 size = getDataSize(IC_RESULT(ic));
1544 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
1548 lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
1553 /* if literal, add a,#-lit, else normal subb */
1555 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1556 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1557 emitcode("sbc","a,%s",
1558 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1560 /* first add without previous c */
1562 emitcode("add","a,#0x%02x",
1563 (unsigned int)(lit & 0x0FFL));
1565 emitcode("adc","a,#0x%02x",
1566 (unsigned int)((lit >> (offset*8)) & 0x0FFL));
1568 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1571 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
1572 AOP_SIZE(IC_LEFT(ic)) == 3 &&
1573 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
1577 freeAsmop(IC_LEFT(ic),NULL,ic);
1578 freeAsmop(IC_RIGHT(ic),NULL,ic);
1579 freeAsmop(IC_RESULT(ic),NULL,ic);
1582 /*-----------------------------------------------------------------*/
1583 /* genMult - generates code for multiplication */
1584 /*-----------------------------------------------------------------*/
1585 static void genMult (iCode *ic)
1587 /* Shouldn't occur - all done through function calls */
1591 /*-----------------------------------------------------------------*/
1592 /* genDiv - generates code for division */
1593 /*-----------------------------------------------------------------*/
1594 static void genDiv (iCode *ic)
1596 /* Shouldn't occur - all done through function calls */
1600 /*-----------------------------------------------------------------*/
1601 /* genMod - generates code for division */
1602 /*-----------------------------------------------------------------*/
1603 static void genMod (iCode *ic)
1605 /* Shouldn't occur - all done through function calls */
1609 /*-----------------------------------------------------------------*/
1610 /* genIfxJump :- will create a jump depending on the ifx */
1611 /*-----------------------------------------------------------------*/
1612 static void genIfxJump (iCode *ic, char *jval)
1617 /* if true label then we jump if condition
1619 if ( IC_TRUE(ic) ) {
1621 if (!strcmp(jval, "a")) {
1624 else if (!strcmp(jval, "c")) {
1628 /* The buffer contains the bit on A that we should test */
1633 /* false label is present */
1634 jlbl = IC_FALSE(ic) ;
1635 if (!strcmp(jval, "a")) {
1638 else if (!strcmp(jval, "c")) {
1642 /* The buffer contains the bit on A that we should test */
1646 /* Z80 can do a conditional long jump */
1647 if (!strcmp(jval, "a")) {
1648 emitcode("or", "a,a");
1650 else if (!strcmp(jval, "c")) {
1653 emitcode("bit", "%s,a", jval);
1655 emitcode("jp", "%s," LABEL_STR , inst, jlbl->key+100);
1657 /* mark the icode as generated */
1661 /** Generic compare for > or <
1663 static void genCmp (operand *left,operand *right,
1664 operand *result, iCode *ifx, int sign)
1666 int size, offset = 0 ;
1667 unsigned long lit = 0L;
1669 /* if left & right are bit variables */
1670 if (AOP_TYPE(left) == AOP_CRY &&
1671 AOP_TYPE(right) == AOP_CRY ) {
1672 /* Cant happen on the Z80 */
1675 /* subtract right from left if at the
1676 end the carry flag is set then we know that
1677 left is greater than right */
1678 size = max(AOP_SIZE(left),AOP_SIZE(right));
1680 /* if unsigned char cmp with lit, just compare */
1681 if((size == 1) && !sign &&
1682 (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
1683 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
1684 emitcode("cp", "%s", aopGet(AOP(right), offset, FALSE));
1687 if(AOP_TYPE(right) == AOP_LIT) {
1688 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
1689 /* optimize if(x < 0) or if(x >= 0) */
1692 /* No sign so it's always false */
1696 /* Just load in the top most bit */
1697 MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE));
1698 if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx) {
1700 genIfxJump (ifx,"acc.7");
1704 emitcode("rlc","a");
1710 /* Do a long subtract */
1711 MOVA(aopGet(AOP(left),offset,FALSE));
1712 if (sign && size == 0) {
1713 /* Case where it's signed and we've hit the end */
1716 /* Subtract through, propagating the carry */
1718 emitcode("sub","a,%s",aopGet(AOP(right),offset++,FALSE));
1721 emitcode("sbc","a,%s",aopGet(AOP(right),offset++,FALSE));
1728 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
1731 /* if the result is used in the next
1732 ifx conditional branch then generate
1733 code a little differently */
1735 genIfxJump (ifx,"c");
1738 /* leave the result in acc */
1742 /*-----------------------------------------------------------------*/
1743 /* genCmpGt :- greater than comparison */
1744 /*-----------------------------------------------------------------*/
1745 static void genCmpGt (iCode *ic, iCode *ifx)
1747 operand *left, *right, *result;
1748 link *letype , *retype;
1752 right= IC_RIGHT(ic);
1753 result = IC_RESULT(ic);
1755 letype = getSpec(operandType(left));
1756 retype =getSpec(operandType(right));
1757 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
1758 /* assign the amsops */
1759 aopOp (left,ic,FALSE);
1760 aopOp (right,ic,FALSE);
1761 aopOp (result,ic,TRUE);
1763 genCmp(right, left, result, ifx, sign);
1765 freeAsmop(left,NULL,ic);
1766 freeAsmop(right,NULL,ic);
1767 freeAsmop(result,NULL,ic);
1770 /*-----------------------------------------------------------------*/
1771 /* genCmpLt - less than comparisons */
1772 /*-----------------------------------------------------------------*/
1773 static void genCmpLt (iCode *ic, iCode *ifx)
1775 operand *left, *right, *result;
1776 link *letype , *retype;
1780 right= IC_RIGHT(ic);
1781 result = IC_RESULT(ic);
1783 letype = getSpec(operandType(left));
1784 retype =getSpec(operandType(right));
1785 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
1787 /* assign the amsops */
1788 aopOp (left,ic,FALSE);
1789 aopOp (right,ic,FALSE);
1790 aopOp (result,ic,TRUE);
1792 genCmp(left, right, result, ifx, sign);
1794 freeAsmop(left,NULL,ic);
1795 freeAsmop(right,NULL,ic);
1796 freeAsmop(result,NULL,ic);
1799 /*-----------------------------------------------------------------*/
1800 /* gencjneshort - compare and jump if not equal */
1801 /*-----------------------------------------------------------------*/
1802 static void gencjneshort(operand *left, operand *right, symbol *lbl)
1804 int size = max(AOP_SIZE(left),AOP_SIZE(right));
1806 unsigned long lit = 0L;
1808 /* Swap the left and right if it makes the computation easier */
1809 if (AOP_TYPE(left) == AOP_LIT) {
1815 if(AOP_TYPE(right) == AOP_LIT)
1816 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
1818 /* if the right side is a literal then anything goes */
1819 if (AOP_TYPE(right) == AOP_LIT &&
1820 AOP_TYPE(left) != AOP_DIR ) {
1822 emitcode("ld", "a,%s", aopGet(AOP(left),offset,FALSE));
1823 emitcode("cp", "a,%s", aopGet(AOP(right),offset,FALSE));
1824 emitcode("jp", "nz," LABEL_STR , lbl->key+100);
1828 /* if the right side is in a register or in direct space or
1829 if the left is a pointer register & right is not */
1830 else if (AOP_TYPE(right) == AOP_REG ||
1831 AOP_TYPE(right) == AOP_DIR ||
1832 (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT)) {
1834 MOVA(aopGet(AOP(left),offset,FALSE));
1835 if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
1836 ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
1838 emitcode("jp","nz," LABEL_STR ,lbl->key+100);
1840 emitcode("cp", "%s", aopGet(AOP(right),offset,FALSE));
1841 emitcode("jp", "nz," LABEL_STR , lbl->key+100);
1850 /*-----------------------------------------------------------------*/
1851 /* gencjne - compare and jump if not equal */
1852 /*-----------------------------------------------------------------*/
1853 static void gencjne(operand *left, operand *right, symbol *lbl)
1855 symbol *tlbl = newiTempLabel(NULL);
1857 gencjneshort(left, right, lbl);
1860 emitcode("ld","a,%s",one);
1861 emitcode("jp", LABEL_STR ,tlbl->key+100);
1862 emitcode("", LABEL_STR ":",lbl->key+100);
1863 emitcode("xor","a,a");
1864 emitcode("", LABEL_STR ":",tlbl->key+100);
1867 /*-----------------------------------------------------------------*/
1868 /* genCmpEq - generates code for equal to */
1869 /*-----------------------------------------------------------------*/
1870 static void genCmpEq (iCode *ic, iCode *ifx)
1872 operand *left, *right, *result;
1874 aopOp((left=IC_LEFT(ic)),ic,FALSE);
1875 aopOp((right=IC_RIGHT(ic)),ic,FALSE);
1876 aopOp((result=IC_RESULT(ic)),ic,TRUE);
1878 /* Swap operands if it makes the operation easier. ie if:
1879 1. Left is a literal.
1881 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
1882 operand *t = IC_RIGHT(ic);
1883 IC_RIGHT(ic) = IC_LEFT(ic);
1887 if (ifx && !AOP_SIZE(result)){
1889 /* if they are both bit variables */
1890 if (AOP_TYPE(left) == AOP_CRY &&
1891 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
1894 tlbl = newiTempLabel(NULL);
1895 gencjneshort(left, right, tlbl);
1896 if ( IC_TRUE(ifx) ) {
1897 emitcode("jp", LABEL_STR ,IC_TRUE(ifx)->key+100);
1898 emitcode("", LABEL_STR ":",tlbl->key+100);
1900 /* PENDING: do this better */
1901 symbol *lbl = newiTempLabel(NULL);
1902 emitcode("jp", LABEL_STR ,lbl->key+100);
1903 emitcode("", LABEL_STR ":",tlbl->key+100);
1904 emitcode("jp", LABEL_STR ,IC_FALSE(ifx)->key+100);
1905 emitcode("", LABEL_STR ":",lbl->key+100);
1908 /* mark the icode as generated */
1913 /* if they are both bit variables */
1914 if (AOP_TYPE(left) == AOP_CRY &&
1915 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
1918 gencjne(left,right,newiTempLabel(NULL));
1919 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
1923 genIfxJump(ifx,"a");
1926 /* if the result is used in an arithmetic operation
1927 then put the result in place */
1928 if (AOP_TYPE(result) != AOP_CRY) {
1931 /* leave the result in acc */
1935 freeAsmop(left,NULL,ic);
1936 freeAsmop(right,NULL,ic);
1937 freeAsmop(result,NULL,ic);
1940 /*-----------------------------------------------------------------*/
1941 /* ifxForOp - returns the icode containing the ifx for operand */
1942 /*-----------------------------------------------------------------*/
1943 static iCode *ifxForOp ( operand *op, iCode *ic )
1945 /* if true symbol then needs to be assigned */
1946 if (IS_TRUE_SYMOP(op))
1949 /* if this has register type condition and
1950 the next instruction is ifx with the same operand
1951 and live to of the operand is upto the ifx only then */
1953 ic->next->op == IFX &&
1954 IC_COND(ic->next)->key == op->key &&
1955 OP_SYMBOL(op)->liveTo <= ic->next->seq )
1961 /*-----------------------------------------------------------------*/
1962 /* genAndOp - for && operation */
1963 /*-----------------------------------------------------------------*/
1964 static void genAndOp (iCode *ic)
1966 operand *left,*right, *result;
1969 /* note here that && operations that are in an if statement are
1970 taken away by backPatchLabels only those used in arthmetic
1971 operations remain */
1972 aopOp((left=IC_LEFT(ic)),ic,FALSE);
1973 aopOp((right=IC_RIGHT(ic)),ic,FALSE);
1974 aopOp((result=IC_RESULT(ic)),ic,FALSE);
1976 /* if both are bit variables */
1977 if (AOP_TYPE(left) == AOP_CRY &&
1978 AOP_TYPE(right) == AOP_CRY ) {
1981 tlbl = newiTempLabel(NULL);
1983 emitcode("jp","z," LABEL_STR ,tlbl->key+100);
1985 emitcode("", LABEL_STR ":",tlbl->key+100);
1989 freeAsmop(left,NULL,ic);
1990 freeAsmop(right,NULL,ic);
1991 freeAsmop(result,NULL,ic);
1994 /*-----------------------------------------------------------------*/
1995 /* genOrOp - for || operation */
1996 /*-----------------------------------------------------------------*/
1997 static void genOrOp (iCode *ic)
1999 operand *left,*right, *result;
2002 /* note here that || operations that are in an
2003 if statement are taken away by backPatchLabels
2004 only those used in arthmetic operations remain */
2005 aopOp((left=IC_LEFT(ic)),ic,FALSE);
2006 aopOp((right=IC_RIGHT(ic)),ic,FALSE);
2007 aopOp((result=IC_RESULT(ic)),ic,FALSE);
2009 /* if both are bit variables */
2010 if (AOP_TYPE(left) == AOP_CRY &&
2011 AOP_TYPE(right) == AOP_CRY ) {
2014 tlbl = newiTempLabel(NULL);
2016 emitcode("jp","nz," LABEL_STR,tlbl->key+100);
2018 emitcode("", LABEL_STR,tlbl->key+100);
2022 freeAsmop(left,NULL,ic);
2023 freeAsmop(right,NULL,ic);
2024 freeAsmop(result,NULL,ic);
2027 /*-----------------------------------------------------------------*/
2028 /* isLiteralBit - test if lit == 2^n */
2029 /*-----------------------------------------------------------------*/
2030 int isLiteralBit(unsigned long lit)
2032 unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
2033 0x100L,0x200L,0x400L,0x800L,
2034 0x1000L,0x2000L,0x4000L,0x8000L,
2035 0x10000L,0x20000L,0x40000L,0x80000L,
2036 0x100000L,0x200000L,0x400000L,0x800000L,
2037 0x1000000L,0x2000000L,0x4000000L,0x8000000L,
2038 0x10000000L,0x20000000L,0x40000000L,0x80000000L};
2041 for(idx = 0; idx < 32; idx++)
2047 /*-----------------------------------------------------------------*/
2048 /* genAnd - code for and */
2049 /*-----------------------------------------------------------------*/
2050 static void genAnd (iCode *ic, iCode *ifx)
2052 operand *left, *right, *result;
2054 unsigned long lit = 0L;
2057 aopOp((left = IC_LEFT(ic)),ic,FALSE);
2058 aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2059 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2062 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2064 AOP_TYPE(left), AOP_TYPE(right));
2065 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2067 AOP_SIZE(left), AOP_SIZE(right));
2070 /* if left is a literal & right is not then exchange them */
2071 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2072 AOP_NEEDSACC(left)) {
2073 operand *tmp = right ;
2078 /* if result = right then exchange them */
2079 if(sameRegs(AOP(result),AOP(right))){
2080 operand *tmp = right ;
2085 /* if right is bit then exchange them */
2086 if (AOP_TYPE(right) == AOP_CRY &&
2087 AOP_TYPE(left) != AOP_CRY){
2088 operand *tmp = right ;
2092 if(AOP_TYPE(right) == AOP_LIT)
2093 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2095 size = AOP_SIZE(result);
2097 if (AOP_TYPE(left) == AOP_CRY){
2102 // if(val & 0xZZ) - size = 0, ifx != FALSE -
2103 // bit = val & 0xZZ - size = 1, ifx = FALSE -
2104 if((AOP_TYPE(right) == AOP_LIT) &&
2105 (AOP_TYPE(result) == AOP_CRY) &&
2106 (AOP_TYPE(left) != AOP_CRY)) {
2107 int posbit = isLiteralBit(lit);
2111 MOVA(aopGet(AOP(left),posbit>>3,FALSE));
2115 emitcode("mov","c,acc.%d",posbit&0x07);
2120 sprintf(buffer, "%d", posbit&0x07);
2121 genIfxJump(ifx, buffer);
2129 symbol *tlbl = newiTempLabel(NULL);
2130 int sizel = AOP_SIZE(left);
2133 emitcode("setb","c");
2136 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
2137 MOVA( aopGet(AOP(left),offset,FALSE));
2139 if((posbit = isLiteralBit(bytelit)) != 0) {
2141 emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
2144 if(bytelit != 0x0FFL)
2145 emitcode("and","a,%s",
2146 aopGet(AOP(right),offset,FALSE));
2147 emitcode("jr","nz, %05d$",tlbl->key+100);
2152 // bit = left & literal
2154 emitcode("clr","c");
2155 emitcode("","%05d$:",tlbl->key+100);
2157 // if(left & literal)
2161 jmpTrueOrFalse(ifx, tlbl);
2172 /* if left is same as result */
2173 if(sameRegs(AOP(result),AOP(left))){
2174 for(;size--; offset++) {
2175 if(AOP_TYPE(right) == AOP_LIT){
2176 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
2180 aopPut(AOP(result),zero,offset);
2182 MOVA(aopGet(AOP(left),offset,FALSE));
2183 emitcode("and","a,%s",
2184 aopGet(AOP(right),offset,FALSE));
2185 emitcode("ld", "%s,a", aopGet(AOP(left),offset,FALSE));
2190 if (AOP_TYPE(left) == AOP_ACC) {
2194 MOVA(aopGet(AOP(right),offset,FALSE));
2195 emitcode("and","%s,a",
2196 aopGet(AOP(left),offset,FALSE));
2201 // left & result in different registers
2202 if(AOP_TYPE(result) == AOP_CRY){
2205 for(;(size--);offset++) {
2207 // result = left & right
2208 if(AOP_TYPE(right) == AOP_LIT){
2209 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
2211 aopGet(AOP(left),offset,FALSE),
2214 } else if(bytelit == 0){
2215 aopPut(AOP(result),zero,offset);
2219 // faster than result <- left, anl result,right
2220 // and better if result is SFR
2221 if (AOP_TYPE(left) == AOP_ACC)
2222 emitcode("and","a,%s",aopGet(AOP(right),offset,FALSE));
2224 MOVA(aopGet(AOP(right),offset,FALSE));
2225 emitcode("and","a,%s",
2226 aopGet(AOP(left),offset,FALSE));
2228 aopPut(AOP(result),"a",offset);
2235 freeAsmop(left,NULL,ic);
2236 freeAsmop(right,NULL,ic);
2237 freeAsmop(result,NULL,ic);
2240 /*-----------------------------------------------------------------*/
2241 /* genOr - code for or */
2242 /*-----------------------------------------------------------------*/
2243 static void genOr (iCode *ic, iCode *ifx)
2245 operand *left, *right, *result;
2247 unsigned long lit = 0L;
2249 aopOp((left = IC_LEFT(ic)),ic,FALSE);
2250 aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2251 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2254 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2256 AOP_TYPE(left), AOP_TYPE(right));
2257 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2259 AOP_SIZE(left), AOP_SIZE(right));
2262 /* if left is a literal & right is not then exchange them */
2263 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2264 AOP_NEEDSACC(left)) {
2265 operand *tmp = right ;
2270 /* if result = right then exchange them */
2271 if(sameRegs(AOP(result),AOP(right))){
2272 operand *tmp = right ;
2277 /* if right is bit then exchange them */
2278 if (AOP_TYPE(right) == AOP_CRY &&
2279 AOP_TYPE(left) != AOP_CRY){
2280 operand *tmp = right ;
2284 if(AOP_TYPE(right) == AOP_LIT)
2285 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2287 size = AOP_SIZE(result);
2289 if (AOP_TYPE(left) == AOP_CRY){
2294 if((AOP_TYPE(right) == AOP_LIT) &&
2295 (AOP_TYPE(result) == AOP_CRY) &&
2296 (AOP_TYPE(left) != AOP_CRY)){
2301 /* if left is same as result */
2302 if(sameRegs(AOP(result),AOP(left))){
2303 for(;size--; offset++) {
2304 if(AOP_TYPE(right) == AOP_LIT){
2305 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
2308 emitcode("or","%s,%s",
2309 aopGet(AOP(left),offset,FALSE),
2310 aopGet(AOP(right),offset,FALSE));
2312 if (AOP_TYPE(left) == AOP_ACC)
2313 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
2315 MOVA(aopGet(AOP(right),offset,FALSE));
2316 emitcode("or","a,%s",
2317 aopGet(AOP(left),offset,FALSE));
2318 aopPut(AOP(result),"a",0);
2323 // left & result in different registers
2324 if(AOP_TYPE(result) == AOP_CRY){
2326 } else for(;(size--);offset++){
2328 // result = left & right
2329 if(AOP_TYPE(right) == AOP_LIT){
2330 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
2332 aopGet(AOP(left),offset,FALSE),
2337 // faster than result <- left, anl result,right
2338 // and better if result is SFR
2339 if (AOP_TYPE(left) == AOP_ACC)
2340 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
2342 MOVA(aopGet(AOP(right),offset,FALSE));
2343 emitcode("or","a,%s",
2344 aopGet(AOP(left),offset,FALSE));
2345 aopPut(AOP(result),"a",0);
2347 aopPut(AOP(result),"a",offset);
2352 freeAsmop(left,NULL,ic);
2353 freeAsmop(right,NULL,ic);
2354 freeAsmop(result,NULL,ic);
2357 /*-----------------------------------------------------------------*/
2358 /* genXor - code for xclusive or */
2359 /*-----------------------------------------------------------------*/
2360 static void genXor (iCode *ic, iCode *ifx)
2362 operand *left, *right, *result;
2364 unsigned long lit = 0L;
2366 aopOp((left = IC_LEFT(ic)),ic,FALSE);
2367 aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2368 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2370 /* if left is a literal & right is not then exchange them */
2371 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2372 AOP_NEEDSACC(left)) {
2373 operand *tmp = right ;
2378 /* if result = right then exchange them */
2379 if(sameRegs(AOP(result),AOP(right))){
2380 operand *tmp = right ;
2385 /* if right is bit then exchange them */
2386 if (AOP_TYPE(right) == AOP_CRY &&
2387 AOP_TYPE(left) != AOP_CRY){
2388 operand *tmp = right ;
2392 if(AOP_TYPE(right) == AOP_LIT)
2393 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2395 size = AOP_SIZE(result);
2397 if (AOP_TYPE(left) == AOP_CRY){
2402 if((AOP_TYPE(right) == AOP_LIT) &&
2403 (AOP_TYPE(result) == AOP_CRY) &&
2404 (AOP_TYPE(left) != AOP_CRY)){
2409 /* if left is same as result */
2410 if(sameRegs(AOP(result),AOP(left))){
2411 for(;size--; offset++) {
2412 if(AOP_TYPE(right) == AOP_LIT){
2413 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
2416 MOVA(aopGet(AOP(right),offset,FALSE));
2417 emitcode("xor","a,%s",
2418 aopGet(AOP(left),offset,FALSE));
2419 aopPut(AOP(result),"a",0);
2422 if (AOP_TYPE(left) == AOP_ACC)
2423 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
2425 MOVA(aopGet(AOP(right),offset,FALSE));
2426 emitcode("xor","a,%s",
2427 aopGet(AOP(left),offset,FALSE));
2428 aopPut(AOP(result),"a",0);
2433 // left & result in different registers
2434 if(AOP_TYPE(result) == AOP_CRY){
2436 } else for(;(size--);offset++){
2438 // result = left & right
2439 if(AOP_TYPE(right) == AOP_LIT){
2440 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
2442 aopGet(AOP(left),offset,FALSE),
2447 // faster than result <- left, anl result,right
2448 // and better if result is SFR
2449 if (AOP_TYPE(left) == AOP_ACC)
2450 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
2452 MOVA(aopGet(AOP(right),offset,FALSE));
2453 emitcode("xor","a,%s",
2454 aopGet(AOP(left),offset,FALSE));
2455 aopPut(AOP(result),"a",0);
2457 aopPut(AOP(result),"a",offset);
2462 freeAsmop(left,NULL,ic);
2463 freeAsmop(right,NULL,ic);
2464 freeAsmop(result,NULL,ic);
2467 /*-----------------------------------------------------------------*/
2468 /* genInline - write the inline code out */
2469 /*-----------------------------------------------------------------*/
2470 static void genInline (iCode *ic)
2472 char buffer[MAX_INLINEASM];
2476 inLine += (!options.asmpeep);
2477 strcpy(buffer,IC_INLINE(ic));
2479 /* emit each line as a code */
2498 /* emitcode("",buffer); */
2499 inLine -= (!options.asmpeep);
2502 /*-----------------------------------------------------------------*/
2503 /* genRRC - rotate right with carry */
2504 /*-----------------------------------------------------------------*/
2505 static void genRRC (iCode *ic)
2510 /*-----------------------------------------------------------------*/
2511 /* genRLC - generate code for rotate left with carry */
2512 /*-----------------------------------------------------------------*/
2513 static void genRLC (iCode *ic)
2518 /*-----------------------------------------------------------------*/
2519 /* shiftR2Left2Result - shift right two bytes from left to result */
2520 /*-----------------------------------------------------------------*/
2521 static void shiftR2Left2Result (operand *left, int offl,
2522 operand *result, int offr,
2523 int shCount, int sign)
2525 if(sameRegs(AOP(result), AOP(left)) &&
2526 ((offl + MSB16) == offr)){
2529 movLeft2Result(left, offl, result, offr, 0);
2530 movLeft2Result(left, offl+1, result, offr+1, 0);
2537 /* if (AOP(result)->type == AOP_REG) {*/
2540 symbol *tlbl , *tlbl1;
2543 /* Left is already in result - so now do the shift */
2545 emitcode("ld","a,#%u+1", shCount);
2546 tlbl = newiTempLabel(NULL);
2547 tlbl1 = newiTempLabel(NULL);
2548 emitcode("jp", LABEL_STR ,tlbl1->key+100);
2549 emitcode("", LABEL_STR ":",tlbl->key+100);
2552 emitcode("or", "a,a");
2555 l = aopGet(AOP(result), --offset, FALSE);
2556 emitcode("rr","%s", l);
2559 emitcode("", LABEL_STR ":",tlbl1->key+100);
2560 emitcode("dec", "a");
2561 emitcode("jp","nz," LABEL_STR ,tlbl->key+100);
2566 /*-----------------------------------------------------------------*/
2567 /* shiftL2Left2Result - shift left two bytes from left to result */
2568 /*-----------------------------------------------------------------*/
2569 static void shiftL2Left2Result (operand *left, int offl,
2570 operand *result, int offr, int shCount)
2572 if(sameRegs(AOP(result), AOP(left)) &&
2573 ((offl + MSB16) == offr)){
2576 /* Copy left into result */
2577 movLeft2Result(left,offl, result, offr, 0);
2579 if (AOP(result)->type == AOP_REG) {
2582 symbol *tlbl , *tlbl1;
2585 /* Left is already in result - so now do the shift */
2587 emitcode("ld","a,#%u+1", shCount);
2588 tlbl = newiTempLabel(NULL);
2589 tlbl1 = newiTempLabel(NULL);
2590 emitcode("jp", LABEL_STR ,tlbl1->key+100);
2591 emitcode("", LABEL_STR ":",tlbl->key+100);
2594 emitcode("or", "a,a");
2596 l = aopGet(AOP(result),offset++,FALSE);
2597 emitcode("rl","%s", l);
2600 emitcode("", LABEL_STR ":",tlbl1->key+100);
2601 emitcode("dec", "a");
2602 emitcode("jp","nz," LABEL_STR ,tlbl->key+100);
2606 /* PENDING: do something */
2611 /*-----------------------------------------------------------------*/
2612 /* AccRol - rotate left accumulator by known count */
2613 /*-----------------------------------------------------------------*/
2614 static void AccRol (int shCount)
2616 shCount &= 0x0007; // shCount : 0..7
2653 /*-----------------------------------------------------------------*/
2654 /* AccLsh - left shift accumulator by known count */
2655 /*-----------------------------------------------------------------*/
2656 static void AccLsh (int shCount)
2660 emitcode("add","a,a");
2663 emitcode("add","a,a");
2664 emitcode("add","a,a");
2666 /* rotate left accumulator */
2668 /* and kill the lower order bits */
2669 emitcode("and","a,#0x%02x", SLMask[shCount]);
2674 /*-----------------------------------------------------------------*/
2675 /* shiftL1Left2Result - shift left one byte from left to result */
2676 /*-----------------------------------------------------------------*/
2677 static void shiftL1Left2Result (operand *left, int offl,
2678 operand *result, int offr, int shCount)
2681 l = aopGet(AOP(left),offl,FALSE);
2683 /* shift left accumulator */
2685 aopPut(AOP(result),"a",offr);
2689 /*-----------------------------------------------------------------*/
2690 /* genlshTwo - left shift two bytes by known amount != 0 */
2691 /*-----------------------------------------------------------------*/
2692 static void genlshTwo (operand *result,operand *left, int shCount)
2694 int size = AOP_SIZE(result);
2698 /* if shCount >= 8 */
2704 movLeft2Result(left, LSB, result, MSB16, 0);
2705 aopPut(AOP(result),zero, 0);
2706 shiftL1Left2Result(left, MSB16, result, MSB16, shCount-8);
2709 movLeft2Result(left, LSB, result, MSB16, 0);
2710 aopPut(AOP(result),zero, 0);
2713 aopPut(AOP(result),zero,LSB);
2715 /* 1 <= shCount <= 7 */
2721 shiftL2Left2Result(left, LSB, result, LSB, shCount);
2726 /*-----------------------------------------------------------------*/
2727 /* genlshOne - left shift a one byte quantity by known count */
2728 /*-----------------------------------------------------------------*/
2729 static void genlshOne (operand *result, operand *left, int shCount)
2731 shiftL1Left2Result(left, LSB, result, LSB, shCount);
2734 /*-----------------------------------------------------------------*/
2735 /* genLeftShiftLiteral - left shifting by known count */
2736 /*-----------------------------------------------------------------*/
2737 static void genLeftShiftLiteral (operand *left,
2742 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
2745 freeAsmop(right,NULL,ic);
2747 aopOp(left,ic,FALSE);
2748 aopOp(result,ic,FALSE);
2750 size = getSize(operandType(result));
2753 emitcode("; shift left ","result %d, left %d",size,
2757 /* I suppose that the left size >= result size */
2762 else if(shCount >= (size * 8))
2764 aopPut(AOP(result),zero,size);
2768 genlshOne (result,left,shCount);
2771 genlshTwo (result,left,shCount);
2780 freeAsmop(left,NULL,ic);
2781 freeAsmop(result,NULL,ic);
2784 /*-----------------------------------------------------------------*/
2785 /* genLeftShift - generates code for left shifting */
2786 /*-----------------------------------------------------------------*/
2787 static void genLeftShift (iCode *ic)
2791 symbol *tlbl , *tlbl1;
2792 operand *left,*right, *result;
2794 right = IC_RIGHT(ic);
2796 result = IC_RESULT(ic);
2798 aopOp(right,ic,FALSE);
2800 /* if the shift count is known then do it
2801 as efficiently as possible */
2802 if (AOP_TYPE(right) == AOP_LIT) {
2803 genLeftShiftLiteral (left,right,result,ic);
2807 /* shift count is unknown then we have to form a loop get the loop
2808 count in B : Note: we take only the lower order byte since
2809 shifting more that 32 bits make no sense anyway, ( the largest
2810 size of an object can be only 32 bits ) */
2811 emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE));
2812 emitcode("inc","a");
2813 freeAsmop (right,NULL,ic);
2814 aopOp(left,ic,FALSE);
2815 aopOp(result,ic,FALSE);
2817 /* now move the left to the result if they are not the
2820 if (!sameRegs(AOP(left),AOP(result))) {
2822 size = AOP_SIZE(result);
2825 l = aopGet(AOP(left),offset,FALSE);
2826 aopPut(AOP(result),l,offset);
2831 size = AOP_SIZE(result);
2834 l = aopGet(AOP(left),offset,FALSE);
2835 aopPut(AOP(result),l,offset);
2841 tlbl = newiTempLabel(NULL);
2842 size = AOP_SIZE(result);
2844 tlbl1 = newiTempLabel(NULL);
2846 emitcode("jp", LABEL_STR ,tlbl1->key+100);
2847 emitcode("", LABEL_STR ":",tlbl->key+100);
2848 l = aopGet(AOP(result),offset,FALSE);
2849 emitcode("or", "a,a");
2851 l = aopGet(AOP(result),offset++,FALSE);
2852 emitcode("rl","%s", l);
2854 emitcode("", LABEL_STR ":",tlbl1->key+100);
2855 emitcode("dec", "a");
2856 emitcode("jp","nz," LABEL_STR ,tlbl->key+100);
2858 freeAsmop(left,NULL,ic);
2859 freeAsmop(result,NULL,ic);
2862 /* genlshTwo - left shift two bytes by known amount != 0 */
2863 /*-----------------------------------------------------------------*/
2864 static void genrshOne (operand *result,operand *left, int shCount)
2867 int size = AOP_SIZE(result);
2873 l = aopGet(AOP(left),0,FALSE);
2874 if (AOP(result)->type == AOP_REG) {
2875 aopPut(AOP(result), l, 0);
2876 l = aopGet(AOP(result), 0, FALSE);
2878 emitcode("srl", "%s", l);
2883 emitcode("srl", "a");
2885 aopPut(AOP(result),"a",0);
2889 /*-----------------------------------------------------------------*/
2890 /* AccRsh - right shift accumulator by known count */
2891 /*-----------------------------------------------------------------*/
2892 static void AccRsh (int shCount)
2899 /* rotate right accumulator */
2900 AccRol(8 - shCount);
2901 /* and kill the higher order bits */
2902 emitcode("and","a,#0x%02x", SRMask[shCount]);
2907 /*-----------------------------------------------------------------*/
2908 /* shiftR1Left2Result - shift right one byte from left to result */
2909 /*-----------------------------------------------------------------*/
2910 static void shiftR1Left2Result (operand *left, int offl,
2911 operand *result, int offr,
2912 int shCount, int sign)
2914 MOVA(aopGet(AOP(left),offl,FALSE));
2921 aopPut(AOP(result),"a",offr);
2924 /*-----------------------------------------------------------------*/
2925 /* genrshTwo - right shift two bytes by known amount != 0 */
2926 /*-----------------------------------------------------------------*/
2927 static void genrshTwo (operand *result,operand *left,
2928 int shCount, int sign)
2930 /* if shCount >= 8 */
2935 shiftR1Left2Result(left, MSB16, result, LSB,
2939 movLeft2Result(left, MSB16, result, LSB, sign);
2940 aopPut(AOP(result),zero,1);
2943 /* 1 <= shCount <= 7 */
2945 shiftR2Left2Result(left, LSB, result, LSB, shCount, sign);
2949 /*-----------------------------------------------------------------*/
2950 /* genRightShiftLiteral - left shifting by known count */
2951 /*-----------------------------------------------------------------*/
2952 static void genRightShiftLiteral (operand *left,
2957 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
2960 freeAsmop(right,NULL,ic);
2962 aopOp(left,ic,FALSE);
2963 aopOp(result,ic,FALSE);
2965 size = getSize(operandType(result));
2967 emitcode("; shift right ","result %d, left %d",size,
2970 /* I suppose that the left size >= result size */
2975 else if(shCount >= (size * 8))
2977 aopPut(AOP(result),zero,size);
2981 genrshOne(result, left, shCount);
2984 /* PENDING: sign support */
2985 genrshTwo(result, left, shCount, FALSE);
2994 freeAsmop(left,NULL,ic);
2995 freeAsmop(result,NULL,ic);
2998 /*-----------------------------------------------------------------*/
2999 /* genRightShift - generate code for right shifting */
3000 /*-----------------------------------------------------------------*/
3001 static void genRightShift (iCode *ic)
3003 operand *left,*right, *result;
3005 right = IC_RIGHT(ic);
3007 result = IC_RESULT(ic);
3009 aopOp(right,ic,FALSE);
3011 /* if the shift count is known then do it
3012 as efficiently as possible */
3013 if (AOP_TYPE(right) == AOP_LIT) {
3014 genRightShiftLiteral (left,right,result,ic);
3022 /*-----------------------------------------------------------------*/
3023 /* genGenPointerGet - gget value from generic pointer space */
3024 /*-----------------------------------------------------------------*/
3025 static void genGenPointerGet (operand *left,
3026 operand *result, iCode *ic)
3029 link *retype = getSpec(operandType(result));
3031 aopOp(left,ic,FALSE);
3032 aopOp(result,ic,FALSE);
3034 if (isPair(AOP(left)) && (AOP_SIZE(result)==1)) {
3036 emitcode("ld", "a,(%s)", getPairName(AOP(left)));
3037 aopPut(AOP(result),"a", 0);
3038 freeAsmop(left,NULL,ic);
3042 /* For now we always load into IY */
3043 /* if this is remateriazable */
3044 if (AOP_TYPE(left) == AOP_IMMD)
3045 emitcode("ld","hl,%s",aopGet(AOP(left),0,TRUE));
3046 else { /* we need to get it byte by byte */
3047 emitcode("ld", "l,%s", aopGet(AOP(left), 0, FALSE));
3048 emitcode("ld", "h,%s", aopGet(AOP(left), 1, FALSE));
3050 /* so iy now contains the address */
3051 freeAsmop(left,NULL,ic);
3053 /* if bit then unpack */
3054 if (IS_BITVAR(retype)) {
3058 size = AOP_SIZE(result);
3062 /* PENDING: make this better */
3063 if (AOP(result)->type == AOP_REG) {
3064 aopPut(AOP(result),"(hl)",offset++);
3067 emitcode("ld", "a,(hl)", offset);
3068 aopPut(AOP(result),"a",offset++);
3071 emitcode("inc", "hl");
3077 freeAsmop(result,NULL,ic);
3080 /*-----------------------------------------------------------------*/
3081 /* genPointerGet - generate code for pointer get */
3082 /*-----------------------------------------------------------------*/
3083 static void genPointerGet (iCode *ic)
3085 operand *left, *result ;
3089 result = IC_RESULT(ic) ;
3091 /* depending on the type of pointer we need to
3092 move it to the correct pointer register */
3093 type = operandType(left);
3094 etype = getSpec(type);
3096 genGenPointerGet (left,result,ic);
3099 bool isRegOrLit(asmop *aop)
3101 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
3106 /*-----------------------------------------------------------------*/
3107 /* genGenPointerSet - stores the value into a pointer location */
3108 /*-----------------------------------------------------------------*/
3109 static void genGenPointerSet (operand *right,
3110 operand *result, iCode *ic)
3113 link *retype = getSpec(operandType(right));
3115 aopOp(result,ic,FALSE);
3116 aopOp(right,ic,FALSE);
3118 /* Handle the exceptions first */
3119 if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
3121 char *l = aopGet(AOP(right), 0, FALSE);
3123 emitcode("ld", "(%s),a", getPairName(AOP(result)));
3124 freeAsmop(result,NULL,ic);
3128 /* if the operand is already in dptr
3129 then we do nothing else we move the value to dptr */
3130 if (AOP_TYPE(result) != AOP_STR) {
3131 /* if this is remateriazable */
3132 if (AOP_TYPE(result) == AOP_IMMD) {
3133 emitcode("", "; Error 2");
3134 emitcode("ld", "hl,%s", aopGet(AOP(result), 0, TRUE));
3136 else { /* we need to get it byte by byte */
3137 /* PENDING: do this better */
3138 emitcode("ld", "l,%s", aopGet(AOP(result), 0, FALSE));
3139 emitcode("ld", "h,%s", aopGet(AOP(result), 1, FALSE));
3142 /* so hl know contains the address */
3143 freeAsmop(result,NULL,ic);
3145 /* if bit then unpack */
3146 if (IS_BITVAR(retype)) {
3150 size = AOP_SIZE(right);
3154 char *l = aopGet(AOP(right),offset,FALSE);
3156 if (isRegOrLit(AOP(right))) {
3157 emitcode("ld", "(hl),%s", l);
3161 emitcode("ld", "(hl),a", offset);
3164 emitcode("inc", "hl");
3170 freeAsmop(right,NULL,ic);
3173 /*-----------------------------------------------------------------*/
3174 /* genPointerSet - stores the value into a pointer location */
3175 /*-----------------------------------------------------------------*/
3176 static void genPointerSet (iCode *ic)
3178 operand *right, *result ;
3181 right = IC_RIGHT(ic);
3182 result = IC_RESULT(ic) ;
3184 /* depending on the type of pointer we need to
3185 move it to the correct pointer register */
3186 type = operandType(result);
3187 etype = getSpec(type);
3189 genGenPointerSet (right,result,ic);
3192 /*-----------------------------------------------------------------*/
3193 /* genIfx - generate code for Ifx statement */
3194 /*-----------------------------------------------------------------*/
3195 static void genIfx (iCode *ic, iCode *popIc)
3197 operand *cond = IC_COND(ic);
3200 aopOp(cond,ic,FALSE);
3202 /* get the value into acc */
3203 if (AOP_TYPE(cond) != AOP_CRY)
3207 /* the result is now in the accumulator */
3208 freeAsmop(cond,NULL,ic);
3210 /* if there was something to be popped then do it */
3214 /* if the condition is a bit variable */
3215 if (isbit && IS_ITEMP(cond) &&
3217 genIfxJump(ic,SPIL_LOC(cond)->rname);
3219 if (isbit && !IS_ITEMP(cond))
3220 genIfxJump(ic,OP_SYMBOL(cond)->rname);
3227 /*-----------------------------------------------------------------*/
3228 /* genAddrOf - generates code for address of */
3229 /*-----------------------------------------------------------------*/
3230 static void genAddrOf (iCode *ic)
3232 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
3234 aopOp(IC_RESULT(ic),ic,FALSE);
3236 /* if the operand is on the stack then we
3237 need to get the stack offset of this
3240 /* if it has an offset then we need to compute it */
3241 emitcode("push", "de");
3242 emitcode("push", "ix");
3243 emitcode("pop", "hl");
3244 emitcode("ld", "de,#%d", sym->stack);
3245 emitcode("add", "hl,de");
3246 emitcode("pop", "de");
3249 emitcode("ld", "hl,#%s", sym->rname);
3251 aopPut(AOP(IC_RESULT(ic)), "l", 0);
3252 aopPut(AOP(IC_RESULT(ic)), "h", 1);
3254 freeAsmop(IC_RESULT(ic),NULL,ic);
3257 /*-----------------------------------------------------------------*/
3258 /* genAssign - generate code for assignment */
3259 /*-----------------------------------------------------------------*/
3260 static void genAssign (iCode *ic)
3262 operand *result, *right;
3264 unsigned long lit = 0L;
3266 result = IC_RESULT(ic);
3267 right = IC_RIGHT(ic) ;
3269 /* Dont bother assigning if they are the same */
3270 if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) {
3271 emitcode("", "; (operands are equal)");
3275 aopOp(right,ic,FALSE);
3276 aopOp(result,ic,TRUE);
3278 /* if they are the same registers */
3279 if (sameRegs(AOP(right),AOP(result))) {
3280 emitcode("", "; (registers are the same)");
3284 /* if the result is a bit */
3285 if (AOP_TYPE(result) == AOP_CRY) {
3290 size = AOP_SIZE(result);
3293 if(AOP_TYPE(right) == AOP_LIT)
3294 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
3296 (AOP_TYPE(result) != AOP_REG) &&
3297 (AOP_TYPE(right) == AOP_LIT) &&
3298 !IS_FLOAT(operandType(right)) &&
3300 emitcode("xor","a,a");
3301 /* Work from the top down.
3302 Done this way so that we can use the cached copy of 0
3303 in A for a fast clear */
3305 if((unsigned int)((lit >> (size*8)) & 0x0FFL)== 0)
3306 aopPut(AOP(result),"a",size);
3309 aopGet(AOP(right),size,FALSE),
3315 aopGet(AOP(right),offset,FALSE),
3322 freeAsmop(right,NULL,ic);
3323 freeAsmop(result,NULL,ic);
3326 /*-----------------------------------------------------------------*/
3327 /* genJumpTab - genrates code for jump table */
3328 /*-----------------------------------------------------------------*/
3329 static void genJumpTab (iCode *ic)
3334 /*-----------------------------------------------------------------*/
3335 /* genCast - gen code for casting */
3336 /*-----------------------------------------------------------------*/
3337 static void genCast (iCode *ic)
3339 operand *result = IC_RESULT(ic);
3340 link *ctype = operandType(IC_LEFT(ic));
3341 operand *right = IC_RIGHT(ic);
3344 /* if they are equivalent then do nothing */
3345 if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
3348 aopOp(right,ic,FALSE) ;
3349 aopOp(result,ic,FALSE);
3351 /* if the result is a bit */
3352 if (AOP_TYPE(result) == AOP_CRY) {
3356 /* if they are the same size : or less */
3357 if (AOP_SIZE(result) <= AOP_SIZE(right)) {
3359 /* if they are in the same place */
3360 if (sameRegs(AOP(right),AOP(result)))
3363 /* if they in different places then copy */
3364 size = AOP_SIZE(result);
3368 aopGet(AOP(right),offset,FALSE),
3375 /* if the result is of type pointer */
3376 if (IS_PTR(ctype)) {
3380 /* so we now know that the size of destination is greater
3381 than the size of the source */
3382 /* we move to result for the size of source */
3383 size = AOP_SIZE(right);
3387 aopGet(AOP(right),offset,FALSE),
3392 /* now depending on the sign of the destination */
3393 size = AOP_SIZE(result) - AOP_SIZE(right);
3394 /* Unsigned or not an integral type - right fill with zeros */
3395 if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) {
3397 aopPut(AOP(result),zero,offset++);
3399 /* we need to extend the sign :{ */
3400 char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
3403 emitcode("", "; genCast: sign extend untested.");
3404 emitcode("rla", "");
3405 emitcode("sbc", "a,a");
3407 aopPut(AOP(result),"a",offset++);
3411 freeAsmop(right, NULL, ic);
3412 freeAsmop(result, NULL, ic);
3415 /*-----------------------------------------------------------------*/
3416 /* genReceive - generate code for a receive iCode */
3417 /*-----------------------------------------------------------------*/
3418 static void genReceive (iCode *ic)
3420 if (isOperandInFarSpace(IC_RESULT(ic)) &&
3421 ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
3422 IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
3426 aopOp(IC_RESULT(ic),ic,FALSE);
3428 assignResultValue(IC_RESULT(ic));
3431 freeAsmop(IC_RESULT(ic),NULL,ic);
3434 /*-----------------------------------------------------------------*/
3435 /* genZ80Code - generate code for Z80 based controllers */
3436 /*-----------------------------------------------------------------*/
3437 void genZ80Code (iCode *lic)
3442 lineHead = lineCurr = NULL;
3444 /* if debug information required */
3445 if (options.debug && currFunc) {
3446 cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
3448 if (IS_STATIC(currFunc->etype))
3449 emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name);
3451 emitcode("","G$%s$0$0 ==.",currFunc->name);
3454 /* stack pointer name */
3458 for (ic = lic ; ic ; ic = ic->next ) {
3460 if ( cln != ic->lineno ) {
3461 if ( options.debug ) {
3463 emitcode("","C$%s$%d$%d$%d ==.",
3464 ic->filename,ic->lineno,
3465 ic->level,ic->block);
3468 emitcode(";","%s %d",ic->filename,ic->lineno);
3471 /* if the result is marked as
3472 spilt and rematerializable or code for
3473 this has already been generated then
3475 if (resultRemat(ic) || ic->generated )
3478 /* depending on the operation */
3481 emitcode("", "; genNot");
3486 emitcode("", "; genCpl");
3491 emitcode("", "; genUminus");
3496 emitcode("", "; genIpush");
3501 /* IPOP happens only when trying to restore a
3502 spilt live range, if there is an ifx statement
3503 following this pop then the if statement might
3504 be using some of the registers being popped which
3505 would destory the contents of the register so
3506 we need to check for this condition and handle it */
3508 ic->next->op == IFX &&
3509 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) {
3510 emitcode("", "; genIfx");
3511 genIfx (ic->next,ic);
3514 emitcode("", "; genIpop");
3520 emitcode("", "; genCall");
3525 emitcode("", "; genPcall");
3530 emitcode("", "; genFunction");
3535 emitcode("", "; genEndFunction");
3536 genEndFunction (ic);
3540 emitcode("", "; genRet");
3545 emitcode("", "; genLabel");
3550 emitcode("", "; genGoto");
3555 emitcode("", "; genPlus");
3560 emitcode("", "; genMinus");
3565 emitcode("", "; genMult");
3570 emitcode("", "; genDiv");
3575 emitcode("", "; genMod");
3580 emitcode("", "; genCmpGt");
3581 genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));
3585 emitcode("", "; genCmpLt");
3586 genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
3593 /* note these two are xlated by algebraic equivalence
3594 during parsing SDCC.y */
3595 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
3596 "got '>=' or '<=' shouldn't have come here");
3600 emitcode("", "; genCmpEq");
3601 genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
3605 emitcode("", "; genAndOp");
3610 emitcode("", "; genOrOp");
3615 emitcode("", "; genXor");
3616 genXor (ic,ifxForOp(IC_RESULT(ic),ic));
3620 emitcode("", "; genOr");
3621 genOr (ic,ifxForOp(IC_RESULT(ic),ic));
3625 emitcode("", "; genAnd");
3626 genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
3630 emitcode("", "; genInline");
3635 emitcode("", "; genRRC");
3640 emitcode("", "; genRLC");
3645 emitcode("", "; genHBIT");
3649 emitcode("", "; genLeftShift");
3654 emitcode("", "; genRightShift");
3658 case GET_VALUE_AT_ADDRESS:
3659 emitcode("", "; genPointerGet");
3665 if (POINTER_SET(ic)) {
3666 emitcode("", "; genAssign (pointer)");
3670 emitcode("", "; genAssign");
3676 emitcode("", "; genIfx");
3681 emitcode("", "; genAddrOf");
3686 emitcode("", "; genJumpTab");
3691 emitcode("", "; genCast");
3696 emitcode("", "; genReceive");
3701 emitcode("", "; addSet");
3702 addSet(&sendSet,ic);
3707 /* piCode(ic,stdout); */
3713 /* now we are ready to call the
3714 peep hole optimizer */
3715 /* if (!options.nopeep)
3716 peepHole (&lineHead); */
3718 /* now do the actual printing */
3719 printLine (lineHead,codeOutFile);