diff options
| author | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
|---|---|---|
| committer | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
| commit | 268a53de823a6750d6256ee1fb1e7707b4b45740 (patch) | |
| tree | 42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/SDCCicode.c | |
| download | sdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz | |
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'src/SDCCicode.c')
| -rw-r--r-- | src/SDCCicode.c | 4678 |
1 files changed, 4678 insertions, 0 deletions
diff --git a/src/SDCCicode.c b/src/SDCCicode.c new file mode 100644 index 0000000..ccb9461 --- /dev/null +++ b/src/SDCCicode.c @@ -0,0 +1,4678 @@ +/*------------------------------------------------------------------------- + + SDCCicode.c - intermediate code generation etc. + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +#include "common.h" +#include "newalloc.h" +#include "math.h" +#include "dbuf_string.h" + +/*-----------------------------------------------------------------*/ +/* global variables */ + +set *iCodeChain = NULL; +int iTempNum = 0; +int iTempLblNum = 0; +int operandKey = 0; +int iCodeKey = 0; +char *filename; /* current file name */ +int lineno = 1; /* current line number */ +int block; +long scopeLevel; +int seqPoint; +int inCriticalPair = 0; + +symbol *returnLabel; /* function return label */ +symbol *entryLabel; /* function entry label */ + +/*-----------------------------------------------------------------*/ +/* forward definition of some functions */ +operand *geniCodeAssign (operand *, operand *, int, int); +static operand *geniCodeArray (operand *, operand *, int); +static operand *geniCodeArray2Ptr (operand *); +operand *geniCodeRValue (operand *, bool); +operand *geniCodeDerefPtr (operand *, int); +static int isLvaluereq (int lvl); +static operand *geniCodeCast (sym_link *, operand *, bool); + +#define PRINTFUNC(x) void x (struct dbuf_s *dbuf, iCode *ic, char *s) +/* forward definition of ic print functions */ +PRINTFUNC (picGetValueAtAddr); +PRINTFUNC (picSetValueAtAddr); +PRINTFUNC (picAddrOf); +PRINTFUNC (picGeneric); +PRINTFUNC (picGenericOne); +PRINTFUNC (picCast); +PRINTFUNC (picAssign); +PRINTFUNC (picLabel); +PRINTFUNC (picGoto); +PRINTFUNC (picIfx); +PRINTFUNC (picJumpTable); +PRINTFUNC (picInline); +PRINTFUNC (picReceive); +PRINTFUNC (picDummyRead); +PRINTFUNC (picCritical); +PRINTFUNC (picEndCritical); + +iCodeTable codeTable[] = { + {'!', "not", picGenericOne, NULL}, + {'~', "~", picGenericOne, NULL}, + {RRC, "rrc", picGenericOne, NULL}, + {RLC, "rlc", picGenericOne, NULL}, + {GETHBIT, "ghbit", picGenericOne, NULL}, + {GETABIT, "gabit", picGenericOne, NULL}, + {GETBYTE, "gbyte", picGenericOne, NULL}, + {GETWORD, "gword", picGenericOne, NULL}, + {UNARYMINUS, "-", picGenericOne, NULL}, + {IPUSH, "push", picGenericOne, NULL}, + {IPOP, "pop", picGenericOne, NULL}, + {CALL, "call", picGenericOne, NULL}, + {PCALL, "pcall", picGenericOne, NULL}, + {FUNCTION, "proc", picGenericOne, NULL}, + {ENDFUNCTION, "eproc", picGenericOne, NULL}, + {RETURN, "ret", picGenericOne, NULL}, + {'+', "+", picGeneric, NULL}, + {'-', "-", picGeneric, NULL}, + {'*', "*", picGeneric, NULL}, + {'/', "/", picGeneric, NULL}, + {'%', "%", picGeneric, NULL}, + {'>', ">", picGeneric, NULL}, + {'<', "<", picGeneric, NULL}, + {LE_OP, "<=", picGeneric, NULL}, + {GE_OP, ">=", picGeneric, NULL}, + {EQ_OP, "==", picGeneric, NULL}, + {NE_OP, "!=", picGeneric, NULL}, + {AND_OP, "&&", picGeneric, NULL}, + {OR_OP, "||", picGeneric, NULL}, + {'^', "^", picGeneric, NULL}, + {'|', "|", picGeneric, NULL}, + {BITWISEAND, "&", picGeneric, NULL}, + {LEFT_OP, "<<", picGeneric, NULL}, + {RIGHT_OP, ">>", picGeneric, NULL}, + {GET_VALUE_AT_ADDRESS, "@", picGetValueAtAddr, NULL}, + {SET_VALUE_AT_ADDRESS, "@", picSetValueAtAddr, NULL}, + {ADDRESS_OF, "&", picAddrOf, NULL}, + {CAST, "<>", picCast, NULL}, + {'=', ":=", picAssign, NULL}, + {LABEL, "", picLabel, NULL}, + {GOTO, "", picGoto, NULL}, + {JUMPTABLE, "jtab", picJumpTable, NULL}, + {IFX, "if", picIfx, NULL}, + {INLINEASM, "", picInline, NULL}, + {RECEIVE, "recv", picReceive, NULL}, + {SEND, "send", picGenericOne, NULL}, + {ARRAYINIT, "arrayInit", picGenericOne, NULL}, + {DUMMY_READ_VOLATILE, "dummy = (volatile)", picDummyRead, NULL}, + {CRITICAL, "critical_start", picCritical, NULL}, + {ENDCRITICAL, "critical_end", picEndCritical, NULL}, + {SWAP, "swap", picGenericOne, NULL} +}; + +/*-----------------------------------------------------------------*/ +/* operandName - returns the name of the operand */ +/*-----------------------------------------------------------------*/ +int +printOperand (operand * op, FILE * file) +{ + struct dbuf_s dbuf; + int ret; + int pnl = 0; + + if (!file) + { + file = stdout; + pnl = 1; + } + dbuf_init (&dbuf, 1024); + ret = dbuf_printOperand (op, &dbuf); + dbuf_write_and_destroy (&dbuf, file); + + if (pnl) + putc ('\n', file); + + return ret; +} + +int +dbuf_printOperand (operand * op, struct dbuf_s *dbuf) +{ + sym_link *opetype; + + if (!op) + return 1; + + switch (op->type) + { + case VALUE: + opetype = getSpec (operandType (op)); + if (IS_FLOAT (opetype)) + dbuf_printf (dbuf, "%g {", SPEC_CVAL (opetype).v_float); + else if (IS_FIXED16X16 (opetype)) + dbuf_printf (dbuf, "%g {", doubleFromFixed16x16 (SPEC_CVAL (opetype).v_fixed16x16)); + else if (IS_LONGLONG (opetype)) + dbuf_printf (dbuf, "0x%llx {", (unsigned long long) SPEC_CVAL (OP_VALUE (op)->etype).v_ulonglong); + else + dbuf_printf (dbuf, "0x%x {", (unsigned int) ulFromVal (OP_VALUE (op))); + dbuf_printTypeChain (operandType (op), dbuf); + dbuf_append_char (dbuf, '}'); + break; + + case SYMBOL: +#define REGA 1 +//#if REGA /* { */ + if (REGA && !getenv ("PRINT_SHORT_OPERANDS")) + { + dbuf_printf (dbuf, "%s [k%d lr%d:%d so:%d]{ ia%d a2p%d re%d rm%d nos%d ru%d dp%d}", /*{ar%d rm%d ru%d p%d a%d u%d i%d au%d k%d ks%d}" , */ + (OP_SYMBOL (op)->rname[0] ? OP_SYMBOL (op)->rname : OP_SYMBOL (op)->name), + op->key, + OP_LIVEFROM (op), OP_LIVETO (op), + OP_SYMBOL (op)->stack, + op->isaddr, op->aggr2ptr, OP_SYMBOL (op)->isreqv, + OP_SYMBOL (op)->remat, OP_SYMBOL (op)->noSpilLoc, OP_SYMBOL (op)->ruonly, OP_SYMBOL (op)->dptr); + { + dbuf_append_char (dbuf, '{'); + dbuf_printTypeChain (operandType (op), dbuf); + if (SPIL_LOC (op) && IS_ITEMP (op)) + dbuf_printf (dbuf, "}{ sir@ %s", SPIL_LOC (op)->rname); + dbuf_append_char (dbuf, '}'); + } + + /* if assigned to registers */ + if (OP_SYMBOL (op)->nRegs) + { + if (OP_SYMBOL (op)->isspilt) + { + if (!OP_SYMBOL (op)->remat) + if (OP_SYMBOL (op)->usl.spillLoc) + dbuf_printf (dbuf, "[%s]", (OP_SYMBOL (op)->usl.spillLoc->rname[0] ? + OP_SYMBOL (op)->usl.spillLoc->rname : OP_SYMBOL (op)->usl.spillLoc->name)); + else + dbuf_append_str (dbuf, "[err]"); + else + dbuf_append_str (dbuf, "[remat]"); + } + else + { + int i; + dbuf_append_char (dbuf, '['); + for (i = 0; i < OP_SYMBOL (op)->nRegs; i++) + dbuf_printf (dbuf, "%s ", port->getRegName (OP_SYMBOL (op)->regs[i])); + dbuf_append_char (dbuf, ']'); + } + } +//#else /* } else { */ + } + else + { + /* (getenv("PRINT_SHORT_OPERANDS") != NULL) */ + dbuf_printf (dbuf, "%s ", (OP_SYMBOL (op)->rname[0] ? OP_SYMBOL (op)->rname : OP_SYMBOL (op)->name)); + + if (getenv ("PRINT_SHORT_OPERANDS")[0] < '1') + { + dbuf_printf (dbuf, "[lr%d:%d so:%d]", OP_LIVEFROM (op), OP_LIVETO (op), OP_SYMBOL (op)->stack); + } + + if (getenv ("PRINT_SHORT_OPERANDS")[0] < '2') + { + dbuf_append_char (dbuf, '{'); + dbuf_printTypeChain (operandType (op), dbuf); + if (SPIL_LOC (op) && IS_ITEMP (op)) + dbuf_printf (dbuf, "}{ sir@ %s", SPIL_LOC (op)->rname); + dbuf_append_char (dbuf, '}'); + } + + /* if assigned to registers */ + if (OP_SYMBOL (op)->nRegs) + { + if (OP_SYMBOL (op)->isspilt) + { + if (!OP_SYMBOL (op)->remat) + if (OP_SYMBOL (op)->usl.spillLoc) + dbuf_printf (dbuf, "[%s]", (OP_SYMBOL (op)->usl.spillLoc->rname[0] ? + OP_SYMBOL (op)->usl.spillLoc->rname : OP_SYMBOL (op)->usl.spillLoc->name)); + else + dbuf_append_str (dbuf, "[err]"); + else + dbuf_append_str (dbuf, "[remat]"); + } + else + { + int i; + dbuf_append_char (dbuf, '['); + for (i = 0; i < OP_SYMBOL (op)->nRegs; i++) + dbuf_printf (dbuf, "%s ", port->getRegName (OP_SYMBOL (op)->regs[i])); + dbuf_append_char (dbuf, ']'); + } + } +//#endif /* } */ + } + break; + + case TYPE: + dbuf_append_char (dbuf, '('); + dbuf_printTypeChain (OP_TYPE (op), dbuf); + dbuf_append_char (dbuf, ')'); + break; + } + + return 0; +} + + +/*-----------------------------------------------------------------*/ +/* print functions */ +/*-----------------------------------------------------------------*/ +PRINTFUNC (picGetValueAtAddr) +{ + dbuf_append_char (dbuf, '\t'); + dbuf_printOperand (IC_RESULT (ic), dbuf); + dbuf_append_str (dbuf, " = "); + dbuf_append_str (dbuf, "@["); + dbuf_printOperand (IC_LEFT (ic), dbuf); + if (IC_RIGHT (ic)) + { + dbuf_append_str (dbuf, " + "); + dbuf_printOperand (IC_RIGHT (ic), dbuf); + } + dbuf_append_str (dbuf, "]\n"); +} + +PRINTFUNC (picSetValueAtAddr) +{ + dbuf_append_char (dbuf, '\t'); + dbuf_append_str (dbuf, "*["); + dbuf_printOperand (IC_LEFT (ic), dbuf); + dbuf_append_str (dbuf, "] = "); + dbuf_printOperand (IC_RIGHT (ic), dbuf); + dbuf_append_char (dbuf, '\n'); +} + +PRINTFUNC (picAddrOf) +{ + dbuf_append_char (dbuf, '\t'); + dbuf_printOperand (IC_RESULT (ic), dbuf); + if (IS_ITEMP (IC_LEFT (ic))) + dbuf_append_str (dbuf, " = "); + else + dbuf_append_str (dbuf, " = &["); + dbuf_printOperand (IC_LEFT (ic), dbuf); + if (IC_RIGHT (ic)) + { + if (IS_ITEMP (IC_LEFT (ic))) + dbuf_append_str (dbuf, " offsetAdd "); + else + dbuf_append_str (dbuf, " , "); + dbuf_printOperand (IC_RIGHT (ic), dbuf); + } + if (IS_ITEMP (IC_LEFT (ic))) + dbuf_append_char (dbuf, '\n'); + else + dbuf_append_str (dbuf, "]\n"); +} + +PRINTFUNC (picJumpTable) +{ + symbol *sym; + + dbuf_append_char (dbuf, '\t'); + dbuf_printf (dbuf, "%s\t", s); + dbuf_printOperand (IC_JTCOND (ic), dbuf); + for (sym = setFirstItem (IC_JTLABELS (ic)); sym; sym = setNextItem (IC_JTLABELS (ic))) + dbuf_printf (dbuf, "; %s", sym->name); + dbuf_append_char (dbuf, '\n'); +} + +PRINTFUNC (picGeneric) +{ + dbuf_append_char (dbuf, '\t'); + dbuf_printOperand (IC_RESULT (ic), dbuf); + dbuf_append_str (dbuf, " = "); + dbuf_printOperand (IC_LEFT (ic), dbuf); + dbuf_printf (dbuf, " %s ", s); + dbuf_printOperand (IC_RIGHT (ic), dbuf); + dbuf_append_char (dbuf, '\n'); +} + +PRINTFUNC (picGenericOne) +{ + dbuf_append_char (dbuf, '\t'); + if (IC_RESULT (ic)) + { + dbuf_printOperand (IC_RESULT (ic), dbuf); + dbuf_append_str (dbuf, " = "); + } + + if (IC_LEFT (ic)) + { + dbuf_printf (dbuf, "%s ", s); + dbuf_printOperand (IC_LEFT (ic), dbuf); + } + + if (!IC_RESULT (ic) && !IC_LEFT (ic)) + dbuf_append_str (dbuf, s); + + if (ic->op == SEND || ic->op == RECEIVE) + { + dbuf_printf (dbuf, "{argreg = %d}", ic->argreg); + } + if (ic->op == IPUSH) + { + dbuf_printf (dbuf, "{parmPush = %d}", ic->parmPush); + } + dbuf_append_char (dbuf, '\n'); +} + +PRINTFUNC (picCast) +{ + dbuf_append_char (dbuf, '\t'); + dbuf_printOperand (IC_RESULT (ic), dbuf); + dbuf_append_str (dbuf, " = "); + dbuf_printOperand (IC_LEFT (ic), dbuf); + dbuf_printOperand (IC_RIGHT (ic), dbuf); + dbuf_append_char (dbuf, '\n'); +} + + +PRINTFUNC (picAssign) +{ + dbuf_append_char (dbuf, '\t'); + + if (IC_RESULT (ic)->isaddr && IS_ITEMP (IC_RESULT (ic))) + dbuf_append_str (dbuf, "*("); + + dbuf_printOperand (IC_RESULT (ic), dbuf); + + if (IC_RESULT (ic)->isaddr && IS_ITEMP (IC_RESULT (ic))) + dbuf_append_char (dbuf, ')'); + + dbuf_printf (dbuf, " %s ", s); + dbuf_printOperand (IC_RIGHT (ic), dbuf); + + dbuf_append_char (dbuf, '\n'); +} + +PRINTFUNC (picLabel) +{ + dbuf_printf (dbuf, " %s($%d) :\n", IC_LABEL (ic)->name, IC_LABEL (ic)->key); +} + +PRINTFUNC (picGoto) +{ + dbuf_append_char (dbuf, '\t'); + dbuf_printf (dbuf, " goto %s($%d)\n", IC_LABEL (ic)->name, IC_LABEL (ic)->key); +} + +PRINTFUNC (picIfx) +{ + dbuf_append_char (dbuf, '\t'); + dbuf_append_str (dbuf, "if "); + dbuf_printOperand (IC_COND (ic), dbuf); + + if (!IC_TRUE (ic)) + dbuf_printf (dbuf, " == 0 goto %s($%d)\n", IC_FALSE (ic)->name, IC_FALSE (ic)->key); + else + { + dbuf_printf (dbuf, " != 0 goto %s($%d)", IC_TRUE (ic)->name, IC_TRUE (ic)->key); + if (IC_FALSE (ic)) + dbuf_printf (dbuf, "; zzgoto %s\n", IC_FALSE (ic)->name); + dbuf_append_char (dbuf, '\n'); + } +} + +PRINTFUNC (picInline) +{ + dbuf_append_str (dbuf, IC_INLINE (ic)); +} + +PRINTFUNC (picReceive) +{ + dbuf_printOperand (IC_RESULT (ic), dbuf); + dbuf_printf (dbuf, " = %s ", s); + dbuf_printOperand (IC_LEFT (ic), dbuf); + dbuf_append_char (dbuf, '\n'); +} + +PRINTFUNC (picDummyRead) +{ + dbuf_append_char (dbuf, '\t'); + dbuf_printf (dbuf, "%s ", s); + dbuf_printOperand (IC_RIGHT (ic), dbuf); + dbuf_append_char (dbuf, '\n'); +} + +PRINTFUNC (picCritical) +{ + dbuf_append_char (dbuf, '\t'); + if (IC_RESULT (ic)) + dbuf_printOperand (IC_RESULT (ic), dbuf); + else + dbuf_append_str (dbuf, "(stack)"); + dbuf_printf (dbuf, " = %s ", s); + dbuf_append_char (dbuf, '\n'); +} + +PRINTFUNC (picEndCritical) +{ + dbuf_append_char (dbuf, '\t'); + dbuf_printf (dbuf, "%s = ", s); + if (IC_RIGHT (ic)) + dbuf_printOperand (IC_RIGHT (ic), dbuf); + else + dbuf_append_str (dbuf, "(stack)"); + dbuf_append_char (dbuf, '\n'); +} + +/*-----------------------------------------------------------------*/ +/* piCode - prints one iCode */ +/*-----------------------------------------------------------------*/ +int +piCode (void *item, FILE * of) +{ + iCode *ic = item; + iCodeTable *icTab; + struct dbuf_s dbuf; + + if (!of) + of = stdout; + + icTab = getTableEntry (ic->op); + fprintf (of, "%s(%d:%d:%d:%d:%d:%d)\t", ic->filename, ic->lineno, ic->seq, ic->key, ic->depth, ic->supportRtn, ic->block); + dbuf_init (&dbuf, 1024); + icTab->iCodePrint (&dbuf, ic, icTab->printName); + dbuf_write_and_destroy (&dbuf, of); + return 1; +} + +void +PICC (iCode * ic) +{ + printiCChain (ic, stdout); +} + +/*-----------------------------------------------------------------*/ +/* printiCChain - prints intermediate code for humans */ +/*-----------------------------------------------------------------*/ +void +printiCChain (iCode * icChain, FILE * of) +{ + iCode *loop; + iCodeTable *icTab; + + if (!of) + of = stdout; + for (loop = icChain; loop; loop = loop->next) + { + if ((icTab = getTableEntry (loop->op))) + { + struct dbuf_s dbuf; + + fprintf (of, "%s(l%d:s%d:k%d:d%d:s%d:b%d)\t", + loop->filename, loop->lineno, loop->seq, loop->key, loop->depth, loop->supportRtn, loop->block); + + dbuf_init (&dbuf, 1024); + icTab->iCodePrint (&dbuf, loop, icTab->printName); + dbuf_write_and_destroy (&dbuf, of); + + fflush (of); + } + } +} + + +/*-----------------------------------------------------------------*/ +/* newOperand - allocate, init & return a new iCode */ +/*-----------------------------------------------------------------*/ +operand * +newOperand () +{ + operand *op; + + op = Safe_alloc (sizeof (operand)); + + op->key = 0; + return op; +} + +/*-----------------------------------------------------------------*/ +/* newiCode - create and return a new iCode entry initialised */ +/*-----------------------------------------------------------------*/ +iCode * +newiCode (int op, operand * left, operand * right) +{ + iCode *ic; + + ic = Safe_alloc (sizeof (iCode)); + + ic->seqPoint = seqPoint; + ic->filename = filename; + ic->lineno = lineno; + ic->block = block; + ic->level = scopeLevel; + ic->op = op; + ic->key = iCodeKey++; + IC_LEFT (ic) = left; + IC_RIGHT (ic) = right; + + return ic; +} + +/*-----------------------------------------------------------------*/ +/* newiCode for conditional statements */ +/*-----------------------------------------------------------------*/ +iCode * +newiCodeCondition (operand * condition, symbol * trueLabel, symbol * falseLabel) +{ + iCode *ic; + + if (IS_VOID (operandType (condition))) + { + werror (E_VOID_VALUE_USED); + } + + ic = newiCode (IFX, NULL, NULL); + IC_COND (ic) = condition; + IC_TRUE (ic) = trueLabel; + IC_FALSE (ic) = falseLabel; + return ic; +} + +/*-----------------------------------------------------------------*/ +/* newiCodeLabelGoto - unconditional goto statement| label stmnt */ +/*-----------------------------------------------------------------*/ +iCode * +newiCodeLabelGoto (int op, symbol * label) +{ + iCode *ic; + + ic = newiCode (op, NULL, NULL); + ic->op = op; + ic->label = label; + IC_LEFT (ic) = NULL; + IC_RIGHT (ic) = NULL; + IC_RESULT (ic) = NULL; + return ic; +} + +/*-----------------------------------------------------------------*/ +/* newiTemp - allocate & return a newItemp Variable */ +/*-----------------------------------------------------------------*/ +symbol * +newiTemp (const char *s) +{ + struct dbuf_s dbuf; + symbol *itmp; + + dbuf_init (&dbuf, 128); + if (s) + dbuf_append_str (&dbuf, s); + else + dbuf_printf (&dbuf, "iTemp%d", iTempNum++); + + itmp = newSymbol (dbuf_c_str (&dbuf), 1); + dbuf_destroy (&dbuf); + strncpyz (itmp->rname, itmp->name, SDCC_NAME_MAX); + itmp->isitmp = 1; + + return itmp; +} + +/*-----------------------------------------------------------------*/ +/* newiTempLabel - creates a temp variable label */ +/*-----------------------------------------------------------------*/ +symbol * +newiTempLabel (const char *s) +{ + symbol *itmplbl; + + /* check if this already exists */ + if (s && (itmplbl = findSym (LabelTab, NULL, s))) + return itmplbl; + + if (s) + { + itmplbl = newSymbol (s, 1); + } + else + { + struct dbuf_s dbuf; + + dbuf_init (&dbuf, 128); + dbuf_printf (&dbuf, "iTempLbl%d", iTempLblNum++); + itmplbl = newSymbol (dbuf_c_str (&dbuf), 1); + dbuf_destroy (&dbuf); + } + + itmplbl->isitmp = 1; + itmplbl->islbl = 1; + itmplbl->key = labelKey++; + addSym (LabelTab, itmplbl, itmplbl->name, 0, 0, 0); + return itmplbl; +} + +/*-----------------------------------------------------------------*/ +/* newiTempLoopHeaderLabel - creates a new loop header label */ +/*-----------------------------------------------------------------*/ +symbol * +newiTempLoopHeaderLabel (bool pre) +{ + symbol *itmplbl; + struct dbuf_s dbuf; + + dbuf_init (&dbuf, 128); + dbuf_printf (&dbuf, pre ? "preHeaderLbl%d" : LOOPEXITLBL "%d", iTempLblNum++); + itmplbl = newSymbol (dbuf_c_str (&dbuf), 1); + dbuf_destroy (&dbuf); + + itmplbl->isitmp = 1; + itmplbl->islbl = 1; + itmplbl->key = labelKey++; + addSym (LabelTab, itmplbl, itmplbl->name, 0, 0, 0); + return itmplbl; +} + + +/*-----------------------------------------------------------------*/ +/* initiCode - initialises some iCode related stuff */ +/*-----------------------------------------------------------------*/ +void +initiCode () +{ + +} + +/*-----------------------------------------------------------------*/ +/* copyiCode - make a copy of the iCode given */ +/*-----------------------------------------------------------------*/ +iCode * +copyiCode (iCode * ic) +{ + iCode *nic = newiCode (ic->op, NULL, NULL); + + nic->filename = ic->filename; + nic->lineno = ic->lineno; + nic->block = ic->block; + nic->level = ic->level; + nic->parmBytes = ic->parmBytes; + + /* deal with the special cases first */ + switch (ic->op) + { + case IFX: + IC_COND (nic) = operandFromOperand (IC_COND (ic)); + IC_TRUE (nic) = IC_TRUE (ic); + IC_FALSE (nic) = IC_FALSE (ic); + break; + + case JUMPTABLE: + IC_JTCOND (nic) = operandFromOperand (IC_JTCOND (ic)); + IC_JTLABELS (nic) = IC_JTLABELS (ic); + break; + + case CALL: + case PCALL: + IC_RESULT (nic) = operandFromOperand (IC_RESULT (ic)); + IC_LEFT (nic) = operandFromOperand (IC_LEFT (ic)); + break; + + case INLINEASM: + IC_INLINE (nic) = IC_INLINE (ic); + break; + + case ARRAYINIT: + IC_ARRAYILIST (nic) = IC_ARRAYILIST (ic); + break; + + default: + IC_RESULT (nic) = operandFromOperand (IC_RESULT (ic)); + IC_LEFT (nic) = operandFromOperand (IC_LEFT (ic)); + IC_RIGHT (nic) = operandFromOperand (IC_RIGHT (ic)); + } + + return nic; +} + +/*-----------------------------------------------------------------*/ +/* getTableEntry - gets the table entry for the given operator */ +/*-----------------------------------------------------------------*/ +iCodeTable * +getTableEntry (int oper) +{ + unsigned i; + + for (i = 0; i < (sizeof (codeTable) / sizeof (iCodeTable)); i++) + if (oper == codeTable[i].icode) + return &codeTable[i]; + + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* newiTempOperand - new intermediate temp operand */ +/*-----------------------------------------------------------------*/ +operand * +newiTempOperand (sym_link * type, char throwType) +{ + symbol *itmp; + operand *op = newOperand (); + sym_link *etype; + + op->type = SYMBOL; + itmp = newiTemp (NULL); + + etype = getSpec (type); + + if (IS_LITERAL (etype)) + throwType = 0; + + /* copy the type information */ + if (type) + itmp->etype = getSpec (itmp->type = (throwType ? type : copyLinkChain (type))); + + SPEC_SCLS (itmp->etype) = S_FIXED; + + /* iTemps always live in the default address space */ + if (IS_DECL (itmp->type)) + DCL_PTR_ADDRSPACE (itmp->type) = 0; + else + SPEC_ADDRSPACE (itmp->etype) = 0; + + op->svt.symOperand = itmp; + op->key = itmp->key = ++operandKey; + return op; +} + +/*-----------------------------------------------------------------*/ +/* operandType - returns the type chain for an operand */ +/*-----------------------------------------------------------------*/ +sym_link * +operandType (const operand *op) +{ + wassert (op); + + /* depending on type of operand */ + switch (op->type) + { + case VALUE: + return op->svt.valOperand->type; + + case SYMBOL: + return op->svt.symOperand->type; + + case TYPE: + return op->svt.typeOperand; + + default: + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, " operand type not known "); + assert (0); /* should never come here */ + /* Just to keep the compiler happy */ + return (sym_link *) 0; + } +} + +/*-----------------------------------------------------------------*/ +/* operandSize - returns size of an operand in bytes */ +/*-----------------------------------------------------------------*/ +unsigned int +operandSize (operand * op) +{ + sym_link *type; + + /* if nothing return 0 */ + if (!op) + return 0; + + type = operandType (op); + if (op->aggr2ptr == 2) + type = type->next; + return getSize (type); +} + +/*-----------------------------------------------------------------*/ +/* isParamterToCall - will return 1 if op is a parameter to args */ +/*-----------------------------------------------------------------*/ +int +isParameterToCall (value * args, operand * op) +{ + value *tval = args; + + wassert (IS_SYMOP (op)); + + while (tval) + { + if (tval->sym && isSymbolEqual (OP_SYMBOL (op), tval->sym)) + return 1; + tval = tval->next; + } + return 0; +} + +/*-----------------------------------------------------------------*/ +/* isOperandGlobal - return 1 if operand is a global variable */ +/*-----------------------------------------------------------------*/ +int +isOperandGlobal (const operand *op) +{ + if (!op) + return 0; + + if (IS_ITEMP (op)) + return 0; + + if (IS_SYMOP (op) && + (op->svt.symOperand->level == 0 || IS_STATIC (op->svt.symOperand->etype) || IS_EXTERN (op->svt.symOperand->etype))) + return 1; + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* isOperandVolatile - return 1 if the operand is volatile */ +/*-----------------------------------------------------------------*/ +int +isOperandVolatile (const operand *op, bool chkTemp) +{ + if (!op) + return 0; + + if (IS_ITEMP (op) && !chkTemp) + return 0; + + return IS_VOLATILE (operandType (op)); +} + +/*-----------------------------------------------------------------*/ +/* isOperandLiteral - returns 1 if an operand contains a literal */ +/*-----------------------------------------------------------------*/ +int +isOperandLiteral (const operand *const op) +{ + sym_link *opetype; + + if (!op) + return 0; + + opetype = getSpec (operandType (op)); + + if (IS_LITERAL (opetype)) + return 1; + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* isOperandInFarSpace - will return true if operand is in farSpace */ +/*-----------------------------------------------------------------*/ +bool +isOperandInFarSpace (operand * op) +{ + sym_link *etype; + + if (!op) + return FALSE; + + if (!IS_SYMOP (op)) + return FALSE; + + if (!IS_TRUE_SYMOP (op)) + { + if (SPIL_LOC (op)) + etype = SPIL_LOC (op)->etype; + else + return FALSE; + } + else + { + etype = getSpec (operandType (op)); + } + return (IN_FARSPACE (SPEC_OCLS (etype)) ? TRUE : FALSE); +} + +/*-----------------------------------------------------------------*/ +/* isOperandInPagedSpace - return true if operand is in pagedSpace */ +/*-----------------------------------------------------------------*/ +bool +isOperandInPagedSpace (operand * op) +{ + sym_link *etype; + + if (!op) + return FALSE; + + if (!IS_SYMOP (op)) + return FALSE; + + if (!IS_TRUE_SYMOP (op)) + { + if (SPIL_LOC (op)) + etype = SPIL_LOC (op)->etype; + else + return FALSE; + } + else + { + etype = getSpec (operandType (op)); + } + return (IN_PAGEDSPACE (SPEC_OCLS (etype)) ? TRUE : FALSE); +} + +/*------------------------------------------------------------------*/ +/* isOperandInDirSpace - will return true if operand is in dirSpace */ +/*------------------------------------------------------------------*/ +bool +isOperandInDirSpace (operand * op) +{ + sym_link *etype; + + if (!op) + return FALSE; + + if (!IS_SYMOP (op)) + return FALSE; + + if (!IS_TRUE_SYMOP (op)) + { + if (SPIL_LOC (op)) + etype = SPIL_LOC (op)->etype; + else + return FALSE; + } + else + { + etype = getSpec (operandType (op)); + } + return (IN_DIRSPACE (SPEC_OCLS (etype)) ? TRUE : FALSE); +} + +/*-----------------------------------------------------------------*/ +/* isOperandInBitSpace - will return true if operand is in bitSpace */ +/*-----------------------------------------------------------------*/ +bool +isOperandInBitSpace (operand * op) +{ + sym_link *etype; + + if (!op) + return FALSE; + + if (!IS_SYMOP (op)) + return FALSE; + + if (!IS_TRUE_SYMOP (op)) + { + if (SPIL_LOC (op)) + etype = SPIL_LOC (op)->etype; + else + return FALSE; + } + else + { + etype = getSpec (operandType (op)); + } + return (IN_BITSPACE (SPEC_OCLS (etype)) ? TRUE : FALSE); +} + +/*--------------------------------------------------------------------*/ +/* isOperandInCodeSpace - will return true if operand is in codeSpace */ +/*--------------------------------------------------------------------*/ +bool +isOperandInCodeSpace (operand * op) +{ + sym_link *etype; + + if (!op) + return FALSE; + + if (!IS_SYMOP (op)) + return FALSE; + + etype = getSpec (operandType (op)); + + if (!IS_TRUE_SYMOP (op)) + { + if (SPIL_LOC (op)) + etype = SPIL_LOC (op)->etype; + else + return FALSE; + } + else + { + etype = getSpec (operandType (op)); + } + return (IN_CODESPACE (SPEC_OCLS (etype)) ? TRUE : FALSE); +} + +/*-----------------------------------------------------------------*/ +/* isOperandOnStack - will return true if operand is on stack */ +/*-----------------------------------------------------------------*/ +bool +isOperandOnStack (operand * op) +{ + sym_link *etype; + + if (!op) + return FALSE; + + if (!IS_SYMOP (op)) + return FALSE; + + etype = getSpec (operandType (op)); + if (IN_STACK (etype) || OP_SYMBOL (op)->onStack || (SPIL_LOC (op) && SPIL_LOC (op)->onStack)) + return TRUE; + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* isOclsExpensive - will return true if accesses to an output */ +/* storage class are expensive */ +/*-----------------------------------------------------------------*/ +bool +isOclsExpensive (struct memmap * oclass) +{ + if (port->oclsExpense) + return port->oclsExpense (oclass) > 0; + + /* In the absence of port specific guidance, assume only */ + /* farspace is expensive. */ + return IN_FARSPACE (oclass); +} + +/*-----------------------------------------------------------------*/ +/* isiCodeInFunctionCall - return TRUE if an iCode is between a */ +/* CALL/PCALL and the first IPUSH/SEND associated with the call */ +/*-----------------------------------------------------------------*/ +int +isiCodeInFunctionCall (iCode * ic) +{ + iCode *lic = ic; + + /* Find the next CALL/PCALL */ + while (lic) + { + if (lic->op == CALL || lic->op == PCALL) + break; + lic = lic->next; + } + + if (!lic) + return FALSE; + + /* A function call was found. Scan backwards and see if an */ + /* IPUSH or SEND is encountered */ + while (ic) + { + if (lic != ic && (ic->op == CALL || ic->op == PCALL)) + return FALSE; + if (ic->op == SEND || (ic->op == IPUSH && ic->parmPush)) + return TRUE; + ic = ic->prev; + } + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* operandLitValueUll - unsigned long long value of an operand */ +/*-----------------------------------------------------------------*/ +unsigned long long +operandLitValueUll (const operand * op) +{ + assert (isOperandLiteral (op)); + + return ullFromVal (OP_VALUE_CONST (op)); +} + +/*-----------------------------------------------------------------*/ +/* operandLitValue - literal value of an operand */ +/*-----------------------------------------------------------------*/ +double +operandLitValue (const operand * op) +{ + assert (isOperandLiteral (op)); + + return floatFromVal (OP_VALUE_CONST (op)); +} + +extern bool regalloc_dry_run; + +/*-----------------------------------------------------------------*/ +/* getBuiltInParms - returns parameters to a builtin function */ +/*-----------------------------------------------------------------*/ +iCode * +getBuiltinParms (iCode * fic, int *pcount, operand ** parms) +{ + sym_link *ftype; + iCode *ic = fic; + + *pcount = 0; + /* builtin function uses only SEND for parameters */ + while (ic->op != CALL) + { + assert (ic->op == SEND && ic->builtinSEND); + if(!regalloc_dry_run || ic != fic) + ic->generated = 1; /* mark the icode as generated */ + parms[*pcount] = IC_LEFT (ic); + ic = ic->next; + (*pcount)++; + } + + ic->generated = 1; + /* make sure this is a builtin function call */ + assert (IS_SYMOP (IC_LEFT (ic))); + ftype = operandType (IC_LEFT (ic)); + assert (IFFUNC_ISBUILTIN (ftype)); + return ic; +} + +/*-----------------------------------------------------------------*/ +/* operandOperation - performs operations on operands */ +/*-----------------------------------------------------------------*/ +operand * +operandOperation (operand * left, operand * right, int op, sym_link * type) +{ + sym_link *let, *ret = NULL; + operand *retval = (operand *) 0; + + assert (isOperandLiteral (left)); + let = getSpec (operandType (left)); + if (right) + { + assert (isOperandLiteral (right)); + ret = getSpec (operandType (right)); + } + + /* FIXME: most of these are not long long safe yet */ + switch (op) + { + case '+': + retval = operandFromValue (valCastLiteral (type, operandLitValue (left) + operandLitValue (right), operandLitValueUll (left) + operandLitValueUll (right))); + break; + case '-': + retval = operandFromValue (valCastLiteral (type, operandLitValue (left) - operandLitValue (right), operandLitValueUll (left) - operandLitValueUll (right))); + break; + case '*': + /* + retval = operandFromValue (valCastLiteral (type, + operandLitValue (left) * + operandLitValue (right))); + This could be all we've to do, but with gcc we've to take care about + overflows. Two examples: + ULONG_MAX * ULONG_MAX doesn't fit into a double, some of the least + significant bits are lost (52 in fraction, 63 bits would be + necessary to keep full precision). + If the resulting double value is greater than ULONG_MAX (resp. + USHRT_MAX, ...), then 0 will be assigned to v_ulong (resp. u_uint, ...)! + */ + + /* if it is not a specifier then we can assume that */ + /* it will be an unsigned long */ + if (IS_INT (type) || !IS_SPEC (type)) + { + /* long long is handled here, because it can overflow with double */ + if (IS_LONGLONG (type) || !IS_SPEC (type)) + /* signed and unsigned mul are the same, as long as the precision + of the result isn't bigger than the precision of the operands. */ + retval = operandFromValue (valCastLiteral (type, + operandLitValue (left) * + operandLitValue (right), + operandLitValueUll (left) * + operandLitValueUll (right))); + /* long is handled here, because it can overflow with double */ + else if (IS_LONG (type) || !IS_SPEC (type)) + /* signed and unsigned mul are the same, as long as the precision + of the result isn't bigger than the precision of the operands. */ + retval = operandFromValue (valCastLiteral (type, + (TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) * + (TYPE_TARGET_ULONG) double2ul (operandLitValue (right)), + (TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) * + (TYPE_TARGET_ULONG) double2ul (operandLitValue (right)))); + else if (IS_UNSIGNED (type)) /* unsigned int */ + { + /* unsigned int is handled here in order to detect overflow */ + TYPE_TARGET_ULONG ul = (TYPE_TARGET_UINT) double2ul (operandLitValue (left)) * + (TYPE_TARGET_UINT) double2ul (operandLitValue (right)); + + retval = operandFromValue (valCastLiteral (type, (TYPE_TARGET_UINT) ul, (TYPE_TARGET_UINT) ul)); + if (ul != (TYPE_TARGET_UINT) ul) + werror (W_INT_OVL); + } + else /* signed int */ + { + /* signed int is handled here in order to detect overflow */ + TYPE_TARGET_LONG l = (TYPE_TARGET_INT) operandLitValue (left) * (TYPE_TARGET_INT) operandLitValue (right); + + retval = operandFromValue (valCastLiteral (type, (TYPE_TARGET_INT) l, (TYPE_TARGET_INT) l)); + if (l != (TYPE_TARGET_INT) l) + werror (W_INT_OVL); + } + } + else + /* all others go here: */ + retval = operandFromValue (valCastLiteral (type, operandLitValue (left) * operandLitValue (right), operandLitValueUll (left) * operandLitValueUll (right))); + break; + case '/': + if ((TYPE_TARGET_ULONG) double2ul (operandLitValue (right)) == 0 && operandLitValueUll (right) == 0) + { + werror (E_DIVIDE_BY_ZERO); + retval = right; + break; + } + if (IS_UNSIGNED (type)) + { + SPEC_USIGN (let) = 1; + SPEC_USIGN (ret) = 1; + if (IS_LONGLONG (type)) + retval = operandFromValue (valCastLiteral (type, + 0.0, + operandLitValueUll (left) / + operandLitValueUll (right))); + else + retval = operandFromValue (valCastLiteral (type, + (TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) / + (TYPE_TARGET_ULONG) double2ul (operandLitValue (right)), + (TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) / + (TYPE_TARGET_ULONG) double2ul (operandLitValue (right)))); + } + else + retval = operandFromValue (valCastLiteral (type, operandLitValue (left) / operandLitValue (right), operandLitValueUll (left) / operandLitValueUll (right))); + break; + case '%': + if ((TYPE_TARGET_ULONG) double2ul (operandLitValue (right)) == 0 && operandLitValueUll (right) == 0) + { + werror (E_DIVIDE_BY_ZERO); + retval = right; + } + else + { + if (IS_UNSIGNED (type)) + { + if (IS_LONGLONG (type)) + retval = operandFromValue (valCastLiteral (type, + 0.0, + operandLitValueUll (left) % + operandLitValueUll (right))); + else + retval = operandFromLit ((TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) % (TYPE_TARGET_ULONG) double2ul (operandLitValue (right))); + } + else + retval = operandFromLit ((TYPE_TARGET_LONG) operandLitValue (left) % (TYPE_TARGET_LONG) operandLitValue (right)); + } + break; + case LEFT_OP: + /* The number of left shifts is always unsigned. Signed doesn't make + sense here. Shifting by a negative number is impossible. */ + if (IS_LONGLONG (type)) + retval = operandFromValue (valCastLiteral (type, + (operandLitValueUll (left) << + operandLitValueUll (right)), + (operandLitValueUll (left) << + operandLitValueUll (right)))); + else + retval = operandFromValue (valCastLiteral (type, + ((TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) << + (TYPE_TARGET_ULONG) double2ul (operandLitValue (right))), + ((TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) << + (TYPE_TARGET_ULONG) double2ul (operandLitValue (right))))); + break; + case RIGHT_OP: + /* The number of right shifts is always unsigned. Signed doesn't make + sense here. Shifting by a negative number is impossible. */ + retval = operandFromValue (valRecastLitVal (type, valShift (OP_VALUE (left), OP_VALUE (right), 0))); + break; + case EQ_OP: + if (IS_FLOAT (let) || IS_FLOAT (ret)) + { + retval = operandFromLit (operandLitValue (left) == operandLitValue (right)); + } + else if (IS_FIXED16X16 (let) || IS_FIXED16X16 (ret)) + { + retval = operandFromLit (operandLitValue (left) == operandLitValue (right)); + } + else if (IS_PTR (operandType (left)) || IS_PTR (operandType (right))) + { + retval = operandFromLit (operandLitValue (left) == operandLitValue (right)); + } + else + { + /* this op doesn't care about signedness */ + TYPE_TARGET_ULONG l, r; + + l = (TYPE_TARGET_ULONG) double2ul (operandLitValue (left)); + r = (TYPE_TARGET_ULONG) double2ul (operandLitValue (right)); + /* In order to correctly compare 'signed int' and 'unsigned int' it's + neccessary to strip them to 16 bit. + Literals are reduced to their cheapest type, therefore left and + right might have different types. It's neccessary to find a + common type: int (used for char too) or long */ + if (!IS_LONG (let) && !IS_LONG (ret)) + { + r = (TYPE_TARGET_UINT) r; + l = (TYPE_TARGET_UINT) l; + } + retval = operandFromLit (l == r); + } + break; + case '<': + retval = operandFromLit (operandLitValue (left) < operandLitValue (right)); + break; + case LE_OP: + retval = operandFromLit (operandLitValue (left) <= operandLitValue (right)); + break; + case NE_OP: + retval = operandFromLit (operandLitValue (left) != operandLitValue (right)); + break; + case '>': + retval = operandFromLit (operandLitValue (left) > operandLitValue (right)); + break; + case GE_OP: + retval = operandFromLit (operandLitValue (left) >= operandLitValue (right)); + break; + case BITWISEAND: + retval = operandFromValue (valCastLiteral (type, + (TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) & + (TYPE_TARGET_ULONG) double2ul (operandLitValue (right)), + (TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) & + (TYPE_TARGET_ULONG) double2ul (operandLitValue (right)))); + break; + case '|': + retval = operandFromValue (valCastLiteral (type, + (TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) | + (TYPE_TARGET_ULONG) double2ul (operandLitValue (right)), + (TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) | + (TYPE_TARGET_ULONG) double2ul (operandLitValue (right)))); + break; + case '^': + retval = operandFromValue (valCastLiteral (type, + (TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) ^ + (TYPE_TARGET_ULONG) double2ul (operandLitValue (right)), + (TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) ^ + (TYPE_TARGET_ULONG) double2ul (operandLitValue (right)))); + break; + case AND_OP: + retval = operandFromLit (operandLitValue (left) && operandLitValue (right)); + break; + case OR_OP: + retval = operandFromLit (operandLitValue (left) || operandLitValue (right)); + break; + case RRC: + { + TYPE_TARGET_ULONG i = (TYPE_TARGET_ULONG) double2ul (operandLitValue (left)); + + retval = operandFromLit ((i >> (getSize (operandType (left)) * 8 - 1)) | (i << 1)); + } + break; + case RLC: + { + TYPE_TARGET_ULONG i = (TYPE_TARGET_ULONG) double2ul (operandLitValue (left)); + + retval = operandFromLit ((i << (getSize (operandType (left)) * 8 - 1)) | (i >> 1)); + } + break; + case GETABIT: + retval = operandFromLit (((TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) >> + (TYPE_TARGET_ULONG) double2ul (operandLitValue (right))) & 1); + break; + case GETBYTE: + retval = operandFromLit (((TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) >> + (TYPE_TARGET_ULONG) double2ul (operandLitValue (right)) & 0xFF)); + break; + case GETWORD: + retval = operandFromLit (((TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) >> + (TYPE_TARGET_ULONG) double2ul (operandLitValue (right)) & 0xFFFF)); + break; + + case GETHBIT: + retval = operandFromLit (((TYPE_TARGET_ULONG) double2ul (operandLitValue (left)) >> ((getSize (let) * 8) - 1)) & 1); + break; + + case UNARYMINUS: + retval = operandFromValue (valCastLiteral (type, -1 * operandLitValue (left), (-1ll) * operandLitValueUll (left))); + break; + + case '~': + retval = operandFromValue (valCastLiteral (type, ~((TYPE_TARGET_ULONG) double2ul (operandLitValue (left))), ~((TYPE_TARGET_ULONGLONG) operandLitValueUll (left)))); + break; + + case '!': + retval = operandFromLit (!operandLitValue (left)); + break; + + case ADDRESS_OF: + retval = operandFromValue (valCastLiteral (type, operandLitValue (left), (TYPE_TARGET_ULONGLONG) operandLitValueUll (left))); + break; + + default: + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, " operandOperation invalid operator "); + assert (0); + } + + return retval; +} + +/*-----------------------------------------------------------------*/ +/* isOperandEqual - compares two operand & return 1 if they are = */ +/*-----------------------------------------------------------------*/ +int +isOperandEqual (const operand * left, const operand * right) +{ + /* if the pointers are equal then they are equal */ + if (left == right) + return 1; + + /* if either of them is null then false */ + if (!left || !right) + return 0; + + if (left->type != right->type) + return 0; + + if (IS_SYMOP (left) && IS_SYMOP (right)) + return left->key == right->key; + + /* if types are the same */ + switch (left->type) + { + case SYMBOL: + return isSymbolEqual (left->svt.symOperand, right->svt.symOperand); + case VALUE: + return (compareType (left->svt.valOperand->type, right->svt.valOperand->type) && + (!IS_FLOAT (getSpec (left->svt.valOperand->type)) ? + (operandLitValueUll (left) == operandLitValueUll (right)) : + (operandLitValue (left) == operandLitValue (right)))); + case TYPE: + if (compareType (left->svt.typeOperand, right->svt.typeOperand) == 1) + return 1; + } + + return 0; +} + +/*-------------------------------------------------------------------*/ +/* isiCodeEqual - compares two iCodes are equal, returns true if yes */ +/*-------------------------------------------------------------------*/ +int +isiCodeEqual (iCode * left, iCode * right) +{ + /* if the same pointer */ + if (left == right) + return 1; + + /* if either of them null */ + if (!left || !right) + return 0; + + /* if operand are the same */ + if (left->op == right->op) + { + /* compare all the elements depending on type */ + if (left->op != IFX) + { + if (!isOperandEqual (IC_LEFT (left), IC_LEFT (right))) + return 0; + if (!isOperandEqual (IC_RIGHT (left), IC_RIGHT (right))) + return 0; + } + else + { + if (!isOperandEqual (IC_COND (left), IC_COND (right))) + return 0; + if (!isSymbolEqual (IC_TRUE (left), IC_TRUE (right))) + return 0; + if (!isSymbolEqual (IC_FALSE (left), IC_FALSE (right))) + return 0; + } + + return 1; + } + return 0; +} + +/*-----------------------------------------------------------------*/ +/* newiTempFromOp - create a temp Operand with same attributes */ +/*-----------------------------------------------------------------*/ +operand * +newiTempFromOp (operand * op) +{ + operand *nop; + + if (!op) + return NULL; + + if (!IS_ITEMP (op)) + return op; + + nop = newiTempOperand (operandType (op), TRUE); + nop->isaddr = op->isaddr; + nop->isvolatile = op->isvolatile; + nop->isGlobal = op->isGlobal; + nop->isLiteral = op->isLiteral; + nop->usesDefs = op->usesDefs; + nop->isParm = op->isParm; + return nop; +} + +/*-----------------------------------------------------------------*/ +/* operand from operand - creates an operand holder for the type */ +/*-----------------------------------------------------------------*/ +operand * +operandFromOperand (operand * op) +{ + operand *nop; + + if (!op) + return NULL; + nop = newOperand (); + nop->type = op->type; + nop->isaddr = op->isaddr; + nop->key = op->key; + nop->isvolatile = op->isvolatile; + nop->isGlobal = op->isGlobal; + nop->isLiteral = op->isLiteral; + nop->usesDefs = op->usesDefs; + nop->isParm = op->isParm; + nop->isConstElimnated = op->isConstElimnated; + + switch (nop->type) + { + case SYMBOL: + nop->svt.symOperand = op->svt.symOperand; + break; + case VALUE: + nop->svt.valOperand = op->svt.valOperand; + break; + case TYPE: + nop->svt.typeOperand = op->svt.typeOperand; + break; + } + + return nop; +} + +/*-----------------------------------------------------------------*/ +/* opFromOpWithDU - makes a copy of the operand and DU chains */ +/*-----------------------------------------------------------------*/ +operand * +opFromOpWithDU (operand * op, bitVect * defs, bitVect * uses) +{ + operand *nop = operandFromOperand (op); + + if (nop->type == SYMBOL) + { + OP_DEFS (nop) = bitVectCopy (defs); + OP_USES (nop) = bitVectCopy (uses); + } + + return nop; +} + +/*-----------------------------------------------------------------*/ +/* operandFromSymbol - creates an operand from a symbol */ +/*-----------------------------------------------------------------*/ +operand * +operandFromSymbol (symbol * sym) +{ + operand *op; + iCode *ic; + int ok = 1; + /* if the symbol's type is a literal */ + /* then it is an enumerator type */ + if (IS_LITERAL (sym->etype) && SPEC_ENUM (sym->etype)) + return operandFromValue (valFromType (sym->etype)); + + if (!sym->key) + sym->key = ++operandKey; + + /* if this an implicit variable, means struct/union */ + /* member so just return it */ + if (sym->implicit || IS_FUNC (sym->type)) + { + op = newOperand (); + op->type = SYMBOL; + op->svt.symOperand = sym; + op->key = sym->key; + op->isvolatile = isOperandVolatile (op, TRUE); + op->isGlobal = isOperandGlobal (op); + return op; + } + + /* under the following conditions create a + register equivalent for a local symbol */ + if (sym->level && sym->etype && SPEC_OCLS (sym->etype) && + (IN_FARSPACE (SPEC_OCLS (sym->etype)) && !TARGET_HC08_LIKE && (!(options.model == MODEL_FLAT24))) && options.stackAuto == 0) + { + ok = 0; + } + + if (!IS_AGGREGATE (sym->type) && /* not an aggregate */ + !IS_FUNC (sym->type) && /* not a function */ + !sym->_isparm && /* not a parameter */ + IS_AUTO (sym) && /* is a local auto variable */ + !sym->addrtaken && /* whose address has not been taken */ + !sym->reqv && /* does not already have a reg equivalence */ + !IS_VOLATILE (sym->etype) && /* not declared as volatile */ + !sym->islbl && /* not a label */ + !(TARGET_HC08_LIKE && (getSize (sym->type) > 2)) && /* will fit in regs */ + ok /* farspace check */ + ) + { + /* we will use it after all optimizations + and before liveRange calculation */ + sym->reqv = newiTempOperand (sym->type, 0); + sym->reqv->key = sym->key; + OP_SYMBOL (sym->reqv)->prereqv = sym; + OP_SYMBOL (sym->reqv)->key = sym->key; + OP_SYMBOL (sym->reqv)->isreqv = 1; + OP_SYMBOL (sym->reqv)->islocal = 1; + OP_SYMBOL (sym->reqv)->onStack = sym->onStack; + SPIL_LOC (sym->reqv) = sym; + } + + if (!IS_AGGREGATE (sym->type)) + { + op = newOperand (); + op->type = SYMBOL; + op->svt.symOperand = sym; + op->isaddr = 1; + op->key = sym->key; + op->isvolatile = isOperandVolatile (op, TRUE); + op->isGlobal = isOperandGlobal (op); + op->isPtr = IS_PTR (operandType (op)); + op->isParm = sym->_isparm; + return op; + } + + /* create :- */ + /* itemp = &[_symbol] */ + + ic = newiCode (ADDRESS_OF, newOperand (), operandFromLit (0)); + IC_LEFT (ic)->type = SYMBOL; + IC_LEFT (ic)->svt.symOperand = sym; + IC_LEFT (ic)->key = sym->key; + (IC_LEFT (ic))->isvolatile = isOperandVolatile (IC_LEFT (ic), TRUE); + (IC_LEFT (ic))->isGlobal = isOperandGlobal (IC_LEFT (ic)); + IC_LEFT (ic)->isPtr = IS_PTR (operandType (IC_LEFT (ic))); + + /* create result */ + IC_RESULT (ic) = newiTempOperand (sym->type, 0); + if (IS_ARRAY (sym->type)) + { + IC_RESULT (ic) = geniCodeArray2Ptr (IC_RESULT (ic)); + } + else + { + IC_RESULT (ic)->isaddr = (!IS_AGGREGATE (sym->type)); + } + + ADDTOCHAIN (ic); + + return IC_RESULT (ic); +} + +/*-----------------------------------------------------------------*/ +/* operandFromValue - creates an operand from value */ +/*-----------------------------------------------------------------*/ +operand * +operandFromValue (value *val) +{ + operand *op; + + /* if this is a symbol then do the symbol thing */ + if (val->sym) + return operandFromSymbol (val->sym); + + /* this is not a symbol */ + op = newOperand (); + op->type = VALUE; + op->svt.valOperand = val; + op->isLiteral = isOperandLiteral (op); + return op; +} + +/*-----------------------------------------------------------------*/ +/* operandFromLink - operand from typeChain */ +/*-----------------------------------------------------------------*/ +operand * +operandFromLink (sym_link * type) +{ + operand *op; + + /* operand from sym_link */ + if (!type) + return NULL; + + op = newOperand (); + op->type = TYPE; + op->svt.typeOperand = copyLinkChain (type); + return op; +} + +/*-----------------------------------------------------------------*/ +/* operandFromLit - makes an operand from a literal value */ +/*-----------------------------------------------------------------*/ +operand * +operandFromLit (double i) +{ + return operandFromValue (valueFromLit (i)); +} + +/*-----------------------------------------------------------------*/ +/* operandFromAst - creates an operand from an ast */ +/*-----------------------------------------------------------------*/ +operand * +operandFromAst (ast * tree, int lvl) +{ + if (!tree) + return NULL; + + /* depending on type do */ + switch (tree->type) + { + case EX_OP: + return ast2iCode (tree, lvl + 1); + break; + + case EX_VALUE: + return operandFromValue (tree->opval.val); + break; + + case EX_LINK: + return operandFromLink (tree->opval.lnk); + break; + + default: + assert (0); + } + + /* Just to keep the compiler happy */ + return (operand *) 0; +} + +/*-----------------------------------------------------------------*/ +/* setOperandType - sets the operand's type to the given type */ +/*-----------------------------------------------------------------*/ +void +setOperandType (operand * op, sym_link * type) +{ + /* depending on the type of operand */ + switch (op->type) + { + case VALUE: + op->svt.valOperand->etype = getSpec (op->svt.valOperand->type = copyLinkChain (type)); + return; + + case SYMBOL: + if (op->svt.symOperand->isitmp) + { + op->svt.symOperand->etype = getSpec (op->svt.symOperand->type = copyLinkChain (type)); + if (IS_SPEC (op->svt.symOperand->type)) + { + SPEC_SCLS (op->svt.symOperand->etype) = S_REGISTER; + SPEC_OCLS (op->svt.symOperand->etype) = reg; + } + } + else + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "attempt to modify type of source"); + return; + + case TYPE: + op->svt.typeOperand = copyLinkChain (type); + return; + } +} + +/*-----------------------------------------------------------------*/ +/* Get size in byte of ptr need to access an array */ +/*-----------------------------------------------------------------*/ +static unsigned int +getArraySizePtr (operand * op) +{ + sym_link *ltype = operandType (op); + + if (IS_PTR (ltype)) + { + int size = getSize (ltype); + return ((IS_GENPTR (ltype) && GPTRSIZE > FARPTRSIZE) ? (size - 1) : size); + } + + if (IS_ARRAY (ltype)) + { + sym_link *letype = getSpec (ltype); + switch (PTR_TYPE (SPEC_OCLS (letype))) + { + case IPOINTER: + case PPOINTER: + case POINTER: + return (NEARPTRSIZE); + case EEPPOINTER: + case FPOINTER: + case CPOINTER: + case FUNCTION: + return (FARPTRSIZE); + case GPOINTER: + if (GPTRSIZE > FARPTRSIZE) + return (GPTRSIZE - 1); + else + return (FARPTRSIZE); + + default: + return (FARPTRSIZE); + } + } + return (FARPTRSIZE); +} + +/*-----------------------------------------------------------------*/ +/* perform "usual unary conversions" */ +/*-----------------------------------------------------------------*/ +#if 0 +static operand * +usualUnaryConversions (operand * op) +{ + if (IS_INTEGRAL (operandType (op))) + { + if (getSize (operandType (op)) < (unsigned int) INTSIZE) + { + /* Widen to int. */ + return geniCodeCast (INTTYPE, op, TRUE); + } + } + return op; +} +#endif + +/*-----------------------------------------------------------------*/ +/* perform "usual binary conversions" */ +/*-----------------------------------------------------------------*/ + +static sym_link * +usualBinaryConversions (operand ** op1, operand ** op2, RESULT_TYPE resultType, int op) +{ + sym_link *ctype; + sym_link *rtype = operandType (*op2); + sym_link *ltype = operandType (*op1); + + ctype = computeType (ltype, rtype, resultType, op); + + switch (op) + { + case '*': + case '/': + case '%': + if (IS_CHAR (getSpec (ltype)) && IS_CHAR (getSpec (rtype))) + { + /* one byte operations: keep signedness for code generator */ + return ctype; + } + break; + default: + break; + } + + *op1 = geniCodeCast (ctype, *op1, TRUE); + *op2 = geniCodeCast (ctype, *op2, TRUE); + + return ctype; +} + +/*-----------------------------------------------------------------*/ +/* geniCodeValueAtAddress - generate intermediate code for value */ +/* at address */ +/*-----------------------------------------------------------------*/ +operand * +geniCodeRValue (operand * op, bool force) +{ + iCode *ic; + sym_link *type = operandType (op); + sym_link *etype = getSpec (type); + + /* if this is an array & already */ + /* a resolved address then return this */ + if ((IS_ARRAY (type) && !IS_FUNCPTR (type->next)) || IS_STRUCT (type) || (IS_PTR (type) && !force && !op->isaddr)) + return operandFromOperand (op); + + /* if this is not an address then must be */ + /* rvalue already so return this one */ + if (!op->isaddr) + return op; + + /* if this is not a temp symbol then */ + if (!IS_ITEMP (op) && !force && !(IN_FARSPACE (SPEC_OCLS (etype)) && !TARGET_HC08_LIKE)) + { + op = operandFromOperand (op); + op->isaddr = 0; + return op; + } + + if (IS_SPEC (type) && + IS_TRUE_SYMOP (op) && (!(IN_FARSPACE (SPEC_OCLS (etype)) && !TARGET_HC08_LIKE) || (options.model == MODEL_FLAT24))) + { + op = operandFromOperand (op); + op->isaddr = 0; + return op; + } + + ic = newiCode (GET_VALUE_AT_ADDRESS, op, operandFromLit (0)); + if ((IS_PTR (type) && op->isaddr && force) || IS_ARRAY (type)) + type = type->next; + + type = copyLinkChain (type); + + IC_RESULT (ic) = newiTempOperand (type, 1); + IC_RESULT (ic)->isaddr = 0; + +/* ic->supportRtn = ((IS_GENPTR(type) | op->isGptr) & op->isaddr); */ + + ADDTOCHAIN (ic); + + return IC_RESULT (ic); +} + +/*-----------------------------------------------------------------*/ +/* checkPtrQualifiers - check for lost pointer qualifers */ +/*-----------------------------------------------------------------*/ +static void +checkPtrQualifiers (sym_link * ltype, sym_link * rtype, int warn_const) +{ + if (IS_PTR (ltype) && IS_PTR (rtype) && !IS_FUNCPTR (ltype) && warn_const) + { + if (!IS_CONSTANT (ltype->next) && IS_CONSTANT (rtype->next)) + werror (W_TARGET_LOST_QUALIFIER, "const"); +#if 0 + // disabled because SDCC will make all union fields volatile + // but your ptr to it need not be + if (!IS_VOLATILE (ltype->next) && IS_VOLATILE (rtype->next)) + werror (W_TARGET_LOST_QUALIFIER, "volatile"); +#endif + if (!IS_RESTRICT (ltype->next) && IS_RESTRICT (rtype->next)) + werror (W_TARGET_LOST_QUALIFIER, "restrict"); + } +} + +/*-----------------------------------------------------------------*/ +/* geniCodeCast - changes the value from one type to another */ +/*-----------------------------------------------------------------*/ +static operand * +geniCodeCast (sym_link *type, operand *op, bool implicit) +{ + iCode *ic; + sym_link *optype; + sym_link *opetype = getSpec (optype = operandType (op)); + sym_link *restype; + + /* one of them has size zero then error */ + if (IS_VOID (optype)) + { + werror (E_CAST_ZERO); + return op; + } + + if (IS_ITEMP (op) && IS_ARRAY (OP_SYMBOL (op)->type)) + { + geniCodeArray2Ptr (op); + } + + /* if the operand is already the desired type then do nothing */ + if (compareType (type, optype) == 1) + { + if (IS_PTR (type) && IS_CONSTANT (opetype) && !IS_CONSTANT (getSpec(type))) + op->isConstElimnated = 1; + return op; + } + + /* if this is a literal then just change the type & return */ + if (IS_LITERAL (opetype) && op->type == VALUE && !IS_PTR (type) && !IS_PTR (optype)) + { + return operandFromValue (valCastLiteral (type, operandLitValue (op), operandLitValueUll (op))); + } + + checkPtrCast (type, optype, implicit, IS_LITERAL (opetype) && !operandLitValue (op)); + + ic = newiCode (CAST, operandFromLink (type), geniCodeRValue (op, FALSE)); + IC_RESULT (ic) = newiTempOperand (type, 0); + + restype = getSpec (operandType (IC_RESULT (ic))); + /* Convert cast to _Bool bitfield members to casts to _Bool. */ + if (SPEC_NOUN (restype) == V_BBITFIELD) + SPEC_NOUN (restype) = V_BOOL; + + ADDTOCHAIN (ic); + return IC_RESULT (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeLabel - will create a Label */ +/*-----------------------------------------------------------------*/ +void +geniCodeLabel (symbol * label) +{ + iCode *ic; + + ic = newiCodeLabelGoto (LABEL, label); + ADDTOCHAIN (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeGoto - will create a Goto */ +/*-----------------------------------------------------------------*/ +void +geniCodeGoto (symbol * label) +{ + iCode *ic; + + ic = newiCodeLabelGoto (GOTO, label); + ADDTOCHAIN (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeMultiply - gen intermediate code for multiplication */ +/*-----------------------------------------------------------------*/ +static operand * +geniCodeMultiply (operand * left, operand * right, RESULT_TYPE resultType) +{ + iCode *ic; + int p2 = 0; + sym_link *resType; + LRTYPE; + + /* if they are both literal then we know the result */ + if (IS_LITERAL (letype) && IS_LITERAL (retype)) + return operandFromValue (valMult (OP_VALUE (left), OP_VALUE (right))); + + if (IS_LITERAL (retype)) + { + p2 = powof2 ((TYPE_TARGET_ULONG) ulFromVal (OP_VALUE (right))); + } + + resType = usualBinaryConversions (&left, &right, resultType, '*'); + rtype = operandType (right); + retype = getSpec (rtype); + ltype = operandType (left); + letype = getSpec (ltype); + + /* if the right is a literal & power of 2 */ + /* then make it a left shift */ + /* code generated for 1 byte * 1 byte literal = 2 bytes result is more + efficient in most cases than 2 bytes result = 2 bytes << literal + if port has 1 byte muldiv */ + if ((p2 > 0) && !IS_FLOAT (letype) && !IS_FIXED (letype) && + !((resultType == RESULT_TYPE_INT) && (getSize (resType) != getSize (ltype)) && !(TARGET_Z80_LIKE || TARGET_IS_STM8 && p2 == 1) /* Mimic old behaviour that tested port->muldiv, which was zero for stm8 and z80-like only. Someone should look into what really makes sense here. */) && + !TARGET_PIC_LIKE) /* don't shift for pic */ + { + if ((resultType == RESULT_TYPE_INT) && (getSize (resType) != getSize (ltype))) + { + /* LEFT_OP need same size for left and result, */ + left = geniCodeCast (resType, left, TRUE); + ltype = operandType (left); + } + ic = newiCode (LEFT_OP, left, operandFromLit (p2)); /* left shift */ + } + else + { + /* if the size left or right > 1 then support routine */ + if (getSize (ltype) > 1 || getSize (rtype) > 1) + { + if (IS_LITERAL (retype)) + ic = newiCode ('*', right, left); /* multiplication by support routine with one literal */ + else + ic = newiCode ('*', left, right); /* multiplication by support routine */ + ic->supportRtn = 1; + } + else + { + ic = newiCode ('*', left, right); /* normal multiplication */ + } + } + IC_RESULT (ic) = newiTempOperand (resType, 1); + + ADDTOCHAIN (ic); + return IC_RESULT (ic); +} + +static operand * +geniCodeAdd (operand *left, operand *right, RESULT_TYPE resultType, int lvl); +static operand * +geniCodeLogic (operand *left, operand *right, int op, ast *tree); +operand * +geniCodeRightShift (operand *left, operand *right); + +/*-----------------------------------------------------------------*/ +/* geniCodeDivision - gen intermediate code for division */ +/*-----------------------------------------------------------------*/ +static operand * +geniCodeDivision (operand *left, operand *right, RESULT_TYPE resultType, bool ptrdiffdiv) +{ + iCode *ic; + int p2 = 0; + sym_link *resType = usualBinaryConversions (&left, &right, resultType, '/'); + sym_link *rtype = operandType (right); + sym_link *retype = getSpec (rtype); + sym_link *ltype = operandType (left); + sym_link *letype = getSpec (ltype); + +/* if the right is a literal & power of 2 and left is unsigned then + make it a right shift. + For pointer division, there can be no remainder, so we can make + it a right shift, too. */ + + if (IS_LITERAL (retype) && + (!IS_FLOAT (letype) && !IS_FIXED (letype) && IS_UNSIGNED (letype) || ptrdiffdiv) && + ((p2 = powof2 ((TYPE_TARGET_ULONG) ulFromVal (OP_VALUE (right)))) > 0)) + { + ic = newiCode (RIGHT_OP, left, operandFromLit (p2)); /* right shift */ + } + /* if the right is a literal & power of 2 + and left is signed then make it a conditional addition + followed by right shift */ + else if (IS_LITERAL (retype) && + !IS_FLOAT (letype) && + !IS_FIXED (letype) && !IS_UNSIGNED (letype) && + ((p2 = powof2 ((TYPE_TARGET_ULONG) ulFromVal (OP_VALUE (right)))) > 0) && + (TARGET_Z80_LIKE || TARGET_HC08_LIKE)) + { + operand *tmp; + symbol *label = newiTempLabel (NULL); + + tmp = newiTempOperand (ltype, 0); + geniCodeAssign (tmp, left, 0, 0); + + ic = newiCodeCondition (geniCodeLogic (tmp, operandFromLit (0), '<', 0), 0, label); + ADDTOCHAIN (ic); + + geniCodeAssign (tmp, geniCodeAdd (tmp, operandFromLit ((1 << p2) - 1), 0, 0), 0, 0); + geniCodeLabel (label); + return (geniCodeCast (resType, geniCodeRightShift (tmp, operandFromLit (p2)), TRUE)); + } + + else + { + ic = newiCode ('/', left, right); /* normal division */ + /* if the size left or right > 1 then support routine */ + if (getSize (ltype) > 1 || getSize (rtype) > 1) + ic->supportRtn = 1; + } + IC_RESULT (ic) = newiTempOperand (resType, 0); + + ADDTOCHAIN (ic); + return IC_RESULT (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeModulus - gen intermediate code for modulus */ +/*-----------------------------------------------------------------*/ +static operand * +geniCodeModulus (operand * left, operand * right, RESULT_TYPE resultType) +{ + iCode *ic; + sym_link *resType; + LRTYPE; + + /* if they are both literal then we know the result */ + if (IS_LITERAL (letype) && IS_LITERAL (retype)) + return operandFromValue (valMod (OP_VALUE (left), OP_VALUE (right))); + + resType = usualBinaryConversions (&left, &right, resultType, '%'); + + /* now they are the same size */ + ic = newiCode ('%', left, right); + + /* if the size left or right > 1 then support routine */ + if (getSize (ltype) > 1 || getSize (rtype) > 1) + ic->supportRtn = 1; + IC_RESULT (ic) = newiTempOperand (resType, 0); + + ADDTOCHAIN (ic); + return IC_RESULT (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodePtrPtrSubtract - subtracts pointer from pointer */ +/*-----------------------------------------------------------------*/ +operand * +geniCodePtrPtrSubtract (operand * left, operand * right) +{ + iCode *ic; + operand *result; + LRTYPE; + + /* if they are both literals then */ + if (IS_LITERAL (letype) && IS_LITERAL (retype)) + { + result = operandFromValue (valMinus (OP_VALUE (left), OP_VALUE (right))); + goto subtractExit; + } + + ic = newiCode ('-', left, right); + + IC_RESULT (ic) = result = newiTempOperand (newIntLink (), 1); + ADDTOCHAIN (ic); + +subtractExit: + if (IS_VOID (ltype->next) || IS_VOID (rtype->next)) + { + return result; + } + + return geniCodeDivision (result, operandFromLit (getSize (ltype->next)), FALSE, true); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeSubtract - generates code for subtraction */ +/*-----------------------------------------------------------------*/ +static operand * +geniCodeSubtract (operand * left, operand * right, RESULT_TYPE resultType) +{ + iCode *ic; + int isarray = 0; + sym_link *resType; + LRTYPE; + + /* if they are both pointers then */ + if ((IS_PTR (ltype) || IS_ARRAY (ltype)) && (IS_PTR (rtype) || IS_ARRAY (rtype))) + return geniCodePtrPtrSubtract (left, right); + + /* if they are both literal then we know the result */ + if (IS_LITERAL (letype) && IS_LITERAL (retype) && left->isLiteral && right->isLiteral) + return operandFromValue (valMinus (OP_VALUE (left), OP_VALUE (right))); + + /* if left is an array or pointer */ + if (IS_PTR (ltype) || IS_ARRAY (ltype)) + { + isarray = left->isaddr; + right = geniCodeMultiply (right, + operandFromLit (getSize (ltype->next)), + (getArraySizePtr (left) >= INTSIZE) ? RESULT_TYPE_INT : RESULT_TYPE_CHAR); + resType = copyLinkChain (IS_ARRAY (ltype) ? ltype->next : ltype); + } + else + { /* make them the same size */ + resType = usualBinaryConversions (&left, &right, resultType, '-'); + } + + ic = newiCode ('-', left, right); + + IC_RESULT (ic) = newiTempOperand (resType, 1); + IC_RESULT (ic)->isaddr = (isarray ? 1 : 0); + + /* if left or right is a float */ + if (IS_FLOAT (ltype) || IS_FLOAT (rtype) || IS_FIXED (ltype) || IS_FIXED (rtype)) + ic->supportRtn = 1; + + ADDTOCHAIN (ic); + return IC_RESULT (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeAdd - generates iCode for addition */ +/*-----------------------------------------------------------------*/ +static operand * +geniCodeAdd (operand *left, operand *right, RESULT_TYPE resultType, int lvl) +{ + iCode *ic; + sym_link *resType; + unsigned int nBytes; + operand *size; + int isarray = 0; + bool indexUnsigned; + LRTYPE; + + /* if the right side is LITERAL zero */ + /* return the left side */ + if (IS_LITERAL (retype) && right->isLiteral && !floatFromVal (valFromType (rtype))) + return left; + + /* if left is literal zero return right */ + if (!IS_PTR (ltype) && IS_LITERAL (letype) && left->isLiteral && !floatFromVal (valFromType (ltype))) + return right; + + /* if left is a pointer then size */ + if (IS_PTR (ltype) || IS_ARRAY (ltype)) + { + unsigned int ptrSize; + isarray = left->isaddr; + nBytes = getSize (ltype->next); + ptrSize = getArraySizePtr (left); // works for both arrays and pointers + + if (nBytes == 0 && !IS_VOID (ltype->next)) + werror (E_UNKNOWN_SIZE, IS_SYMOP (left) ? OP_SYMBOL (left)->name : "<no name>"); + // there is no need to multiply with 1 + if (nBytes != 1) + { + size = operandFromLit (nBytes); + SPEC_USIGN (getSpec (operandType (size))) = 1; + indexUnsigned = IS_UNSIGNED (getSpec (operandType (right))); + if (!indexUnsigned && ptrSize > INTSIZE) + { + SPEC_LONG (getSpec (operandType (size))) = 1; + SPEC_CVAL (getSpec (operandType (size))).v_ulong = nBytes; + } + right = geniCodeMultiply (right, size, (ptrSize >= INTSIZE) ? RESULT_TYPE_INT : RESULT_TYPE_CHAR); + /* Even if right is a 'unsigned char', + the result will be a 'signed int' due to the promotion rules. + It doesn't make sense when accessing arrays, so let's fix it here: */ + if (indexUnsigned) + SPEC_USIGN (getSpec (operandType (right))) = 1; + } + + if (ptrSize > getSize (rtype) && !IS_UNSIGNED (retype)) + { + sym_link *type = 0; + + switch(ptrSize) + { + case 2: + type = newIntLink(); + break; + case 3: + case 4: + type = newLongLink(); + break; + default: + wassert(0); + } + right = geniCodeCast (type, right, TRUE); + } + + resType = copyLinkChain (ltype); + } + else + { // make them the same size + resType = usualBinaryConversions (&left, &right, resultType, '+'); + } + + /* if they are both literals then we know */ + if (IS_LITERAL (letype) && IS_LITERAL (retype) && left->isLiteral && right->isLiteral) + { + value *scaledRight = valFromType (rtype); + if (IS_PTR (ltype)) + scaledRight = valMult (scaledRight, valueFromLit (getSize (ltype->next))); + return operandFromValue (valPlus (valFromType (ltype), scaledRight)); + } + + ic = newiCode ('+', left, right); + + IC_RESULT (ic) = newiTempOperand (resType, 1); + IC_RESULT (ic)->isaddr = (isarray ? 1 : 0); + + /* if left or right is a float then support routine */ + if (IS_FLOAT (ltype) || IS_FLOAT (rtype) || IS_FIXED (ltype) || IS_FIXED (rtype)) + ic->supportRtn = 1; + + ADDTOCHAIN (ic); + + return IC_RESULT (ic); +} + +/*-----------------------------------------------------------------*/ +/* aggrToPtr - changes an "aggregate" to a "pointer to aggregate" */ +/*-----------------------------------------------------------------*/ +sym_link * +aggrToPtr (sym_link * type, bool force) +{ + sym_link *etype; + sym_link *ptype; + + if (IS_PTR (type) && !force) + return type; + + etype = getSpec (type); + ptype = newLink (DECLARATOR); + + ptype->next = type; + + /* set the pointer depending on the storage class */ + DCL_TYPE (ptype) = PTR_TYPE (SPEC_OCLS (etype)); + return ptype; +} + +/*------------------------------------------------------------------*/ +/* aggrToPtrDclType - like aggrToPtr, but returns only the DCL_TYPE */ +/*------------------------------------------------------------------*/ +int +aggrToPtrDclType (sym_link * type, bool force) +{ + if (IS_PTR (type) && !force) + return DCL_TYPE (type); + + /* return the pointer depending on the storage class */ + return PTR_TYPE (SPEC_OCLS (getSpec (type))); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeArray2Ptr - array to pointer */ +/*-----------------------------------------------------------------*/ +static operand * +geniCodeArray2Ptr (operand * op) +{ + sym_link *optype = operandType (op); + sym_link *opetype = getSpec (optype); + + /* set the pointer depending on the storage class */ + DCL_TYPE (optype) = PTR_TYPE (SPEC_OCLS (opetype)); + /* now remove the storage class from this itemp */ + SPEC_SCLS (opetype) = S_FIXED; + SPEC_OCLS (opetype) = NULL; + + op->isaddr = 0; + return op; +} + + +/*-----------------------------------------------------------------*/ +/* geniCodeArray - array access */ +/*-----------------------------------------------------------------*/ +static operand * +geniCodeArray (operand * left, operand * right, int lvl) +{ + iCode *ic; + operand *size; + sym_link *ltype = operandType (left); + bool indexUnsigned; + RESULT_TYPE resultType; + + resultType = (getArraySizePtr (left) >= INTSIZE) ? RESULT_TYPE_INT : RESULT_TYPE_CHAR; + if (DCL_ELEM (ltype)) + { + if (DCL_ELEM (ltype) * getSize (ltype->next) <= 255) + resultType = RESULT_TYPE_CHAR; + } + + if (IS_PTR (ltype)) + { + if (IS_PTR (ltype->next) && left->isaddr) + { + left = geniCodeRValue (left, FALSE); + } + + return geniCodeDerefPtr (geniCodeAdd (left, right, resultType, lvl), lvl); + } + size = operandFromLit (getSize (ltype->next)); + SPEC_USIGN (getSpec (operandType (size))) = 1; + indexUnsigned = IS_UNSIGNED (getSpec (operandType (right))); + right = geniCodeMultiply (right, size, resultType); + /* Even if right is a 'unsigned char', the result will be a 'signed int' due to the promotion rules. + It doesn't make sense when accessing arrays, so let's fix it here: */ + if (indexUnsigned) + SPEC_USIGN (getSpec (operandType (right))) = 1; + /* we can check for limits here */ + /* already done in SDCCast.c + if (isOperandLiteral (right) && + IS_ARRAY (ltype) && + DCL_ELEM (ltype) && + (operandLitValue (right) / getSize (ltype->next)) >= DCL_ELEM (ltype)) + { + werror (W_IDX_OUT_OF_BOUNDS, + (int) operandLitValue (right) / getSize (ltype->next), + DCL_ELEM (ltype)); + } + */ + + ic = newiCode ('+', left, right); + + IC_RESULT (ic) = newiTempOperand (((IS_PTR (ltype) && !IS_AGGREGATE (ltype->next) && !IS_PTR (ltype->next)) || + (IS_ARRAY (ltype) && IS_FUNCPTR (ltype->next))) ? ltype : ltype->next, 0); + + if (!IS_AGGREGATE (ltype->next)) + { + IC_RESULT (ic)->isaddr = 1; + IC_RESULT (ic)->aggr2ptr = 1; + } + ADDTOCHAIN (ic); + + return IC_RESULT (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeStruct - generates intermediate code for structures */ +/*-----------------------------------------------------------------*/ +operand * +geniCodeStruct (operand * left, operand * right, bool islval) +{ + iCode *ic; + sym_link *type = operandType (left); + sym_link *etype = getSpec (type); + sym_link *rtype, *retype; + symbol *element = getStructElement (SPEC_STRUCT (etype), OP_SYMBOL (right)); + + wassert (IS_SYMOP (right)); + + wassert (IS_STRUCT (type) || ((IS_PTR (type) || IS_ARRAY (type)) && IS_STRUCT (type->next))); + + /* add the offset */ + ic = newiCode ('+', left, operandFromLit (element->offset)); + + IC_RESULT (ic) = newiTempOperand (element->type, 0); + + /* preserve the storage & output class of the struct */ + /* as well as the volatile attribute */ + rtype = operandType (IC_RESULT (ic)); + retype = getSpec (rtype); + SPEC_SCLS (retype) = SPEC_SCLS (etype); + SPEC_OCLS (retype) = SPEC_OCLS (etype); + + if (IS_PTR (element->type)) + { + DCL_PTR_CONST (rtype) |= DCL_PTR_CONST (element->type); + DCL_PTR_VOLATILE (rtype) |= DCL_PTR_VOLATILE (element->type); + DCL_PTR_RESTRICT (rtype) |= DCL_PTR_RESTRICT (element->type); + setOperandType (IC_RESULT (ic), aggrToPtr (operandType (IC_RESULT (ic)), TRUE)); + } + else + { + SPEC_CONST (retype) |= SPEC_CONST (etype); + /*Do not preserve volatile */ + SPEC_RESTRICT (retype) |= SPEC_RESTRICT (etype); + } + + IC_RESULT (ic)->isaddr = (!IS_AGGREGATE (element->type)); + + ADDTOCHAIN (ic); + return (islval ? IC_RESULT (ic) : geniCodeRValue (IC_RESULT (ic), TRUE)); +} + +/*-----------------------------------------------------------------*/ +/* geniCodePostInc - generate int code for Post increment */ +/*-----------------------------------------------------------------*/ +operand * +geniCodePostInc (operand * op) +{ + iCode *ic; + operand *rOp; + sym_link *optype = operandType (op); + operand *result; + operand *rv = (IS_ITEMP (op) ? geniCodeRValue (op, (!op->aggr2ptr && IS_PTR (optype)) ? TRUE : FALSE) : op); + sym_link *rvtype = operandType (rv); + int size = 0; + operand *srcOp = rv; + + /* if this is not an address we have trouble */ + if (!op->isaddr) + { + werror (E_LVALUE_REQUIRED, "++"); + return op; + } + + rOp = newiTempOperand (rvtype, 0); + OP_SYMBOL (rOp)->noSpilLoc = 1; + + if (IS_ITEMP (rv)) + OP_SYMBOL (rv)->noSpilLoc = 1; + + geniCodeAssign (rOp, rv, 0, 0); + + /* If rv is volatile, we can only read it once, and we've just */ + /* done that, so use the copy in rOp instead to avoid reading */ + /* it again. */ + if (isOperandVolatile (rv, FALSE)) + srcOp = rOp; + + size = (IS_PTR (rvtype) ? getSize (rvtype->next) : 1); + if (size == 0) + werror (W_SIZEOF_VOID); + if (IS_FLOAT (rvtype)) + ic = newiCode ('+', srcOp, operandFromValue (constFloatVal ("1.0"))); + else if (IS_FIXED16X16 (rvtype)) + ic = newiCode ('+', srcOp, operandFromValue (constFixed16x16Val ("1.0"))); + else if (IS_BOOL (rvtype)) + ic = newiCode ('=', NULL, operandFromLit (1)); + else + ic = newiCode ('+', srcOp, operandFromLit (size)); + + IC_RESULT (ic) = result = newiTempOperand (rvtype, 0); + ADDTOCHAIN (ic); + + geniCodeAssign (op, result, 0, 0); + + return rOp; + +} + +/*-----------------------------------------------------------------*/ +/* geniCodePreInc - generate code for preIncrement */ +/*-----------------------------------------------------------------*/ +operand * +geniCodePreInc (operand * op, bool lvalue) +{ + iCode *ic; + sym_link *optype = operandType (op); + operand *rop = (IS_ITEMP (op) ? geniCodeRValue (op, ((!op->aggr2ptr && IS_PTR (optype)) ? TRUE : FALSE)) : op); + sym_link *roptype = operandType (rop); + operand *result; + int size = 0; + + if (!op->isaddr) + { + werror (E_LVALUE_REQUIRED, "++"); + return op; + } + + size = (IS_PTR (roptype) ? getSize (roptype->next) : 1); + if (size == 0) + werror (W_SIZEOF_VOID); + if (IS_FLOAT (roptype)) + ic = newiCode ('+', rop, operandFromValue (constFloatVal ("1.0"))); + else if (IS_FIXED16X16 (roptype)) + ic = newiCode ('+', rop, operandFromValue (constFixed16x16Val ("1.0"))); + else if (IS_BOOL (roptype)) + ic = newiCode ('=', NULL, operandFromLit (1)); + else + ic = newiCode ('+', rop, operandFromLit (size)); + IC_RESULT (ic) = result = newiTempOperand (roptype, 0); + ADDTOCHAIN (ic); + + (void) geniCodeAssign (op, result, 0, 0); + if (lvalue || (IS_TRUE_SYMOP (op) && !isOperandVolatile (op, FALSE)) || IS_BITVAR (optype)) + return op; + else + return result; +} + +/*-----------------------------------------------------------------*/ +/* geniCodePostDec - generates code for Post decrement */ +/*-----------------------------------------------------------------*/ +operand * +geniCodePostDec (operand * op) +{ + iCode *ic; + operand *rOp; + sym_link *optype = operandType (op); + operand *result; + operand *rv = (IS_ITEMP (op) ? geniCodeRValue (op, ((!op->aggr2ptr && IS_PTR (optype)) ? TRUE : FALSE)) : op); + sym_link *rvtype = operandType (rv); + int size = 0; + operand *srcOp = rv; + + /* if this is not an address we have trouble */ + if (!op->isaddr) + { + werror (E_LVALUE_REQUIRED, "--"); + return op; + } + + rOp = newiTempOperand (rvtype, 0); + OP_SYMBOL (rOp)->noSpilLoc = 1; + + if (IS_ITEMP (rv)) + OP_SYMBOL (rv)->noSpilLoc = 1; + + geniCodeAssign (rOp, rv, 0, 0); + + /* If rv is volatile, we can only read it once, and we've just */ + /* done that, so use the copy in rOp instead to avoid reading */ + /* it again. */ + if (isOperandVolatile (rv, FALSE)) + srcOp = rOp; + + size = (IS_PTR (rvtype) ? getSize (rvtype->next) : 1); + if (size == 0) + werror (W_SIZEOF_VOID); + if (IS_FLOAT (rvtype)) + ic = newiCode ('-', srcOp, operandFromValue (constFloatVal ("1.0"))); + else if (IS_FIXED16X16 (rvtype)) + ic = newiCode ('-', srcOp, operandFromValue (constFixed16x16Val ("1.0"))); + else if (IS_BOOL (rvtype)) + ic = newiCode ('!', srcOp, 0); + else + ic = newiCode ('-', srcOp, operandFromLit (size)); + + IC_RESULT (ic) = result = newiTempOperand (rvtype, 0); + ADDTOCHAIN (ic); + + geniCodeAssign (op, result, 0, 0); + + return rOp; + +} + +/*-----------------------------------------------------------------*/ +/* geniCodePreDec - generate code for pre decrement */ +/*-----------------------------------------------------------------*/ +operand * +geniCodePreDec (operand * op, bool lvalue) +{ + iCode *ic; + sym_link *optype = operandType (op); + operand *rop = (IS_ITEMP (op) ? geniCodeRValue (op, ((!op->aggr2ptr && IS_PTR (optype)) ? TRUE : FALSE)) : op); + sym_link *roptype = operandType (rop); + operand *result; + int size = 0; + + if (!op->isaddr) + { + werror (E_LVALUE_REQUIRED, "--"); + return op; + } + + size = (IS_PTR (roptype) ? getSize (roptype->next) : 1); + if (size == 0) + werror (W_SIZEOF_VOID); + if (IS_FLOAT (roptype)) + ic = newiCode ('-', rop, operandFromValue (constFloatVal ("1.0"))); + else if (IS_FIXED16X16 (roptype)) + ic = newiCode ('-', rop, operandFromValue (constFixed16x16Val ("1.0"))); + else if (IS_BOOL (roptype)) + ic = newiCode ('!', rop, 0); + else + ic = newiCode ('-', rop, operandFromLit (size)); + IC_RESULT (ic) = result = newiTempOperand (roptype, 0); + ADDTOCHAIN (ic); + + (void) geniCodeAssign (op, result, 0, 0); + if (lvalue || (IS_TRUE_SYMOP (op) && !isOperandVolatile (op, FALSE)) || IS_BITVAR (optype)) + return op; + else + return result; +} + + +/*-----------------------------------------------------------------*/ +/* geniCodeBitwise - gen int code for bitWise operators */ +/*-----------------------------------------------------------------*/ +operand * +geniCodeBitwise (operand * left, operand * right, int oper, sym_link * resType) +{ + iCode *ic; + + left = geniCodeCast (resType, left, TRUE); + right = geniCodeCast (resType, right, TRUE); + + ic = newiCode (oper, left, right); + IC_RESULT (ic) = newiTempOperand (resType, 0); + + ADDTOCHAIN (ic); + return IC_RESULT (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeAddressOf - gens icode for '&' address of operator */ +/*-----------------------------------------------------------------*/ +operand * +geniCodeAddressOf (operand * op) +{ + iCode *ic; + sym_link *p; + sym_link *optype = operandType (op); + sym_link *opetype = getSpec (optype); + + if (IS_ITEMP (op) && IS_PTR (optype)) + { + op = operandFromOperand (op); + op->isaddr = 0; + return op; + } + + /* lvalue check already done in decorateType */ + /* this must be a lvalue */ +/* if (!op->isaddr && !IS_AGGREGATE(optype)) { */ +/* werror (E_LVALUE_REQUIRED,"&"); */ +/* return op; */ +/* } */ + + p = newLink (DECLARATOR); + + /* set the pointer depending on the storage class */ + DCL_TYPE (p) = PTR_TYPE (SPEC_OCLS (opetype)); + + p->next = copyLinkChain (optype); + + /* if already a temp */ + if (IS_ITEMP (op)) + { + setOperandType (op, p); + op->isaddr = 0; + return op; + } + + /* otherwise make this of the type coming in */ + ic = newiCode (ADDRESS_OF, op, operandFromLit (0)); + IC_RESULT (ic) = newiTempOperand (p, 1); + IC_RESULT (ic)->isaddr = 0; + ADDTOCHAIN (ic); + return IC_RESULT (ic); +} + +/*-----------------------------------------------------------------*/ +/* setOClass - sets the output class depending on the pointer type */ +/*-----------------------------------------------------------------*/ +void +setOClass (sym_link * ptr, sym_link * spec) +{ + switch (DCL_TYPE (ptr)) + { + case POINTER: + SPEC_OCLS (spec) = data; + break; + + case GPOINTER: + SPEC_OCLS (spec) = generic; + break; + + case FPOINTER: + SPEC_OCLS (spec) = xdata; + break; + + case CPOINTER: + SPEC_OCLS (spec) = code; + break; + + case IPOINTER: + SPEC_OCLS (spec) = idata; + break; + + case PPOINTER: + SPEC_OCLS (spec) = xstack; + break; + + case EEPPOINTER: + SPEC_OCLS (spec) = eeprom; + break; + + default: + break; + } +} + +/*-----------------------------------------------------------------*/ +/* geniCodeDerefPtr - dereference pointer with '*' */ +/*-----------------------------------------------------------------*/ +operand * +geniCodeDerefPtr (operand * op, int lvl) +{ + sym_link *rtype, *retype; + sym_link *optype = operandType (op); + + // if this is an array then array access + if (IS_ARRAY (optype)) + { + // don't worry, this will be optimized out later + return geniCodeArray (op, operandFromLit (0), lvl); + } + + // just in case someone screws up + wassert (IS_PTR (optype)); + + if (IS_TRUE_SYMOP (op)) + { + op->isaddr = 1; + op = geniCodeRValue (op, TRUE); + } + else if (IS_OP_LITERAL (op)) + { + /* To avoid problems converting a dereferenced literal pointer */ + /* back and forth between lvalue and rvalue formats, replace */ + /* the literal pointer with an iTemp and assign the literal */ + /* value to the iTemp. */ + iCode *ic; + operand *iop = newiTempOperand (optype, 0); + SPEC_SCLS (OP_SYM_ETYPE (iop)) = S_AUTO; /* remove S_LITERAL */ + iop->isaddr = 0; /* assign to the iTemp itself */ + ic = newiCode ('=', NULL, op); + IC_RESULT (ic) = iop; + ADDTOCHAIN (ic); + op = operandFromOperand (iop); /* now use the iTemp as operand */ + optype = operandType (op); + } + + /* now get rid of the pointer part */ + if (isLvaluereq (lvl) && IS_ITEMP (op)) + { + retype = getSpec (rtype = copyLinkChain (optype)); + } + else + { + retype = getSpec (rtype = copyLinkChain (optype->next)); + /* outputclass needs 2b updated */ + setOClass (optype, retype); + } + + op->isGptr = IS_GENPTR (optype); + + op->isaddr = (IS_PTR (rtype) || + IS_STRUCT (rtype) || IS_INT (rtype) || IS_BOOL (rtype) || IS_CHAR (rtype) || IS_FLOAT (rtype) || IS_FIXED (rtype)); + + if (!isLvaluereq (lvl)) + op = geniCodeRValue (op, TRUE); + + if (IS_DECL (rtype)) + { + DCL_PTR_ADDRSPACE (rtype) = 0; + DCL_PTR_VOLATILE (rtype) = 0; + } + else + { + SPEC_ADDRSPACE (rtype) = 0; + SPEC_VOLATILE (rtype) = 0; + } + setOperandType (op, rtype); + + return op; +} + +/*-----------------------------------------------------------------*/ +/* geniCodeUnaryMinus - does a unary minus of the operand */ +/*-----------------------------------------------------------------*/ +operand * +geniCodeUnaryMinus (operand * op) +{ + iCode *ic; + sym_link *optype = operandType (op); + + if (IS_LITERAL (optype)) + return operandFromLit (-floatFromVal (OP_VALUE (op))); + + ic = newiCode (UNARYMINUS, op, NULL); + IC_RESULT (ic) = newiTempOperand (optype, 0); + ADDTOCHAIN (ic); + return IC_RESULT (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeLeftShift - gen i code for left shift */ +/*-----------------------------------------------------------------*/ +operand * +geniCodeLeftShift (operand * left, operand * right, RESULT_TYPE resultType) +{ + iCode *ic; + sym_link *resType; + + resType = usualBinaryConversions (&left, &right, resultType, LEFT_OP); + ic = newiCode(LEFT_OP, left, right); + IC_RESULT (ic) = newiTempOperand (resType, 0); + ADDTOCHAIN (ic); + return IC_RESULT (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeRightShift - gen i code for right shift */ +/*-----------------------------------------------------------------*/ +operand * +geniCodeRightShift (operand * left, operand * right) +{ + iCode *ic; + + ic = newiCode (RIGHT_OP, left, right); + IC_RESULT (ic) = newiTempOperand (operandType (left), 0); + ADDTOCHAIN (ic); + return IC_RESULT (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeLogic- logic code */ +/*-----------------------------------------------------------------*/ +static operand * +geniCodeLogic (operand * left, operand * right, int op, ast * tree) +{ + iCode *ic; + sym_link *ctype, *ttype; + sym_link *rtype = operandType (right); + sym_link *ltype = operandType (left); + + /* left is integral type and right is literal then + check if the literal value is within bounds */ + if (IS_INTEGRAL (ltype) && IS_VALOP (right) && IS_LITERAL (rtype)) + { + CCR_RESULT ccr_result = checkConstantRange (ltype, rtype, op, FALSE); + switch (ccr_result) + { + case CCR_ALWAYS_TRUE: + case CCR_ALWAYS_FALSE: + werror (W_COMP_RANGE, "true resp. false"); + return operandFromLit (ccr_result == CCR_ALWAYS_TRUE ? 1 : 0); + default: + break; + } + } + + /* Avoid expensive comparisons when the type of the constant is bigger than the type of the non-const operand */ + if (IS_INTEGRAL (ltype) && IS_LITERAL (rtype) && getSize (ltype) < getSize (rtype)) + right->svt.valOperand = valCastLiteral (ltype, operandLitValue (right), operandLitValueUll (right)); + if (IS_INTEGRAL (rtype) && IS_LITERAL (ltype) && getSize (rtype) < getSize (ltype)) + left->svt.valOperand = valCastLiteral (rtype, operandLitValue (left), operandLitValueUll (left)); + + /* if one operand is a pointer and the other is a literal generic void pointer, + change the type of the literal generic void pointer to match the other pointer */ + if (IS_GENPTR (ltype) && IS_VOID (ltype->next) && IS_ITEMP (left) && IS_PTR (rtype) && !IS_GENPTR (rtype)) + { + /* find left's definition */ + ic = (iCode *) setFirstItem (iCodeChain); + while (ic) + { + if (((ic->op == CAST) || (ic->op == '=')) && isOperandEqual (left, IC_RESULT (ic))) + break; + else + ic = setNextItem (iCodeChain); + } + /* if casting literal to generic pointer, then cast to rtype instead */ + if (ic && (ic->op == CAST) && isOperandLiteral (IC_RIGHT (ic))) + { + left = operandFromValue (valCastLiteral (rtype, operandLitValue (IC_RIGHT (ic)),operandLitValueUll (IC_RIGHT (ic)))); + ltype = operandType (left); + } + } + if (IS_GENPTR (rtype) && IS_VOID (rtype->next) && IS_ITEMP (right) && IS_PTR (ltype) && !IS_GENPTR (ltype)) + { + /* find right's definition */ + ic = (iCode *) setFirstItem (iCodeChain); + while (ic) + { + if (((ic->op == CAST) || (ic->op == '=')) && isOperandEqual (right, IC_RESULT (ic))) + break; + else + ic = setNextItem (iCodeChain); + } + /* if casting literal to generic pointer, then cast to rtype instead */ + if (ic && (ic->op == CAST) && isOperandLiteral (IC_RIGHT (ic))) + { + right = operandFromValue (valCastLiteral (ltype, operandLitValue (IC_RIGHT (ic)), operandLitValueUll (IC_RIGHT (ic)))); + rtype = operandType (right); + } + } + + ctype = usualBinaryConversions (&left, &right, RESULT_TYPE_BOOL, op); + + ic = newiCode (op, left, right); + /* store 0 or 1 in result */ + ttype = (tree && IS_BOOLEAN (tree->ftype)) ? newBoolLink () : newCharLink (); + IC_RESULT (ic) = newiTempOperand (ttype, 1); + + /* if comparing float + and not a '==' || '!=' || '&&' || '||' (these + will be inlined */ + if (IS_FLOAT (ctype) && op != EQ_OP && op != NE_OP && op != AND_OP && op != OR_OP) + ic->supportRtn = 1; + + /* if comparing a fixed type use support functions */ + if (IS_FIXED (ctype)) + ic->supportRtn = 1; + + ADDTOCHAIN (ic); + return IC_RESULT (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeLogicAndOr - && || operations */ +/*-----------------------------------------------------------------*/ +static operand * +geniCodeLogicAndOr (ast * tree, int lvl) +{ + iCode *ic; + sym_link *type; + symbol *falseLabel = newiTempLabel (NULL); + symbol *trueLabel = newiTempLabel (NULL); + symbol *exitLabel = newiTempLabel (NULL); + operand *op, *result, *condition; + + /* AND_OP and OR_OP are no longer generated because of bug-905492. + They can be reenabled by executing the following block. If you find + a decent optimization you could start right here: + */ +#if 0 + if (0) + { + operand *leftOp, *rightOp; + + leftOp = geniCodeRValue (ast2iCode (tree->left, lvl + 1), FALSE); + rightOp = geniCodeRValue (ast2iCode (tree->right, lvl + 1), FALSE); + + return geniCodeLogic (leftOp, rightOp, tree->opval.op); + } +#endif + + /* generate two IFX for the '&&' or '||' op */ + + /* evaluate left operand */ + condition = ast2iCode (tree->left, lvl + 1); + op = geniCodeRValue (condition, FALSE); + + /* test left operand */ + if (tree->opval.op == AND_OP) + ic = newiCodeCondition (op, NULL, falseLabel); + else /* OR_OP */ + ic = newiCodeCondition (op, trueLabel, NULL); + ADDTOCHAIN (ic); + + /* evaluate right operand */ + condition = ast2iCode (tree->right, lvl + 1); + op = geniCodeRValue (condition, FALSE); + + /* test right operand */ + ic = newiCodeCondition (op, trueLabel, NULL); + ADDTOCHAIN (ic); + + /* store 0 or 1 in result */ + type = (IS_BOOLEAN (tree->ftype)) ? newBoolLink () : newCharLink (); + result = newiTempOperand (type, 1); + + geniCodeLabel (falseLabel); + geniCodeAssign (result, operandFromLit (0), 0, 0); + /* generate an unconditional goto */ + geniCodeGoto (exitLabel); + + geniCodeLabel (trueLabel); + geniCodeAssign (result, operandFromLit (1), 0, 0); + + geniCodeLabel (exitLabel); + + return result; +} + +/*-----------------------------------------------------------------*/ +/* geniCodeUnary - for a generic unary operation */ +/*-----------------------------------------------------------------*/ +operand * +geniCodeUnary (operand * op, int oper, sym_link * resType) +{ + iCode *ic = newiCode (oper, op, NULL); + + IC_RESULT (ic) = newiTempOperand (resType, 0); + ADDTOCHAIN (ic); + return IC_RESULT (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeBinary - for a generic binary operation */ +/*-----------------------------------------------------------------*/ +operand * +geniCodeBinary (operand * left, operand * right, int oper, sym_link * resType) +{ + iCode *ic = newiCode (oper, left, right); + + IC_RESULT (ic) = newiTempOperand (resType, 0); + ADDTOCHAIN (ic); + return IC_RESULT (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeConditional - geniCode for '?' ':' operation */ +/*-----------------------------------------------------------------*/ +operand * +geniCodeConditional (ast * tree, int lvl) +{ + iCode *ic; + symbol *falseLabel = newiTempLabel (NULL); + symbol *exitLabel = newiTempLabel (NULL); + ast *astTrue = tree->right->left; + ast *astFalse = tree->right->right; + operand *cond = ast2iCode (tree->left, lvl + 1); + operand *result = newiTempOperand (tree->ftype, 0); + operand *opTrue, *opFalse; + + ic = newiCodeCondition (geniCodeRValue (cond, FALSE), NULL, falseLabel); + ADDTOCHAIN (ic); + + opTrue = ast2iCode (astTrue, lvl + 1); + + /* move the value to the new operand */ + geniCodeAssign (result, geniCodeRValue (opTrue, FALSE), 0, 0); + + /* generate an unconditional goto */ + geniCodeGoto (exitLabel); + + /* now for the right side */ + geniCodeLabel (falseLabel); + + opFalse = ast2iCode (astFalse, lvl + 1); + geniCodeAssign (result, geniCodeRValue (opFalse, FALSE), 0, 0); + + /* create the exit label */ + geniCodeLabel (exitLabel); + + return result; +} + +/*-----------------------------------------------------------------*/ +/* checkTypes - check types for assignment */ +/*-----------------------------------------------------------------*/ +static operand * +checkTypes (operand * left, operand * right) +{ + sym_link *ltype = operandType (left); + sym_link *rtype = operandType (right); + bool always_cast = FALSE; + + /* if the left & right type don't exactly match */ + /* if pointer set then make sure the check is + done with the type & not the pointer */ + /* then cast rights type to left */ + + /* first check the type for pointer assignement */ + if (left->isaddr && IS_PTR (ltype) && IS_ITEMP (left) && compareType (ltype, rtype) <= 0) + { + if (left->aggr2ptr) + { + always_cast = TRUE; + } + else + { + ltype = ltype->next; + } + } + + /* left is integral type and right is literal then + check if the literal value is within bounds */ + if (IS_INTEGRAL (ltype) && right->type == VALUE && IS_LITERAL (rtype) && + checkConstantRange (ltype, rtype, '=', FALSE) == CCR_OVL) + { + werror (W_LIT_OVERFLOW); + } + + if (always_cast || compareType (ltype, rtype) == -1) + right = geniCodeCast (ltype, right, TRUE); + checkPtrQualifiers (ltype, rtype, !right->isConstElimnated); + return right; +} + +/*-----------------------------------------------------------------*/ +/* geniCodeAssign - generate code for assignment */ +/*-----------------------------------------------------------------*/ +operand * +geniCodeAssign (operand * left, operand * right, int nosupdate, int strictLval) +{ + iCode *ic; + sym_link *ltype; + + if (!left->isaddr && (!IS_ITEMP (left) || strictLval)) + { + werror (E_LVALUE_REQUIRED, "assignment"); + return left; + } + + right = checkTypes (left, right); + + /* If left is a true symbol & ! volatile + create an assignment to temporary for + the right & then assign this temporary + to the symbol. This is SSA (static single + assignment). Isn't it simple and folks have + published mountains of paper on it */ + if (IS_TRUE_SYMOP (left) && !isOperandVolatile (left, FALSE) && isOperandGlobal (left)) + { + symbol *sym = NULL; + operand *newRight; + sym_link *ltype = operandType (left); + + if (IS_TRUE_SYMOP (right)) + sym = OP_SYMBOL (right); + ic = newiCode ('=', NULL, right); + IC_RESULT (ic) = newRight = newiTempOperand (ltype, 0); + /* avoid double fetch from volatile right, see bug 1369874 */ + if (!isOperandVolatile (right, FALSE)) + SPIL_LOC (newRight) = sym; + right = newRight; + ADDTOCHAIN (ic); + } + + ic = newiCode ('=', NULL, right); + IC_RESULT (ic) = left; + ADDTOCHAIN (ic); + + /* if left isgptr flag is set then support + routine will be required */ + if (left->isGptr) + ic->supportRtn = 1; + + ic->nosupdate = nosupdate; + /* left could be a pointer assignment, + return the properly casted right instead */ + ltype = operandType (left); + if ((IS_PTR (ltype) && IS_BITVAR (ltype->next)) || IS_BITVAR (ltype)) + return left; + else + return right; +} + +/*-----------------------------------------------------------------*/ +/* geniCodeDummyRead - generate code for dummy read */ +/*-----------------------------------------------------------------*/ +static void +geniCodeDummyRead (operand * op) +{ + iCode *ic; + sym_link *type = operandType (op); + + if (!IS_VOLATILE (type)) + return; + + ic = newiCode (DUMMY_READ_VOLATILE, NULL, op); + ADDTOCHAIN (ic); + + ic->nosupdate = 1; +} + +/*-----------------------------------------------------------------*/ +/* geniCodeSEParms - generate code for side effecting fcalls */ +/*-----------------------------------------------------------------*/ +static void +geniCodeSEParms (ast * parms, int lvl) +{ + if (!parms) + return; + + if (IS_AST_PARAM (parms)) + { + geniCodeSEParms (parms->left, lvl); + geniCodeSEParms (parms->right, lvl); + return; + } + + /* hack don't like this but too lazy to think of + something better */ + if (IS_ADDRESS_OF_OP (parms)) + parms->left->lvalue = 1; + + if (IS_CAST_OP (parms) && IS_PTR (parms->ftype) && IS_ADDRESS_OF_OP (parms->right)) + parms->right->left->lvalue = 1; + + parms->opval.oprnd = geniCodeRValue (ast2iCode (parms, lvl + 1), FALSE); + + parms->type = EX_OPERAND; + AST_ARGREG (parms) = parms->etype ? SPEC_ARGREG (parms->etype) : SPEC_ARGREG (parms->ftype); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeParms - generates parameters */ +/*-----------------------------------------------------------------*/ +value * +geniCodeParms (ast * parms, value * argVals, int *iArg, int *stack, sym_link * ftype, int lvl) +{ + iCode *ic; + operand *pval; + + if (!parms) + return argVals; + + /* if this is a param node then do the left & right */ + if (parms->type == EX_OP && parms->opval.op == PARAM) + { + argVals = geniCodeParms (parms->left, argVals, iArg, stack, ftype, lvl); + argVals = geniCodeParms (parms->right, argVals, iArg, stack, ftype, lvl); + return argVals; + } + + /* get the parameter value */ + if (parms->type == EX_OPERAND) + pval = parms->opval.oprnd; + else + { + /* maybe this else should go away ?? */ + /* hack don't like this but too lazy to think of + something better */ + if (IS_ADDRESS_OF_OP (parms)) + parms->left->lvalue = 1; + + if (IS_CAST_OP (parms) && IS_PTR (parms->ftype) && IS_ADDRESS_OF_OP (parms->right)) + parms->right->left->lvalue = 1; + + pval = geniCodeRValue (ast2iCode (parms, lvl + 1), FALSE); + } + + /* if register parm then make it a send */ + if ((IS_REGPARM (parms->etype) && !IFFUNC_HASVARARGS (ftype)) || IFFUNC_ISBUILTIN (ftype)) + { + pval = checkTypes (operandFromValue (argVals), pval); + ic = newiCode (SEND, pval, NULL); + ic->argreg = SPEC_ARGREG (parms->etype); + ic->builtinSEND = FUNC_ISBUILTIN (ftype); + ADDTOCHAIN (ic); + } + else + { + /* now decide whether to push or assign */ + if (!(options.stackAuto || IFFUNC_ISREENT (ftype))) + { + /* assign */ + operand *top = operandFromValue (argVals); + /* clear useDef and other bitVectors */ + OP_USES (top) = OP_DEFS (top) = OP_SYMBOL (top)->clashes = NULL; + geniCodeAssign (top, pval, 1, 0); + } + else + { + sym_link *p; + if (argVals && (*iArg >= 0)) + { + pval = checkTypes (operandFromValue (argVals), pval); + } + p = operandType (pval); + /* push */ + ic = newiCode (IPUSH, pval, NULL); + ic->parmPush = 1; + /* update the stack adjustment */ + *stack += getSize (IS_AGGREGATE (p) ? aggrToPtr (p, FALSE) : p); + if ((IFFUNC_ISSMALLC (ftype) || TARGET_PDK_LIKE) && !IS_AGGREGATE (p) && getSize (p) == 1) /* SmallC calling convention passes 8-bit paramters as 16-bit values. So does pdk due to stack alignment requirements */ + (*stack)++; + ADDTOCHAIN (ic); + } + } + + if (*iArg >= 0) + { + assert (argVals != NULL); + argVals = argVals->next; + } + (*iArg)++; + return argVals; +} + +/*-----------------------------------------------------------------*/ +/* geniCodeCall - generates temp code for calling */ +/*-----------------------------------------------------------------*/ +operand * +geniCodeCall (operand * left, ast * parms, int lvl) +{ + iCode *ic; + operand *result; + sym_link *type, *etype; + sym_link *ftype; + int stack = 0; + int iArg = 0; + + if (IS_ARRAY (operandType (left))) + { + iCode *tic; + sym_link *ttype; + + tic = newiCode (GET_VALUE_AT_ADDRESS, left, operandFromLit (0)); + ttype = copyLinkChain (operandType (left)->next); + IC_RESULT (tic) = newiTempOperand (ttype, 1); + IC_RESULT (tic)->isaddr = IS_FUNCPTR (ttype) ? 1 : 0; + ADDTOCHAIN (tic); + left = IC_RESULT (tic); + } + + ftype = operandType (left); + if (!IS_FUNC (ftype) && !IS_FUNCPTR (ftype)) + { + werror (E_FUNCTION_EXPECTED); + return operandFromValue (valueFromLit (0)); + } + + // not allow call a critical function + if (inCriticalPair && FUNC_ISCRITICAL (ftype)) + werror (E_INVALID_CRITICAL); + + /* take care of parameters with side-effecting + function calls in them, this is required to take care + of overlaying function parameters */ + geniCodeSEParms (parms, lvl); + + if (IS_FUNCPTR (ftype)) + ftype = ftype->next; + + /* first the parameters */ + if ((options.stackAuto || IFFUNC_ISREENT (ftype)) && !IFFUNC_ISBUILTIN (ftype)) + { + value *argVals; + int nArgs = 0; + ast *parm; + int nParms = 0; + + //count expected arguments except varargs + for (argVals = FUNC_ARGS (ftype); argVals; argVals = argVals->next) + nArgs++; + //count actual parameters including varargs + for (parm = parms; parm && parm->type == EX_OP && parm->opval.op == PARAM; parm = parm->right) + { + if (parm->left) + nParms++; + } + if (parm) + nParms++; + argVals = FUNC_ARGS (ftype); + iArg = nArgs - nParms; + + // reverse the argVals to match the parms + argVals = reverseVal (argVals); + geniCodeParms (parms, argVals, &iArg, &stack, ftype, lvl); + argVals = reverseVal (argVals); + } + else + { + geniCodeParms (parms, FUNC_ARGS (ftype), &iArg, &stack, ftype, lvl); + } + + /* now call : if symbol then pcall */ + if (IS_OP_POINTER (left) || IS_ITEMP (left)) + { + ic = newiCode (PCALL, left, NULL); + } + else + { + ic = newiCode (CALL, left, NULL); + } + + type = copyLinkChain (ftype->next); + etype = getSpec (type); + SPEC_EXTR (etype) = 0; + IC_RESULT (ic) = result = newiTempOperand (type, 1); + + ADDTOCHAIN (ic); + + /* stack adjustment after call */ + ic->parmBytes = stack; + + return result; +} + +/*-----------------------------------------------------------------*/ +/* geniCodeReceive - generate intermediate code for "receive" */ +/*-----------------------------------------------------------------*/ +static void +geniCodeReceive (value * args, operand * func) +{ + unsigned char paramByteCounter = 0; + + /* for all arguments that are passed in registers */ + while (args) + { + if (IS_REGPARM (args->etype)) + { + operand *opr = operandFromValue (args); + operand *opl; + symbol *sym = OP_SYMBOL (opr); + iCode *ic; + + /* we will use it after all optimizations + and before liveRange calculation */ + if (!sym->addrtaken && !IS_VOLATILE (sym->etype)) + { + + if ((IN_FARSPACE (SPEC_OCLS (sym->etype)) && !TARGET_HC08_LIKE) && + options.stackAuto == 0 && (!(options.model == MODEL_FLAT24))) + { + } + else + { + opl = newiTempOperand (args->type, 0); + sym->reqv = opl; + sym->reqv->key = sym->key; + OP_SYMBOL (sym->reqv)->key = sym->key; + OP_SYMBOL (sym->reqv)->isreqv = 1; + OP_SYMBOL (sym->reqv)->islocal = 0; + SPIL_LOC (sym->reqv) = sym; + } + } + + ic = newiCode (RECEIVE, func, NULL); + ic->argreg = SPEC_ARGREG (args->etype); + if (ic->argreg == 1) + { + currFunc->recvSize = getSize (sym->type); + } + IC_RESULT (ic) = opr; + + /* misuse of parmBytes (normally used for functions) + * to save estimated stack position of this argument. + * Normally this should be zero for RECEIVE iCodes. + * No idea if this causes side effects on other ports. - dw + */ + ic->parmBytes = paramByteCounter; + + /* what stack position do we have? */ + paramByteCounter += getSize (sym->type); + + ADDTOCHAIN (ic); + } + + args = args->next; + } +} + +/*-----------------------------------------------------------------*/ +/* geniCodeFunctionBody - create the function body */ +/*-----------------------------------------------------------------*/ +void +geniCodeFunctionBody (ast * tree, int lvl) +{ + iCode *ic; + operand *func; + char *savefilename; + int savelineno; + short functionBlock; + + /* reset the auto generation */ + /* numbers */ + iTempNum = 0; + iTempLblNum = 0; + operandKey = 0; + iCodeKey = 0; + func = ast2iCode (tree->left, lvl + 1); + + savefilename = filename; + savelineno = lineno; + filename = OP_SYMBOL (func)->fileDef; + lineno = OP_SYMBOL (func)->lineDef; + /* create an entry label */ + geniCodeLabel (entryLabel); + filename = savefilename; + lineno = savelineno; + + /* create a proc icode */ + functionBlock = block; + ic = newiCode (FUNCTION, func, NULL); + filename = ic->filename = OP_SYMBOL (func)->fileDef; + lineno = ic->lineno = OP_SYMBOL (func)->lineDef; + ic->tree = tree; + + ADDTOCHAIN (ic); + + /* for all parameters that are passed + on registers add a "receive" */ + geniCodeReceive (tree->values.args, func); + + /* generate code for the body */ + ast2iCode (tree->right, lvl + 1); + + /* create a label for return */ + block = functionBlock; + geniCodeLabel (returnLabel); + + /* now generate the end proc */ + ic = newiCode (ENDFUNCTION, func, NULL); + ic->filename = OP_SYMBOL (func)->fileDef; + ic->lineno = OP_SYMBOL (func)->lastLine; + ic->tree = tree; + ADDTOCHAIN (ic); + return; +} + +/*-----------------------------------------------------------------*/ +/* geniCodeReturn - gen icode for 'return' statement */ +/*-----------------------------------------------------------------*/ +void +geniCodeReturn (operand * op) +{ + iCode *ic; + + /* return in _Noreturn function */ + if (currFunc && IFFUNC_ISNORETURN (currFunc->type)) + werror (W_NORETURNRETURN); + + /* check if a cast is needed */ + if (op && currFunc && currFunc->type && currFunc->type->next) + checkPtrQualifiers (currFunc->type->next, operandType (op), !op->isConstElimnated); + + /* if the operand is present force an rvalue */ + if (op) + op = geniCodeRValue (op, FALSE); + + ic = newiCode (RETURN, op, NULL); + ADDTOCHAIN (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeIfx - generates code for extended if statement */ +/*-----------------------------------------------------------------*/ +void +geniCodeIfx (ast * tree, int lvl) +{ + iCode *ic; + operand *condition = ast2iCode (tree->left, lvl + 1); + sym_link *cetype; + + /* if condition is null then exit */ + if (!condition) + goto exit; + else + condition = geniCodeRValue (condition, FALSE); + + cetype = getSpec (operandType (condition)); + /* if the condition is a literal */ + if (IS_LITERAL (cetype)) + { + if (floatFromVal (OP_VALUE (condition))) + { + if (tree->trueLabel) + geniCodeGoto (tree->trueLabel); + else + assert (0); + } + else + { + if (tree->falseLabel) + geniCodeGoto (tree->falseLabel); + } + goto exit; + } + + if (tree->trueLabel) + { + ic = newiCodeCondition (condition, tree->trueLabel, NULL); + ADDTOCHAIN (ic); + + if (tree->falseLabel) + geniCodeGoto (tree->falseLabel); + } + else + { + ic = newiCodeCondition (condition, NULL, tree->falseLabel); + ADDTOCHAIN (ic); + } + +exit: + if (tree->right && tree->right->type == EX_VALUE) + geniCodeDummyRead (ast2iCode (tree->right, lvl + 1)); + else + ast2iCode (tree->right, lvl + 1); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeJumpTable - tries to create a jump table for switch */ +/*-----------------------------------------------------------------*/ +int +geniCodeJumpTable (operand * cond, value * caseVals, ast * tree) +{ + int min, max, cnt = 1; + int i, t; + value *vch, *maxVal; + iCode *ic; + symbol *falseLabel; + set *labels = NULL; + sym_link *cetype = getSpec (operandType (cond)); + int sizeofMinCost, sizeofZeroMinCost, sizeofMaxCost; + int sizeofMatchJump, sizeofJumpTable; + int sizeIndex; + struct dbuf_s dbuf; + + if (!tree || !caseVals) + return 0; + + /* the criteria for creating a jump table is */ + /* all integer numbers between the maximum & minimum must */ + /* be present, the maximum value should not exceed 255 */ + /* If not all integer numbers are present the algorithm */ + /* inserts jumps to the default label for the missing numbers */ + /* and decides later whether it is worth it */ + min = (int) ulFromVal (vch = caseVals); + + while (vch->next) + { + cnt++; + vch = vch->next; + } + max = (int) ulFromVal (vch); + maxVal = vch; + + /* Exit if the range is too large to handle with a jump table. */ + if (1 + max - min > port->jumptableCost.maxCount) + return 0; + + switch (getSize (operandType (cond))) + { + case 1: + sizeIndex = 0; + break; + case 2: + sizeIndex = 1; + break; + case 4: + sizeIndex = 2; + break; + default: + return 0; + } + + /* Compute the size cost of the range check and subtraction. */ + sizeofMinCost = 0; + sizeofZeroMinCost = 0; + sizeofMaxCost = 0; + + if (!(min == 0 && IS_UNSIGNED (cetype))) + sizeofMinCost = port->jumptableCost.sizeofRangeCompare[sizeIndex]; + if (!IS_UNSIGNED (cetype)) + sizeofZeroMinCost = port->jumptableCost.sizeofRangeCompare[sizeIndex]; + sizeofMaxCost = port->jumptableCost.sizeofRangeCompare[sizeIndex]; + + if (min) + sizeofMinCost += port->jumptableCost.sizeofSubtract; + + /* If the size cost of handling a non-zero minimum exceeds the */ + /* cost of extending the range down to zero, then it might be */ + /* better to extend the range to zero. */ + if (min > 0 && (sizeofMinCost - sizeofZeroMinCost) >= (min * port->jumptableCost.sizeofElement)) + { + /* Only extend the jump table if it would still be manageable. */ + if (1 + max <= port->jumptableCost.maxCount) + { + min = 0; + if (IS_UNSIGNED (cetype)) + sizeofMinCost = 0; + else + sizeofMinCost = port->jumptableCost.sizeofRangeCompare[sizeIndex]; + } + } + + /* Compute the total size cost of a jump table. */ + sizeofJumpTable = (1 + max - min) * port->jumptableCost.sizeofElement + + port->jumptableCost.sizeofDispatch + sizeofMinCost + sizeofMaxCost; + + /* Compute the total size cost of a match & jump sequence */ + sizeofMatchJump = cnt * port->jumptableCost.sizeofMatchJump[sizeIndex]; + + /* If the size cost of the jump table is uneconomical then exit */ + if (sizeofMatchJump < sizeofJumpTable) + return 0; + + /* The jump table is preferable. */ + + /* First, a label for the default or missing cases. */ + dbuf_init (&dbuf, 128); + if (tree->values.switchVals.swDefault) + { + dbuf_printf (&dbuf, "_default_%d%s", tree->values.switchVals.swNum, + tree->values.switchVals.swSuffix ? tree->values.switchVals.swSuffix : ""); + } + else + { + dbuf_printf (&dbuf, "_swBrk_%d%s", tree->values.switchVals.swNum, + tree->values.switchVals.swSuffix ? tree->values.switchVals.swSuffix : ""); + } + falseLabel = newiTempLabel (dbuf_c_str (&dbuf)); + dbuf_destroy (&dbuf); + + /* Build the list of labels for the jump table. */ + vch = caseVals; + t = (int) ulFromVal (vch); + for (i = min; i <= max; i++) + { + if (vch && t == i) + { + dbuf_init (&dbuf, 128); + /* Explicit case: make a new label for it. */ + dbuf_printf (&dbuf, "_case_%d_%d%s", tree->values.switchVals.swNum, i, + tree->values.switchVals.swSuffix ? tree->values.switchVals.swSuffix : ""); + addSet (&labels, newiTempLabel (dbuf_c_str (&dbuf))); + dbuf_destroy (&dbuf); + vch = vch->next; + if (vch) + t = (int) ulFromVal (vch); + } + else + { + /* Implicit case: use the default label. */ + addSet (&labels, falseLabel); + } + } + + /* first we rule out the boundary conditions */ + { + operand *lit; + operand *boundary; + sym_link *cetype = getSpec (operandType (cond)); + /* no need to check the lower bound if + the condition is always >= min or + the condition is unsigned & minimum value is zero */ + if ((checkConstantRange (cetype, caseVals->etype, '<', FALSE) != CCR_ALWAYS_FALSE) && + (!(min == 0 && IS_UNSIGNED (cetype)))) + { + lit = operandFromValue (valCastLiteral (cetype, min, min)); + boundary = geniCodeLogic (cond, lit, '<', NULL); + ic = newiCodeCondition (boundary, falseLabel, NULL); + ADDTOCHAIN (ic); + } + + /* now for upper bounds */ + if (checkConstantRange (cetype, maxVal->etype, '>', FALSE) != CCR_ALWAYS_FALSE) + { + lit = operandFromValue (valCastLiteral (cetype, max, max)); + boundary = geniCodeLogic (cond, lit, '>', NULL); + ic = newiCodeCondition (boundary, falseLabel, NULL); + ADDTOCHAIN (ic); + } + } + + /* if the min is not zero then we now make it zero */ + if (min) + { + cond = geniCodeSubtract (cond, operandFromLit (min), RESULT_TYPE_CHAR); + if (!IS_LITERAL (getSpec (operandType (cond)))) + setOperandType (cond, UCHARTYPE); + } + + /* now create the jumptable */ + ic = newiCode (JUMPTABLE, NULL, NULL); + IC_JTCOND (ic) = cond; + IC_JTLABELS (ic) = labels; + ADDTOCHAIN (ic); + return 1; +} + +/*-----------------------------------------------------------------*/ +/* geniCodeSwitch - changes a switch to a if statement */ +/*-----------------------------------------------------------------*/ +void +geniCodeSwitch (ast * tree, int lvl) +{ + iCode *ic; + operand *cond = geniCodeRValue (ast2iCode (tree->left, lvl + 1), FALSE); + value *caseVals = tree->values.switchVals.swVals; + symbol *trueLabel, *falseLabel; + struct dbuf_s dbuf; + + /* If the condition is a literal, then just jump to the */ + /* appropriate case label. */ + if (IS_LITERAL (getSpec (operandType (cond)))) + { + int switchVal, caseVal; + + switchVal = (int) ulFromVal (OP_VALUE (cond)); + while (caseVals) + { + caseVal = (int) ulFromVal (caseVals); + if (caseVal == switchVal) + { + struct dbuf_s dbuf; + + dbuf_init (&dbuf, 128); + dbuf_printf (&dbuf, "_case_%d_%d%s", tree->values.switchVals.swNum, caseVal, + tree->values.switchVals.swSuffix ? tree->values.switchVals.swSuffix : ""); + trueLabel = newiTempLabel (dbuf_c_str (&dbuf)); + dbuf_destroy (&dbuf); + geniCodeGoto (trueLabel); + goto jumpTable; + } + caseVals = caseVals->next; + } + goto defaultOrBreak; + } + + /* If cond is volatile, it might change while we are trying to */ + /* find the matching case. To avoid this possibility, make a */ + /* non-volatile copy to use instead. */ + if (IS_OP_VOLATILE (cond)) + { + operand *newcond; + iCode *ic; + + newcond = newiTempOperand (operandType (cond), TRUE); + newcond->isvolatile = 0; + ic = newiCode ('=', NULL, cond); + IC_RESULT (ic) = newcond; + ADDTOCHAIN (ic); + cond = newcond; + } + + /* if we can make this a jump table */ + if (geniCodeJumpTable (cond, caseVals, tree)) + goto jumpTable; /* no need for the comparison */ + + /* for the cases defined do */ + while (caseVals) + { + operand *compare = geniCodeLogic (cond, operandFromValue (caseVals), EQ_OP, NULL); + + dbuf_init (&dbuf, 128); + dbuf_printf (&dbuf, "_case_%d_%d%s", tree->values.switchVals.swNum, (int) ulFromVal (caseVals), + tree->values.switchVals.swSuffix ? tree->values.switchVals.swSuffix : ""); + trueLabel = newiTempLabel (dbuf_c_str (&dbuf)); + dbuf_destroy (&dbuf); + + ic = newiCodeCondition (compare, trueLabel, NULL); + ADDTOCHAIN (ic); + caseVals = caseVals->next; + } + +defaultOrBreak: + /* if default is present then goto break else break */ + dbuf_init (&dbuf, 128); + if (tree->values.switchVals.swDefault) + { + dbuf_printf (&dbuf, "_default_%d%s", tree->values.switchVals.swNum, + tree->values.switchVals.swSuffix ? tree->values.switchVals.swSuffix : ""); + } + else + { + dbuf_printf (&dbuf, "_swBrk_%d%s", tree->values.switchVals.swNum, + tree->values.switchVals.swSuffix ? tree->values.switchVals.swSuffix : ""); + } + + falseLabel = newiTempLabel (dbuf_c_str (&dbuf)); + dbuf_destroy (&dbuf); + geniCodeGoto (falseLabel); + +jumpTable: + ast2iCode (tree->right, lvl + 1); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeInline - intermediate code for inline assembler */ +/*-----------------------------------------------------------------*/ +static void +geniCodeInline (ast * tree) +{ + iCode *ic; + + ic = newiCode (INLINEASM, NULL, NULL); + IC_INLINE (ic) = tree->values.inlineasm; + ADDTOCHAIN (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeArrayInit - intermediate code for array initializer */ +/*-----------------------------------------------------------------*/ +static void +geniCodeArrayInit (ast * tree, operand * array) +{ + iCode *ic; + + if (!getenv ("TRY_THE_NEW_INITIALIZER")) + { + ic = newiCode (ARRAYINIT, array, NULL); + IC_ARRAYILIST (ic) = tree->values.constlist; + } + else + { + operand *left = newOperand (), *right = newOperand (); + left->type = right->type = SYMBOL; + OP_SYMBOL (left) = AST_SYMBOL (tree->left); + OP_SYMBOL (right) = AST_SYMBOL (tree->right); + ic = newiCode (ARRAYINIT, left, right); + } + ADDTOCHAIN (ic); +} + +/*-----------------------------------------------------------------*/ +/* geniCodeCritical - intermediate code for a critical statement */ +/*-----------------------------------------------------------------*/ +static void +geniCodeCritical (ast * tree, int lvl) +{ + iCode *ic; + operand *op = NULL; + sym_link *type; + + if (!options.stackAuto && !TARGET_HC08_LIKE) + { + type = newLink (SPECIFIER); + SPEC_VOLATILE (type) = 1; + SPEC_NOUN (type) = V_BIT; + SPEC_SCLS (type) = S_BIT; + SPEC_BLEN (type) = 1; + SPEC_BSTR (type) = 0; + op = newiTempOperand (type, 1); + } + + /* If op is NULL, the original interrupt state will saved on */ + /* the stack. Otherwise, it will be saved in op. */ + + /* Generate a save of the current interrupt state & disable */ + inCriticalPair = 1; + ic = newiCode (CRITICAL, NULL, NULL); + IC_RESULT (ic) = op; + ADDTOCHAIN (ic); + + /* Generate the critical code sequence */ + if (tree->left && tree->left->type == EX_VALUE) + geniCodeDummyRead (ast2iCode (tree->left, lvl + 1)); + else + ast2iCode (tree->left, lvl + 1); + + /* Generate a restore of the original interrupt state */ + ic = newiCode (ENDCRITICAL, NULL, op); + ADDTOCHAIN (ic); + inCriticalPair = 0; +} + +/*-----------------------------------------------------------------*/ +/* Stuff used in ast2iCode to modify geniCodeDerefPtr in some */ +/* particular case. Ie : assigning or dereferencing array or ptr */ +/*-----------------------------------------------------------------*/ +set *lvaluereqSet = NULL; +typedef struct lvalItem +{ + int req; + int lvl; +} +lvalItem; + +/*-----------------------------------------------------------------*/ +/* addLvaluereq - add a flag for lvalreq for current ast level */ +/*-----------------------------------------------------------------*/ +static void +addLvaluereq (int lvl) +{ + lvalItem *lpItem = (lvalItem *) Safe_alloc (sizeof (lvalItem)); + lpItem->req = 1; + lpItem->lvl = lvl; + addSetHead (&lvaluereqSet, lpItem); +} + +/*-----------------------------------------------------------------*/ +/* delLvaluereq - del a flag for lvalreq for current ast level */ +/*-----------------------------------------------------------------*/ +static void +delLvaluereq () +{ + lvalItem *lpItem = getSet (&lvaluereqSet); + if (lpItem) + Safe_free (lpItem); +} + +/*-----------------------------------------------------------------*/ +/* clearLvaluereq - clear lvalreq flag */ +/*-----------------------------------------------------------------*/ +static void +clearLvaluereq () +{ + lvalItem *lpItem = peekSet (lvaluereqSet); + if (lpItem) + lpItem->req = 0; +} + +/*-----------------------------------------------------------------*/ +/* getLvaluereq - get the last lvalreq level */ +/*-----------------------------------------------------------------*/ +#if 0 +int +getLvaluereqLvl () +{ + lvalItem *lpItem = peekSet (lvaluereqSet); + if (lpItem) + return lpItem->lvl; + return 0; +} +#endif +/*-----------------------------------------------------------------*/ +/* isLvaluereq - is lvalreq valid for this level ? */ +/*-----------------------------------------------------------------*/ +static int +isLvaluereq (int lvl) +{ + lvalItem *lpItem = peekSet (lvaluereqSet); + if (lpItem) + return ((lpItem->req) && (lvl <= (lpItem->lvl + 1))); + return 0; +} + +/*-----------------------------------------------------------------*/ +/* ast2iCode - creates an icodeList from an ast */ +/*-----------------------------------------------------------------*/ +operand * +ast2iCode (ast * tree, int lvl) +{ + operand *left = NULL; + operand *right = NULL; + if (!tree) + return NULL; + + /* set the global variables for filename & line number */ + if (tree->filename) + filename = tree->filename; + if (tree->lineno) + lineno = tree->lineno; + if (tree->block) + block = tree->block; + if (tree->level) + scopeLevel = tree->level; + if (tree->seqPoint) + seqPoint = tree->seqPoint; + + if (tree->type == EX_VALUE) + return operandFromValue (tree->opval.val); + + if (tree->type == EX_LINK) + return operandFromLink (tree->opval.lnk); + + /* if we find a nullop */ + if (tree->type == EX_OP && (tree->opval.op == NULLOP || tree->opval.op == BLOCK)) + { + if (tree->left && tree->left->type == EX_VALUE) + geniCodeDummyRead (ast2iCode (tree->left, lvl + 1)); + else + ast2iCode (tree->left, lvl + 1); + if (tree->right && tree->right->type == EX_VALUE) + geniCodeDummyRead (ast2iCode (tree->right, lvl + 1)); + else + ast2iCode (tree->right, lvl + 1); + return NULL; + } + + /* special cases for not evaluating */ + if (tree->opval.op != ':' && + tree->opval.op != '?' && + tree->opval.op != CALL && + tree->opval.op != IFX && + tree->opval.op != AND_OP && + tree->opval.op != OR_OP && + tree->opval.op != LABEL && + tree->opval.op != GOTO && + tree->opval.op != SWITCH && tree->opval.op != FUNCTION && tree->opval.op != INLINEASM && tree->opval.op != CRITICAL) + { + if (IS_ASSIGN_OP (tree->opval.op) || IS_DEREF_OP (tree) || IS_ADDRESS_OF_OP (tree)) + { + addLvaluereq (lvl); + if ((!IS_ADDRESS_OF_OP (tree) && IS_ARRAY_OP (tree->left) && IS_ARRAY_OP (tree->left->left) && + tree->left->left->ftype && IS_ARRAY (tree->left->left->ftype) && + tree->left->left->ftype->next && IS_ARRAY (tree->left->left->ftype->next)) || + (IS_DEREF_OP (tree) && IS_ARRAY_OP (tree->left))) + clearLvaluereq (); + + left = operandFromAst (tree->left, lvl); + delLvaluereq (); + if (IS_DEREF_OP (tree) && IS_DEREF_OP (tree->left)) + left = geniCodeRValue (left, TRUE); + } + else + { + left = operandFromAst (tree->left, lvl); + } + if (tree->opval.op == INC_OP || tree->opval.op == DEC_OP) + { + addLvaluereq (lvl); + right = operandFromAst (tree->right, lvl); + delLvaluereq (); + } + else + { + right = operandFromAst (tree->right, lvl); + } + } + + /* now depending on the type of operand */ + /* this will be a biggy */ + switch (tree->opval.op) + { + case '[': /* array operation */ + { + //sym_link *ltype = operandType (left); + //left = geniCodeRValue (left, IS_PTR (ltype->next) ? TRUE : FALSE); + left = geniCodeRValue (left, FALSE); + right = geniCodeRValue (right, TRUE); + } + + return geniCodeArray (left, right, lvl); + + case '.': /* structure dereference */ + if (IS_PTR (operandType (left))) + left = geniCodeRValue (left, TRUE); + else + left = geniCodeRValue (left, FALSE); + + return geniCodeStruct (left, right, tree->lvalue); + + case PTR_OP: /* structure pointer dereference */ + { + sym_link *pType; + pType = operandType (left); + left = geniCodeRValue (left, TRUE); + + setOClass (pType, getSpec (operandType (left))); + } + + return geniCodeStruct (left, right, tree->lvalue); + + case INC_OP: /* increment operator */ + if (left) + return geniCodePostInc (left); + else + return geniCodePreInc (right, tree->lvalue); + + case DEC_OP: /* decrement operator */ + if (left) + return geniCodePostDec (left); + else + return geniCodePreDec (right, tree->lvalue); + + case '&': /* bitwise and or address of operator */ + if (right) + { /* this is a bitwise operator */ + left = geniCodeRValue (left, FALSE); + right = geniCodeRValue (right, FALSE); + return geniCodeBitwise (left, right, BITWISEAND, tree->ftype); + } + else + return geniCodeAddressOf (left); + + case '|': /* bitwise or & xor */ + case '^': + return geniCodeBitwise (geniCodeRValue (left, FALSE), geniCodeRValue (right, FALSE), tree->opval.op, tree->ftype); + + case '/': + return geniCodeDivision (geniCodeRValue (left, FALSE), + geniCodeRValue (right, FALSE), getResultTypeFromType (tree->ftype), false); + + case '%': + return geniCodeModulus (geniCodeRValue (left, FALSE), geniCodeRValue (right, FALSE), getResultTypeFromType (tree->ftype)); + case '*': + if (right) + return geniCodeMultiply (geniCodeRValue (left, FALSE), + geniCodeRValue (right, FALSE), getResultTypeFromType (tree->ftype)); + else + return geniCodeDerefPtr (geniCodeRValue (left, FALSE), lvl); + + case '-': + if (right) + return geniCodeSubtract (geniCodeRValue (left, FALSE), + geniCodeRValue (right, FALSE), getResultTypeFromType (tree->ftype)); + else + return geniCodeUnaryMinus (geniCodeRValue (left, FALSE)); + + case '+': + if (right) + return geniCodeAdd (geniCodeRValue (left, FALSE), + geniCodeRValue (right, FALSE), getResultTypeFromType (tree->ftype), lvl); + else + return geniCodeRValue (left, FALSE); /* unary '+' has no meaning */ + + case LEFT_OP: + return geniCodeLeftShift (geniCodeRValue (left, FALSE), + geniCodeRValue (right, FALSE), getResultTypeFromType (tree->ftype)); + + case RIGHT_OP: + return geniCodeRightShift (geniCodeRValue (left, FALSE), geniCodeRValue (right, FALSE)); + case CAST: +#if 0 // this indeed needs a second thought + { + operand *op; + + // let's keep this simple: get the rvalue we need + op = geniCodeRValue (right, FALSE); + // now cast it to whatever we want + op = geniCodeCast (operandType (left), op, FALSE); + // if this is going to be used as an lvalue, make it so + if (tree->lvalue) + { + op->isaddr = 1; + } + return op; + } +#else // bug #604575, is it a bug ???? + return geniCodeCast (operandType (left), geniCodeRValue (right, FALSE), FALSE); +#endif + + case '~': + case RRC: + case RLC: + case SWAP: + return geniCodeUnary (geniCodeRValue (left, FALSE), tree->opval.op, tree->ftype); + + case '!': + case GETHBIT: + { + operand *op = geniCodeUnary (geniCodeRValue (left, FALSE), tree->opval.op, tree->ftype); + return op; + } + case GETABIT: + { + operand *op = geniCodeBinary (geniCodeRValue (left, FALSE), + geniCodeRValue (right, FALSE), + tree->opval.op, tree->ftype); + return op; + } + case GETBYTE: + { + operand *op = geniCodeBinary (geniCodeRValue (left, FALSE), + geniCodeRValue (right, FALSE), + tree->opval.op, tree->ftype); + setOperandType (op, UCHARTYPE); + return op; + } + case GETWORD: + { + operand *op = geniCodeBinary (geniCodeRValue (left, FALSE), + geniCodeRValue (right, FALSE), + tree->opval.op, tree->ftype); + setOperandType (op, UINTTYPE); + return op; + } + case AND_OP: + case OR_OP: + return geniCodeLogicAndOr (tree, lvl); + case '>': + case '<': + case LE_OP: + case GE_OP: + case EQ_OP: + case NE_OP: + /* different compilers (even different gccs) evaluate + the two calls in a different order. to get the same + result on all machines we have to specify a clear sequence. + return geniCodeLogic (geniCodeRValue (left, FALSE), + geniCodeRValue (right, FALSE), + tree->opval.op); + */ + { + operand *leftOp, *rightOp; + + leftOp = geniCodeRValue (left, FALSE); + rightOp = geniCodeRValue (right, FALSE); + + return geniCodeLogic (leftOp, rightOp, tree->opval.op, tree); + } + case '?': + return geniCodeConditional (tree, lvl); + + case SIZEOF: + return operandFromLit (getSize (tree->right->ftype)); + + case '=': + { + sym_link *rtype = operandType (right); + sym_link *ltype = operandType (left); + if (IS_PTR (rtype) && IS_ITEMP (right) && right->isaddr && compareType (rtype->next, ltype) == 1) + right = geniCodeRValue (right, TRUE); + else + right = geniCodeRValue (right, FALSE); + return geniCodeAssign (left, right, 0, 1); + } + case MUL_ASSIGN: + return + geniCodeAssign (left, + geniCodeMultiply (geniCodeRValue (operandFromOperand (left), + FALSE), + geniCodeRValue (right, FALSE), getResultTypeFromType (tree->ftype)), 0, 1); + + case DIV_ASSIGN: + return + geniCodeAssign (left, + geniCodeDivision (geniCodeRValue (operandFromOperand (left), FALSE), + geniCodeRValue (right, FALSE), getResultTypeFromType (tree->ftype), false), 0, 1); + case MOD_ASSIGN: + return + geniCodeAssign (left, + geniCodeModulus (geniCodeRValue (operandFromOperand (left), + FALSE), + geniCodeRValue (right, FALSE), getResultTypeFromType (tree->ftype)), 0, 1); + case ADD_ASSIGN: + { + sym_link *rtype = operandType (right); + sym_link *ltype = operandType (left); + if (IS_PTR (rtype) && IS_ITEMP (right) && right->isaddr && compareType (rtype->next, ltype) == 1) + right = geniCodeRValue (right, TRUE); + else + right = geniCodeRValue (right, FALSE); + + + return geniCodeAssign (left, + geniCodeAdd (geniCodeRValue (operandFromOperand (left), + FALSE), right, getResultTypeFromType (tree->ftype), lvl), 0, 1); + } + case SUB_ASSIGN: + { + sym_link *rtype = operandType (right); + sym_link *ltype = operandType (left); + if (IS_PTR (rtype) && IS_ITEMP (right) && right->isaddr && compareType (rtype->next, ltype) == 1) + { + right = geniCodeRValue (right, TRUE); + } + else + { + right = geniCodeRValue (right, FALSE); + } + return + geniCodeAssign (left, + geniCodeSubtract (geniCodeRValue (operandFromOperand (left), + FALSE), right, getResultTypeFromType (tree->ftype)), 0, 1); + } + case LEFT_ASSIGN: + return + geniCodeAssign (left, + geniCodeLeftShift (geniCodeRValue (operandFromOperand (left), FALSE), + geniCodeRValue (right, FALSE), getResultTypeFromType (tree->ftype)), 0, 1); + case RIGHT_ASSIGN: + return + geniCodeAssign (left, + geniCodeRightShift (geniCodeRValue (operandFromOperand (left), FALSE), + geniCodeRValue (right, FALSE)), 0, 1); + case AND_ASSIGN: + return + geniCodeAssign (left, + geniCodeBitwise (geniCodeRValue (operandFromOperand (left), + FALSE), + geniCodeRValue (right, FALSE), BITWISEAND, operandType (left)), 0, 1); + case XOR_ASSIGN: + return + geniCodeAssign (left, + geniCodeBitwise (geniCodeRValue (operandFromOperand (left), + FALSE), geniCodeRValue (right, FALSE), '^', operandType (left)), 0, 1); + case OR_ASSIGN: + return + geniCodeAssign (left, + geniCodeBitwise (geniCodeRValue (operandFromOperand (left), FALSE), + geniCodeRValue (right, FALSE), '|', operandType (left)), 0, 1); + case ',': + return geniCodeRValue (right, FALSE); + + case CALL: + return geniCodeCall (ast2iCode (tree->left, lvl + 1), tree->right, lvl); + + case LABEL: + geniCodeLabel (OP_SYMBOL (ast2iCode (tree->left, lvl + 1))); + if (tree->right && tree->right->type == EX_VALUE) + { + geniCodeDummyRead (ast2iCode (tree->right, lvl + 1)); + return NULL; + } + else + return ast2iCode (tree->right, lvl + 1); + + case GOTO: + geniCodeGoto (OP_SYMBOL (ast2iCode (tree->left, lvl + 1))); + return ast2iCode (tree->right, lvl + 1); + + case FUNCTION: + geniCodeFunctionBody (tree, lvl); + return NULL; + + case RETURN: + geniCodeReturn (right); + return NULL; + + case IFX: + geniCodeIfx (tree, lvl); + return NULL; + + case SWITCH: + geniCodeSwitch (tree, lvl); + return NULL; + + case INLINEASM: + geniCodeInline (tree); + return NULL; + + case ARRAYINIT: + geniCodeArrayInit (tree, ast2iCode (tree->left, lvl + 1)); + return NULL; + + case CRITICAL: + geniCodeCritical (tree, lvl); + } + + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* reverseICChain - gets from the list and creates a linkedlist */ +/*-----------------------------------------------------------------*/ +iCode * +reverseiCChain () +{ + iCode *loop = NULL; + iCode *prev = NULL; + + while ((loop = getSet (&iCodeChain))) + { + loop->next = prev; + if (prev) + prev->prev = loop; + prev = loop; + } + + return prev; +} + + +/*-----------------------------------------------------------------*/ +/* iCodeFromAst - given an ast will convert it to iCode */ +/*-----------------------------------------------------------------*/ +iCode * +iCodeFromAst (ast * tree) +{ + returnLabel = newiTempLabel ("_return"); + entryLabel = newiTempLabel ("_entry"); + ast2iCode (tree, 0); + return reverseiCChain (); +} + +static const char * +opTypeToStr (OPTYPE op) +{ + switch (op) + { + case SYMBOL: + return "symbol"; + case VALUE: + return "value"; + case TYPE: + return "type"; + } + return "undefined type"; +} + + +operand * +validateOpType (operand * op, const char *macro, const char *args, OPTYPE type, const char *file, unsigned line) +{ + if (op && op->type == type) + { + return op; + } + fprintf (stderr, + "Internal error: validateOpType failed in %s(%s) @ %s:%u:" + " expected %s, got %s\n", macro, args, file, line, opTypeToStr (type), op ? opTypeToStr (op->type) : "null op"); + exit (EXIT_FAILURE); + return op; // never reached, makes compiler happy. +} + +const operand * +validateOpTypeConst (const operand * op, const char *macro, const char *args, OPTYPE type, const char *file, unsigned line) +{ + if (op && op->type == type) + { + return op; + } + fprintf (stderr, + "Internal error: validateOpType failed in %s(%s) @ %s:%u:" + " expected %s, got %s\n", macro, args, file, line, opTypeToStr (type), op ? opTypeToStr (op->type) : "null op"); + exit (EXIT_FAILURE); + return op; // never reached, makes compiler happy. +} |
