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/SDCCcse.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/SDCCcse.c')
| -rw-r--r-- | src/SDCCcse.c | 2736 |
1 files changed, 2736 insertions, 0 deletions
diff --git a/src/SDCCcse.c b/src/SDCCcse.c new file mode 100644 index 0000000..dc6d8aa --- /dev/null +++ b/src/SDCCcse.c @@ -0,0 +1,2736 @@ +/*------------------------------------------------------------------------- + SDCCcse.c - source file for Common Subexpressions and other utility + + 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 "dbuf_string.h" + +/*-----------------------------------------------------------------*/ +/* newCseDef - new cseDef */ +/*-----------------------------------------------------------------*/ +cseDef * +newCseDef (operand * sym, iCode * ic) +{ + cseDef *cdp; + memmap *map; + + assert (sym); + cdp = Safe_alloc (sizeof (cseDef)); + + cdp->sym = sym; + cdp->diCode = ic; + cdp->key = sym->key; + cdp->ancestors = newBitVect(operandKey); + cdp->fromGlobal = 0; + cdp->fromAddrTaken = 0; + + if (ic->op != IF && ic->op != JUMPTABLE) + { + if (ic->op != ADDRESS_OF && IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic))) + { + bitVectSetBit (cdp->ancestors, IC_LEFT (ic)->key); + if (isOperandGlobal (IC_LEFT (ic))) + { + map = SPEC_OCLS (getSpec (operandType (IC_LEFT (ic)))); + if (map) + cdp->fromGlobal |= (1 << map->ptrType); + } + cdp->fromAddrTaken |= OP_SYMBOL (IC_LEFT (ic))->addrtaken; + } + if (IC_RIGHT (ic) && IS_SYMOP (IC_RIGHT (ic))) + { + bitVectSetBit (cdp->ancestors, IC_RIGHT (ic)->key); + if (isOperandGlobal (IC_RIGHT (ic))) + { + map = SPEC_OCLS (getSpec (operandType (IC_RIGHT (ic)))); + if (map) + cdp->fromGlobal |= (1 << map->ptrType); + } + cdp->fromAddrTaken |= OP_SYMBOL (IC_RIGHT (ic))->addrtaken; + } + } + + return cdp; +} + +void +freeLocalCseDef (void *item) +{ + cseDef * cse = (cseDef *)item; + + /* If this CSE definition being deleted is not visible outside */ + /* its defining eBBlock, we can safely deallocate it completely */ + if (!cse->nonLocalCSE) + { + freeBitVect(cse->ancestors); + Safe_free(cse); + } +} + + +void +updateCseDefAncestors(cseDef *cdp, set * cseSet) +{ + cseDef *loop; + set *sl; + iCode *ic = cdp->diCode; + + if (ic->op!=IF && ic->op!=JUMPTABLE) + { + if (ic->op != ADDRESS_OF && IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic))) + { + bitVectSetBit (cdp->ancestors, IC_LEFT (ic)->key); + for (sl = cseSet; sl; sl = sl->next) + { + loop = sl->item; + if (loop->sym->key == IC_LEFT (ic)->key) + { + cdp->ancestors = bitVectInplaceUnion (cdp->ancestors, loop->ancestors); + cdp->fromGlobal |= loop->fromGlobal; + cdp->fromAddrTaken |= loop->fromAddrTaken; + break; + } + } + } + if (IC_RIGHT (ic) && IS_SYMOP (IC_RIGHT (ic))) + { + bitVectSetBit (cdp->ancestors, IC_RIGHT (ic)->key); + for (sl = cseSet; sl; sl = sl->next) + { + loop = sl->item; + if (loop->sym->key == IC_RIGHT (ic)->key) + { + cdp->ancestors = bitVectInplaceUnion (cdp->ancestors, loop->ancestors); + cdp->fromGlobal |= loop->fromGlobal; + cdp->fromAddrTaken |= loop->fromAddrTaken; + break; + } + } + } + } +} + + +/*-----------------------------------------------------------------*/ +/* int isCseDefEqual - two definitions are equal */ +/*-----------------------------------------------------------------*/ +int +isCseDefEqual (void *vsrc, void *vdest) +{ + cseDef *src = vsrc; + cseDef *dest = vdest; + + if (src == dest) + return 1; + + return (src->key == dest->key && + src->diCode == dest->diCode); +} + +/*-----------------------------------------------------------------*/ +/* pcseDef - in the cseDef */ +/*-----------------------------------------------------------------*/ +int +pcseDef (void *item, va_list ap) +{ + cseDef *cdp = item; + iCodeTable *icTab; + struct dbuf_s dbuf; + + (void) ap; + + if (!cdp->sym) + fprintf (stdout, "**null op**"); + printOperand (cdp->sym, stdout); + icTab = getTableEntry (cdp->diCode->op); + dbuf_init (&dbuf, 1024); + icTab->iCodePrint (&dbuf, cdp->diCode, icTab->printName); + dbuf_write_and_destroy (&dbuf, stdout); + return 1; +} + +void ReplaceOpWithCheaperOp(operand **op, operand *cop) { +#ifdef RANGEHUNT + printf ("ReplaceOpWithCheaperOp\n\t"); + printOperand (*op, stdout); + printf ("\nwith\t"); + printOperand (cop, stdout); + + // if op is a register equivalent + if (IS_ITEMP(cop) && IS_SYMOP((*op)) && OP_SYMBOL((*op))->isreqv) { + operand **rop = &OP_SYMBOL((*op))->usl.spillLoc->reqv; + if (isOperandEqual(*rop, *op)) { + printf ("true"); + *rop=cop; + OP_SYMBOL((*op))->isreqv=0; + OP_SYMBOL(cop)->isreqv=1; + } else { + printf ("false"); + } + } + printf ("\n"); +#endif + *op=cop; +} + +/*-----------------------------------------------------------------*/ +/* replaceAllSymBySym - replaces all operands by operand in an */ +/* instruction chain */ +/*-----------------------------------------------------------------*/ +void +replaceAllSymBySym (iCode * ic, operand * from, operand * to, bitVect ** ndpset) +{ + iCode *lic; + +#ifdef RANGEHUNT + printf ("replaceAllSymBySym\n\t"); + printOperand (from, stdout); + printf ("\nwith\t"); + printOperand (to, stdout); + printf ("\n"); +#endif + for (lic = ic; lic; lic = lic->next) + { + int isaddr; + + /* do the special cases first */ + if (lic->op == IFX) + { + if (IS_SYMOP (to) && + IC_COND (lic)->key == from->key) + { + + bitVectUnSetBit (OP_USES (from), lic->key); + OP_USES(to)=bitVectSetBit (OP_USES (to), lic->key); + isaddr = IC_COND (lic)->isaddr; + IC_COND (lic) = operandFromOperand (to); + IC_COND (lic)->isaddr = isaddr; + + } + continue; + } + + if (lic->op == JUMPTABLE) + { + if (IS_SYMOP (to) && + IC_JTCOND (lic)->key == from->key) + { + + bitVectUnSetBit (OP_USES (from), lic->key); + OP_USES(to)=bitVectSetBit (OP_USES (to), lic->key); + isaddr = IC_COND (lic)->isaddr; + IC_JTCOND (lic) = operandFromOperand (to); + IC_JTCOND (lic)->isaddr = isaddr; + + } + continue; + } + + if (IS_SYMOP(to) && + IC_RESULT (lic) && IC_RESULT (lic)->key == from->key) + { + /* maintain du chains */ + if (POINTER_SET (lic)) + { + bitVectUnSetBit (OP_USES (from), lic->key); + OP_USES(to)=bitVectSetBit (OP_USES (to), lic->key); + + /* also check if the "from" was in the non-dominating + pointer sets and replace it with "to" in the bitVector */ + if (bitVectBitValue (*ndpset, from->key)) + { + bitVectUnSetBit (*ndpset, from->key); + bitVectSetBit (*ndpset, to->key); + } + + } + else + { + bitVectUnSetBit (OP_DEFS (from), lic->key); + OP_DEFS(to)=bitVectSetBit (OP_DEFS (to), lic->key); + } + isaddr = IC_RESULT (lic)->isaddr; + IC_RESULT (lic) = operandFromOperand (to); + IC_RESULT (lic)->isaddr = isaddr; + } + + if (IS_SYMOP (to) && + IC_RIGHT (lic) && IC_RIGHT (lic)->key == from->key) + { + bitVectUnSetBit (OP_USES (from), lic->key); + OP_USES(to)=bitVectSetBit (OP_USES (to), lic->key); + isaddr = IC_RIGHT (lic)->isaddr; + IC_RIGHT (lic) = operandFromOperand (to); + IC_RIGHT (lic)->isaddr = isaddr; + } + + if (IS_SYMOP (to) && + IC_LEFT (lic) && IC_LEFT (lic)->key == from->key) + { + bitVectUnSetBit (OP_USES (from), lic->key); + OP_USES(to)=bitVectSetBit (OP_USES (to), lic->key); + isaddr = IC_LEFT (lic)->isaddr; + IC_LEFT (lic) = operandFromOperand (to); + IC_LEFT (lic)->isaddr = isaddr; + } + } +} + +/*-----------------------------------------------------------------*/ +/* iCodeKeyIs - if the icode keys match then return 1 */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (iCodeKeyIs) +{ + cseDef *cdp = item; + V_ARG (int, key); + + if (cdp->diCode->key == key) + return 1; + else + return 0; +} + +/*-----------------------------------------------------------------*/ +/* removeFromInExprs - removes an icode from inexpressions */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (removeFromInExprs) +{ + eBBlock *ebp = item; + V_ARG (iCode *, ic); + V_ARG (operand *, from); + V_ARG (operand *, to); + V_ARG (eBBlock *, cbp); + + if (ebp->visited) + return 0; + + ebp->visited = 1; + deleteItemIf (&ebp->inExprs, iCodeKeyIs, ic->key); + if (ebp != cbp && !bitVectBitValue (cbp->domVect, ebp->bbnum)) + replaceAllSymBySym (ebp->sch, from, to, &ebp->ndompset); + + applyToSet (ebp->succList, removeFromInExprs, ic, from, to, cbp); + return 0; +} + +/*-----------------------------------------------------------------*/ +/* isGlobalInNearSpace - return TRUE if variable is a globalin data */ +/*-----------------------------------------------------------------*/ +static bool +isGlobalInNearSpace (operand * op) +{ + sym_link *type = getSpec (operandType (op)); + /* this is 8051 specific: optimization + suggested by Jean-Louis VERN, with 8051s we have no + advantage of putting variables in near space into + registers */ + if (isOperandGlobal (op) && !IN_FARSPACE (SPEC_OCLS (type)) && + IN_DIRSPACE (SPEC_OCLS (type))) + return TRUE; + else + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* findCheaperOp - cseBBlock support routine, will check to see if */ +/* we have a operand previously defined */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (findCheaperOp) +{ + cseDef *cdp = item; + V_ARG (operand *, cop); + V_ARG (operand **, opp); + V_ARG (int, checkSign); + + /* if we have already found it */ + if (*opp) + return 1; + + /* not found it yet check if this is the one */ + /* and this is not the defining one */ + if (cop->key && cop->key == cdp->key) + { + /* do a special check this will help in */ + /* constant propagation & dead code elim */ + /* for assignments only */ + if (cdp->diCode->op == '=') + { + /* if the result is volatile then return result */ + if (IS_OP_VOLATILE (IC_RESULT (cdp->diCode))) + { + *opp = IC_RESULT (cdp->diCode); + } + else + { + /* if this is a straight assignment and + left is a temp then prefer the temporary to the + true symbol */ + if (!POINTER_SET (cdp->diCode) && + IS_ITEMP (IC_RESULT (cdp->diCode)) && + IS_TRUE_SYMOP (IC_RIGHT (cdp->diCode))) + { + *opp = IC_RESULT (cdp->diCode); + } + else + { + /* if straight assignment and both + are temps then prefer the one that + will not need extra space to spil, also + take into consideration if right side + is an induction variable + */ + if (!POINTER_SET (cdp->diCode) && + IS_ITEMP (IC_RESULT (cdp->diCode)) && + IS_ITEMP (IC_RIGHT (cdp->diCode)) && + !OP_SYMBOL (IC_RIGHT (cdp->diCode))->isind && + !OP_SYMBOL(IC_RIGHT (cdp->diCode))->isreqv && + ((!SPIL_LOC (IC_RIGHT (cdp->diCode)) && SPIL_LOC (IC_RESULT (cdp->diCode))) || + (SPIL_LOC (IC_RESULT (cdp->diCode)) && SPIL_LOC (IC_RESULT (cdp->diCode)) == SPIL_LOC (IC_RIGHT (cdp->diCode))))) + { + *opp = IC_RESULT (cdp->diCode); + } + else + { + *opp = IC_RIGHT (cdp->diCode); + } + } + } + } + else + { + *opp = IC_RESULT (cdp->diCode); + } + } + + /* if this is an assign to a temp. then check + if the right side is this then return this */ + if (IS_TRUE_SYMOP (cop) && + cdp->diCode->op == '=' && + !POINTER_SET (cdp->diCode) && + cop->key == IC_RIGHT (cdp->diCode)->key && + !isGlobalInNearSpace (IC_RIGHT (cdp->diCode)) && + IS_ITEMP (IC_RESULT (cdp->diCode))) + { + *opp = IC_RESULT (cdp->diCode); + } + + if ((*opp) && + (isOperandLiteral(*opp) || !checkSign || + (checkSign && + IS_SPEC(operandType (cop)) && IS_SPEC(operandType (*opp)) && + (SPEC_USIGN(operandType (cop))==SPEC_USIGN(operandType (*opp)) && + (SPEC_LONG(operandType (cop))==SPEC_LONG(operandType (*opp))))))) + { + if ((isGlobalInNearSpace (cop) && !isOperandLiteral (*opp)) || + isOperandVolatile (*opp, FALSE)) + { + *opp = NULL; + return 0; + } + + if (cop->key == (*opp)->key) + { + *opp = NULL; + return 0; + } + + if ((*opp)->isaddr != cop->isaddr && IS_ITEMP (cop)) + { + *opp = operandFromOperand (*opp); + (*opp)->isaddr = cop->isaddr; + } + + /* copy signedness to literal operands */ + if (IS_SPEC(operandType (cop)) && IS_SPEC(operandType (*opp)) + && isOperandLiteral(*opp) + && SPEC_NOUN(operandType(*opp)) == SPEC_NOUN(operandType(cop)) + && SPEC_USIGN(operandType(*opp)) != SPEC_USIGN(operandType(cop))) + { + SPEC_USIGN(operandType(*opp)) = SPEC_USIGN(operandType(cop)); + } + + if (IS_SPEC(operandType (cop)) && IS_SPEC(operandType (*opp)) && + SPEC_NOUN(operandType(cop)) != SPEC_NOUN(operandType(*opp))) + { + // special case: we can make an unsigned char literal + // into an int literal with no cost. + if (isOperandLiteral(*opp) && + SPEC_NOUN(operandType(*opp)) == V_CHAR && + SPEC_NOUN(operandType(cop)) == V_INT) + { + *opp = operandFromOperand (*opp); + SPEC_NOUN(operandType(*opp)) = V_INT; + } + else + { + // No clue... + *opp = NULL; + return 0; + } + } + return 1; + } + *opp=NULL; + return 0; +} + +/*-----------------------------------------------------------------*/ +/* findPointerSet - finds the right side of a pointer set op */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (findPointerSet) +{ + cseDef *cdp = item; + V_ARG (operand *, op); + V_ARG (operand **, opp); + V_ARG (operand *, rop); + + if (POINTER_SET (cdp->diCode) && + op->key && + IC_RESULT (cdp->diCode)->key == op->key && + !isOperandVolatile (IC_RESULT (cdp->diCode), TRUE) && + !isOperandVolatile (IC_RIGHT (cdp->diCode), TRUE) && + getSize (operandType (IC_RIGHT (cdp->diCode))) == + getSize (operandType (rop))) + { + if (IS_SPEC (operandType (IC_RIGHT (cdp->diCode))) && + SPEC_USIGN (operandType (IC_RIGHT (cdp->diCode))) != + SPEC_USIGN (operandType (rop))) + { + /* bug #1493710 + Reminder for Bernhard: check of signedness + could be unnecessary together with 'checkSign', if + signedness of operation is stored in ic */ + return 0; + } + *opp = IC_RIGHT (cdp->diCode); + return 1; + } + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* findPrevIc - cseBBlock support function will return the iCode */ +/* which matches the current one */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (findPrevIc) +{ + cseDef *cdp = item; + V_ARG (iCode *, ic); + V_ARG (iCode **, icp); + + /* if already found */ + if (*icp) + return 1; + + /* if the iCodes are the same */ + if (isiCodeEqual (ic, cdp->diCode) && + isOperandEqual (cdp->sym, IC_RESULT (cdp->diCode))) + { + *icp = cdp->diCode; + return 1; + } + + /* if iCodes are not the same */ + /* see the operands maybe interchanged */ + if (ic->op == cdp->diCode->op && + IS_COMMUTATIVE (ic) && + isOperandEqual (IC_LEFT (ic), IC_RIGHT (cdp->diCode)) && + isOperandEqual (IC_RIGHT (ic), IC_LEFT (cdp->diCode))) + { + *icp = cdp->diCode; + return 1; + } + + return 0; +} + +/*-------------------------------------------------------------------*/ +/* ifAssignedFromGlobal - if definition is an assignment from global */ +/*-------------------------------------------------------------------*/ +DEFSETFUNC (ifAssignedFromGlobal) +{ + cseDef *cdp = item; + iCode *dic=cdp->diCode; + + if (dic->op=='=' && isOperandGlobal(IC_RIGHT(dic))) { + return 1; + } + return 0; +} + +/*-------------------------------------------------------------------*/ +/* ifFromGlobal - if definition is derived from global */ +/*-------------------------------------------------------------------*/ +DEFSETFUNC (ifFromGlobal) +{ + cseDef *cdp = item; + + return cdp->fromGlobal; +} + +/*-------------------------------------------------------------------*/ +/* ifFromGlobalAliasableByPtr - if definition is derived from global */ +/* that may be aliasble by a particular pointer type */ +/*-------------------------------------------------------------------*/ +DEFSETFUNC (ifFromGlobalAliasableByPtr) +{ + cseDef *cdp = item; + V_ARG (DECLARATOR_TYPE, decl); + + if (decl == GPOINTER && cdp->fromGlobal) + return 1; + else if (cdp->fromGlobal & (1 << decl)) + return 1; + else + return 0; +} + +/*-----------------------------------------------------------------*/ +/* ifDefGlobal - if definition is global */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (ifDefGlobal) +{ + cseDef *cdp = item; + + return (isOperandGlobal (cdp->sym)); +} + +/*-----------------------------------------------------------------*/ +/* ifDefGlobalAliasableByPtr - if definition is global */ +/* and may be aliasble by a particular pointer type */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (ifDefGlobalAliasableByPtr) +{ + cseDef *cdp = item; + V_ARG (DECLARATOR_TYPE, decl); + memmap *map; + + if (!isOperandGlobal (cdp->sym)) + return 0; + if (decl == GPOINTER) + return 1; + map = SPEC_OCLS (getSpec (operandType (cdp->sym))); + return (map->ptrType == decl); +} + +/*-------------------------------------------------------------------*/ +/* ifFromAddrTaken - if definition is derived from a symbol whose */ +/* address was taken */ +/*-------------------------------------------------------------------*/ +DEFSETFUNC (ifFromAddrTaken) +{ + cseDef *cdp = item; + + if (OP_SYMBOL(cdp->sym)->addrtaken) + return 1; + return cdp->fromAddrTaken; +} + + +/*-----------------------------------------------------------------*/ +/* ifAnyGetPointer - if get pointer icode */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (ifAnyGetPointer) +{ + cseDef *cdp = item; + + if (cdp->diCode && POINTER_GET (cdp->diCode)) + return 1; + return 0; +} + +/*-----------------------------------------------------------------*/ +/* ifAnyUnrestrictedGetPointer - if get pointer icode */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (ifAnyUnrestrictedGetPointer) +{ + cseDef *cdp = item; + V_ARG (DECLARATOR_TYPE, decl); + + if (cdp->diCode && POINTER_GET (cdp->diCode)) + { + sym_link *ptype; + ptype = operandType (IC_LEFT (cdp->diCode)); + if (!IS_PTR_RESTRICT (ptype)) + { + if (DCL_TYPE (ptype) == decl || IS_GENPTR (ptype)) + return 1; + } + } + return 0; +} + +/*-----------------------------------------------------------------*/ +/* ifAnyUnrestrictedSetPointer - if set pointer icode */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (ifAnyUnrestrictedSetPointer) +{ + cseDef *cdp = item; + V_ARG (DECLARATOR_TYPE, decl); + + if (cdp->diCode && POINTER_SET (cdp->diCode)) + { + sym_link *ptype; + ptype = operandType (IC_RESULT (cdp->diCode)); + if (!IS_PTR_RESTRICT (ptype)) + { + if (DCL_TYPE (ptype) == decl || IS_GENPTR (ptype)) + return 1; + } + } + return 0; +} + +/*-----------------------------------------------------------------*/ +/* ifOperandsHave - if any of the operand are the same as this */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (ifOperandsHave) +{ + cseDef *cdp = item; + V_ARG (operand *, op); + + if (bitVectBitValue(cdp->ancestors, op->key)) + return 1; + + if (IC_LEFT (cdp->diCode) && + IS_SYMOP (IC_LEFT (cdp->diCode)) && + IC_LEFT (cdp->diCode)->key == op->key) + return 1; + + if (IC_RIGHT (cdp->diCode) && + IS_SYMOP (IC_RIGHT (cdp->diCode)) && + IC_RIGHT (cdp->diCode)->key == op->key) + return 1; + + if (POINTER_SET (cdp->diCode) && + IS_SYMOP (IC_RESULT (cdp->diCode)) && + IC_RESULT (cdp->diCode)->key == op->key) + return 1; + + /* or if any of the operands are volatile */ + if (IC_LEFT (cdp->diCode) && + IS_OP_VOLATILE (IC_LEFT (cdp->diCode))) + return 1; + + if (IC_RIGHT (cdp->diCode) && + IS_OP_VOLATILE (IC_RIGHT (cdp->diCode))) + return 1; + + + if (IC_RESULT (cdp->diCode) && + IS_OP_VOLATILE (IC_RESULT (cdp->diCode))) + return 1; + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* ifDefSymIs - if a definition is found in the set */ +/*-----------------------------------------------------------------*/ +int +ifDefSymIs (set * cseSet, operand * sym) +{ + cseDef *loop; + set *sl; + + if (!sym || !IS_SYMOP (sym)) + return 0; + for (sl = cseSet; sl; sl = sl->next) + { + loop = sl->item; + if (loop->sym->key == sym->key) + return 1; + } + return 0; +} + + +/*-----------------------------------------------------------------*/ +/* ifDefSymIsX - will return 1 if the symbols match */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (ifDefSymIsX) +{ + cseDef *cdp = item; + V_ARG (operand *, op); + int match; + + if (op && cdp->sym && op->key) + match = cdp->sym->key == op->key; + else + match = (isOperandEqual (cdp->sym, op)); + #if 0 + if (match) + printf("%s ",OP_SYMBOL(cdp->sym)->name); + #endif + return match; +} + + +/*-----------------------------------------------------------------*/ +/* ifDiCodeIs - returns true if diCode is same */ +/*-----------------------------------------------------------------*/ +int +ifDiCodeIs (set * cseSet, iCode * ic) +{ + cseDef *loop; + set *sl; + + if (!ic) + return 0; + + for (sl = cseSet; sl; sl = sl->next) + { + loop = sl->item; + if (loop->diCode == ic) + return 1; + } + return 0; + +} + +/*-----------------------------------------------------------------*/ +/* ifPointerGet - returns true if the icode is pointer get sym */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (ifPointerGet) +{ + cseDef *cdp = item; + V_ARG (operand *, op); + iCode *dic = cdp->diCode; + operand *left = IC_LEFT (cdp->diCode); + + if (POINTER_GET (dic) && op->key && left->key == op->key) + return 1; + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* ifPointerSet - returns true if the icode is pointer set sym */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (ifPointerSet) +{ + cseDef *cdp = item; + V_ARG (operand *, op); + + if (POINTER_SET (cdp->diCode) && op->key && + IC_RESULT (cdp->diCode)->key == op->key) + return 1; + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* ifDiCodeIsX - will return 1 if the symbols match */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (ifDiCodeIsX) +{ + cseDef *cdp = item; + V_ARG (iCode *, ic); + + return cdp->diCode == ic; + +} + +/*-----------------------------------------------------------------*/ +/* findBackwardDef - scan backwards to find definition of operand */ +/*-----------------------------------------------------------------*/ +iCode *findBackwardDef(operand *op,iCode *ic) +{ + iCode *lic; + + for (lic = ic; lic ; lic = lic->prev) { + if (IC_RESULT(lic) && isOperandEqual(op,IC_RESULT(lic))) + return lic; + } + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* algebraicOpts - does some algebraic optimizations */ +/*-----------------------------------------------------------------*/ +static void +algebraicOpts (iCode * ic, eBBlock * ebp) +{ + /* we don't deal with the following iCodes + here */ + if (ic->op == IFX || + ic->op == IPUSH || + ic->op == IPOP || + ic->op == CALL || + ic->op == PCALL || + ic->op == RETURN || + POINTER_GET (ic)) + return; + + /* if both operands present & ! IFX */ + /* then if they are both literal we */ + /* perform the operation right now */ + if (IC_RESULT (ic) && + IC_RIGHT (ic) && + IC_LEFT (ic) && + IS_OP_LITERAL (IC_LEFT (ic)) && + IS_OP_LITERAL (IC_RIGHT (ic))) + { + IC_RIGHT (ic) = operandOperation (IC_LEFT (ic), + IC_RIGHT (ic), + ic->op, + operandType (IC_RESULT (ic))); + ic->op = '='; + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + return; + } + /* if not ifx & only one operand present */ + if (IC_RESULT (ic) && + IC_LEFT (ic) && + IS_OP_LITERAL (IC_LEFT (ic)) && + !IC_RIGHT (ic)) + { + IC_RIGHT (ic) = operandOperation (IC_LEFT (ic), + IC_RIGHT (ic), + ic->op, + operandType (IC_RESULT (ic))); + ic->op = '='; + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + return; + } + + /* a special case : or in short a kludgy solution will think + about a better solution over a glass of wine someday */ + if (ic->op == GET_VALUE_AT_ADDRESS) + { + if (IS_ITEMP (IC_RESULT (ic)) && + IS_TRUE_SYMOP (IC_LEFT (ic))) + { + ic->op = '='; + IC_RIGHT (ic) = operandFromOperand (IC_LEFT (ic)); + IC_RIGHT (ic)->isaddr = 0; + IC_LEFT (ic) = NULL; + IC_RESULT (ic) = operandFromOperand (IC_RESULT (ic)); + IC_RESULT (ic)->isaddr = 0; + setOperandType (IC_RESULT (ic), operandType (IC_RIGHT (ic))); + if (IS_DECL (operandType (IC_RESULT (ic)))) + { + DCL_PTR_VOLATILE (operandType (IC_RESULT (ic))) = 0; + DCL_PTR_ADDRSPACE (operandType (IC_RESULT (ic))) = 0; + } + return; + } + + if (IS_ITEMP (IC_LEFT (ic)) && + IS_ITEMP (IC_RESULT (ic)) && + !IC_LEFT (ic)->isaddr) + { + ic->op = '='; + IC_RIGHT (ic) = operandFromOperand (IC_LEFT (ic)); + IC_RIGHT (ic)->isaddr = 0; + IC_RESULT (ic) = operandFromOperand (IC_RESULT (ic)); + IC_RESULT (ic)->isaddr = 0; + IC_LEFT (ic) = NULL; + return; + } + } + + /* depending on the operation */ + switch (ic->op) + { + case '+': + /* if adding the same thing change to left shift by 1 */ + if (IC_LEFT (ic)->key == IC_RIGHT (ic)->key && + !IS_OP_VOLATILE (IC_LEFT (ic)) && + !(IS_FLOAT (operandType (IC_RESULT (ic))) + || IS_FIXED(operandType (IC_RESULT (ic))))) + { + ic->op = LEFT_OP; + IC_RIGHT (ic) = operandFromLit (1); + return; + } + /* if addition then check if one of them is a zero */ + /* if yes turn it into assignment or cast */ + if (IS_OP_LITERAL (IC_LEFT (ic)) && + isEqualVal (OP_VALUE (IC_LEFT (ic)), 0)) + { + int typematch; + typematch = compareType (operandType (IC_RESULT (ic)), + operandType (IC_RIGHT (ic))); + if ((typematch<0) || (IS_TRUE_SYMOP (IC_RIGHT (ic)))) + { + ic->op = CAST; + IC_LEFT (ic) = operandFromLink (operandType (IC_RESULT (ic))); + } + else + { + ic->op = '='; + IC_LEFT (ic) = NULL; + if (typematch==0) + { + /* for completely different types, preserve the source type */ + IC_RIGHT (ic) = operandFromOperand (IC_RIGHT (ic)); + setOperandType (IC_RIGHT (ic), operandType (IC_RESULT (ic))); + } + } + SET_ISADDR (IC_RESULT (ic), 0); + SET_ISADDR (IC_RIGHT (ic), 0); + return; + } + if (IS_OP_LITERAL (IC_RIGHT (ic)) && + isEqualVal (OP_VALUE (IC_RIGHT (ic)), 0)) + { + int typematch; + typematch = compareType (operandType (IC_RESULT (ic)), + operandType (IC_LEFT (ic))); + if ((typematch<0) || (IS_TRUE_SYMOP (IC_LEFT (ic)))) + { + ic->op = CAST; + IC_RIGHT (ic) = IC_LEFT (ic); + IC_LEFT (ic) = operandFromLink (operandType (IC_RESULT (ic))); + } + else + { + ic->op = '='; + IC_RIGHT (ic) = IC_LEFT (ic); + IC_LEFT (ic) = NULL; + if (typematch==0) + { + /* for completely different types, preserve the source type */ + IC_RIGHT (ic) = operandFromOperand (IC_RIGHT (ic)); + setOperandType (IC_RIGHT (ic), operandType (IC_RESULT (ic))); + } + } + SET_ISADDR (IC_RIGHT (ic), 0); + SET_ISADDR (IC_RESULT (ic), 0); + return; + } + break; + case '-': + /* if subtracting the same thing then zero */ + if (IC_LEFT (ic)->key == IC_RIGHT (ic)->key && + !IS_OP_VOLATILE (IC_LEFT (ic))) + {printf("Sub. at %d\n", ic->key); + ic->op = '='; + IC_RIGHT (ic) = operandFromLit (0); + IC_LEFT (ic) = NULL; + IC_RESULT (ic) = operandFromOperand (IC_RESULT (ic)); + IC_RESULT (ic)->isaddr = 0; + return; + } + + /* if subtraction then check if one of the operand */ + /* is zero then depending on which operand change */ + /* to assignment or unary minus */ + if (IS_OP_LITERAL (IC_RIGHT (ic)) && + isEqualVal (OP_VALUE (IC_RIGHT (ic)), 0)) + { + /* right size zero change to assignment */ + ic->op = '='; + IC_RIGHT (ic) = IC_LEFT (ic); + IC_LEFT (ic) = NULL; + SET_ISADDR (IC_RIGHT (ic), 0); + SET_ISADDR (IC_RESULT (ic), 0); + return; + } + if (IS_OP_LITERAL (IC_LEFT (ic)) && + isEqualVal (OP_VALUE (IC_LEFT (ic)), 0)) + { + /* left zero turn into an unary minus */ + ic->op = UNARYMINUS; + IC_LEFT (ic) = IC_RIGHT (ic); + IC_RIGHT (ic) = NULL; + return; + } + break; + /* if multiplication then check if either of */ + /* them is zero then the result is zero */ + /* if either of them is one then result is */ + /* the other one */ + case '*': + if (IS_OP_LITERAL (IC_LEFT (ic))) + { + if (isEqualVal (OP_VALUE (IC_LEFT (ic)), 0)) + { + ic->op = '='; + IC_RIGHT (ic) = IC_LEFT (ic); + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + return; + } + if (isEqualVal (OP_VALUE (IC_LEFT (ic)), 1)) + { + /* '*' can have two unsigned chars as operands */ + /* and an unsigned int as result. */ + if (compareType (operandType (IC_RESULT (ic)), + operandType (IC_RIGHT (ic))) == 1) + { + ic->op = '='; + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + } + else + { + ic->op = CAST; + IC_LEFT (ic) = operandFromOperand (IC_LEFT (ic)); + IC_LEFT (ic)->type = TYPE; + IC_LEFT (ic)->isLiteral = 0; + setOperandType (IC_LEFT (ic), operandType (IC_RESULT (ic))); + } + return; + } + if (isEqualVal (OP_VALUE (IC_LEFT (ic)), -1)) + { + /* convert -1 * x to -x */ + ic->op = UNARYMINUS; + IC_LEFT (ic) = IC_RIGHT (ic); + IC_RIGHT (ic) = NULL; + return; + } + } + + if (IS_OP_LITERAL (IC_RIGHT (ic))) + { + if (isEqualVal (OP_VALUE (IC_RIGHT (ic)), 0)) + { + ic->op = '='; + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + return; + } + + if (isEqualVal (OP_VALUE (IC_RIGHT (ic)), 1)) + { + /* '*' can have two unsigned chars as operands */ + /* and an unsigned int as result. */ + if (compareType (operandType (IC_RESULT (ic)), + operandType (IC_LEFT (ic))) == 1) + { + ic->op = '='; + IC_RIGHT (ic) = IC_LEFT (ic); + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + } + else + { + operand *op; + + ic->op = CAST; + op = IC_RIGHT (ic); + IC_RIGHT (ic) = IC_LEFT (ic); + IC_LEFT (ic) = operandFromOperand (op); + IC_LEFT (ic)->type = TYPE; + IC_LEFT (ic)->isLiteral = 0; + setOperandType (IC_LEFT (ic), operandType (IC_RESULT (ic))); + } + return; + } + if (isEqualVal (OP_VALUE (IC_RIGHT (ic)), -1)) + { + /* '*' can have two unsigned chars as operands */ + /* and an unsigned int as result. */ + if (IS_INTEGRAL (operandType (IC_LEFT (ic)))) + { + if ((getSize (operandType (IC_LEFT (ic))) < (unsigned int) INTSIZE) && + (getSize (operandType (IC_LEFT (ic))) < getSize (operandType (IC_RESULT (ic))))) + { + operand * op; + iCode * newic; + /* Widen to int. */ + op = operandFromOperand (IC_RESULT (ic)); + op->type = TYPE; + setOperandType (op, INTTYPE); + newic = newiCode (CAST, op, IC_LEFT (ic)); + IC_RESULT (newic) = newiTempOperand (INTTYPE, TRUE); + addiCodeToeBBlock (ebp, newic, ic); + IC_LEFT (ic) = IC_RESULT (newic); + } + } + /* convert x * -1 to -x */ + ic->op = UNARYMINUS; + IC_RIGHT (ic) = NULL; + return; + } + } + break; + case '/': + /* if division by self then 1 */ + if (IC_LEFT (ic)->key == IC_RIGHT (ic)->key) + { + ic->op = '='; + IC_RIGHT (ic) = operandFromLit (1); + IC_LEFT (ic) = NULL; + IC_RESULT (ic) = operandFromOperand (IC_RESULT (ic)); + IC_RESULT (ic)->isaddr = 0; + return; + } + /* if this is a division then check if left is zero */ + /* then change it to an assignment */ + if (IS_OP_LITERAL (IC_LEFT (ic)) && isEqualVal (OP_VALUE (IC_LEFT (ic)), 0)) + { + ic->op = '='; + IC_RIGHT (ic) = IC_LEFT (ic); + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + return; + } + /* if this is a division then check if right */ + /* is one then change it to an assignment */ + if (IS_OP_LITERAL (IC_RIGHT (ic))) + { + if (isEqualVal (OP_VALUE (IC_RIGHT (ic)), 1)) + { + ic->op = '='; + IC_RIGHT (ic) = IC_LEFT (ic); + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + return; + } + if (isEqualVal (OP_VALUE (IC_RIGHT (ic)), -1)) + { + /* '/' can have two unsigned chars as operands */ + /* and an unsigned int as result. */ + if (IS_INTEGRAL (operandType (IC_LEFT (ic)))) + { + if ((getSize (operandType (IC_LEFT (ic))) < (unsigned int) INTSIZE) && + (getSize (operandType (IC_LEFT (ic))) < getSize (operandType (IC_RESULT (ic))))) + { + operand * op; + iCode * newic; + /* Widen to int. */ + op = operandFromOperand (IC_RESULT (ic)); + op->type = TYPE; + setOperandType (op, INTTYPE); + newic = newiCode (CAST, op, IC_LEFT (ic)); + IC_RESULT (newic) = newiTempOperand (INTTYPE, TRUE); + addiCodeToeBBlock (ebp, newic, ic); + IC_LEFT (ic) = IC_RESULT (newic); + } + } + /* convert x / -1 to -x */ + ic->op = UNARYMINUS; + IC_RIGHT (ic) = NULL; + return; + } + } + break; + /* if both are the same for an comparison operators */ + case EQ_OP: + case LE_OP: + case GE_OP: + if (isOperandEqual (IC_LEFT (ic), IC_RIGHT (ic)) && + !IS_OP_VOLATILE (IC_LEFT (ic))) + { + ic->op = '='; + IC_RIGHT (ic) = operandFromLit (1); + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + } + break; + case NE_OP: + case '>': + case '<': + if (isOperandEqual (IC_LEFT (ic), IC_RIGHT (ic)) && + !IS_OP_VOLATILE (IC_LEFT (ic))) + { + ic->op = '='; + IC_RIGHT (ic) = operandFromLit (0); + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + } + break; + case CAST: + { + sym_link *otype = operandType(IC_RIGHT(ic)); + sym_link *ctype = operandType(IC_LEFT(ic)); + /* if this is a cast of a literal value */ + if (IS_OP_LITERAL (IC_RIGHT (ic))) + { + double litval = operandLitValue (IC_RIGHT (ic)); + if (IS_GENPTR(ctype) && IS_PTR(otype)) + { + unsigned long gpVal = 0; + const char *name = IS_SYMOP (IC_RESULT (ic)) ? OP_SYMBOL (IC_RESULT (ic))->name : NULL; + if (IS_FUNCPTR(otype)) + gpVal = pointerTypeToGPByte (DCL_TYPE (otype->next), NULL, name); + if (!IS_GENPTR(otype)) + gpVal = pointerTypeToGPByte (DCL_TYPE (otype), NULL, name); + gpVal <<= ((GPTRSIZE - 1) * 8); + gpVal |= (unsigned long)litval; + litval = gpVal; + } + ic->op = '='; + IC_RIGHT (ic) = operandFromValue (valCastLiteral (operandType (IC_LEFT (ic)), litval, litval)); + IC_LEFT (ic) = NULL; + SET_ISADDR (IC_RESULT (ic), 0); + } + /* if casting to the same */ + if (compareType (operandType (IC_RESULT (ic)), operandType (IC_RIGHT (ic))) == 1) + { + ic->op = '='; + IC_LEFT (ic) = NULL; + SET_ISADDR (IC_RESULT (ic), 0); + } + } + break; + case '!': + if (IS_OP_LITERAL (IC_LEFT (ic))) + { + ic->op = '='; + IC_RIGHT (ic) = + (isEqualVal (OP_VALUE (IC_LEFT (ic)), 0) ? + operandFromLit (1) : operandFromLit (0)); + IC_LEFT (ic) = NULL; + SET_ISADDR (IC_RESULT (ic), 0); + } + break; + case BITWISEAND: + /* if both operands are equal */ + /* if yes turn it into assignment */ + if (isOperandEqual (IC_LEFT (ic), IC_RIGHT (ic))) + { + if (IS_OP_VOLATILE (IC_LEFT (ic))) + { + iCode *newic = newiCode (DUMMY_READ_VOLATILE, NULL, IC_LEFT (ic)); + IC_RESULT (newic) = IC_LEFT (ic); + newic->filename = ic->filename; + newic->lineno = ic->lineno; + addiCodeToeBBlock (ebp, newic, ic->next); + } + ic->op = '='; + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + return; + } + /* swap literal to right ic */ + if (IS_OP_LITERAL (IC_LEFT (ic))) + { + operand *op; + + op = IC_LEFT (ic); + IC_LEFT (ic) = IC_RIGHT (ic); + IC_RIGHT (ic) = op; + } + if (IS_OP_LITERAL (IC_RIGHT (ic))) + { + unsigned val; + + /* if BITWISEAND then check if one of them is a zero */ + /* if yes turn it into 0 assignment */ + if (isEqualVal (OP_VALUE (IC_RIGHT (ic)), 0)) + { + if (IS_OP_VOLATILE (IC_LEFT (ic))) + { + iCode *newic = newiCode (DUMMY_READ_VOLATILE, NULL, IC_LEFT (ic)); + IC_RESULT (newic) = IC_LEFT (ic); + newic->filename = ic->filename; + newic->lineno = ic->lineno; + addiCodeToeBBlock (ebp, newic, ic->next); + } + ic->op = '='; + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + return; + } + /* if BITWISEAND then check if one of them is 0xff... */ + /* if yes turn it into assignment */ + if (IS_BOOLEAN (operandType (IC_RIGHT (ic)))) /* Special handling since _Bool is stored in 8 bits */ + goto boolcase; + switch (bitsForType (operandType (IC_RIGHT (ic)))) + { + case 1: + boolcase: + val = 0x01; + break; + case 8: + val = 0xff; + break; + case 16: + val = 0xffff; + break; + case 32: + val = 0xffffffff; + break; + default: + return; + } + if (((unsigned) double2ul (operandLitValue (IC_RIGHT (ic))) & val) == val) + { + ic->op = '='; + IC_RIGHT (ic) = IC_LEFT (ic); + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + return; + } + } + break; + case '|': + /* if both operands are equal */ + /* if yes turn it into assignment */ + if (isOperandEqual (IC_LEFT (ic), IC_RIGHT (ic))) + { + if (IS_OP_VOLATILE (IC_LEFT (ic))) + { + iCode *newic = newiCode (DUMMY_READ_VOLATILE, NULL, IC_LEFT (ic)); + IC_RESULT (newic) = IC_LEFT (ic); + newic->filename = ic->filename; + newic->lineno = ic->lineno; + addiCodeToeBBlock (ebp, newic, ic->next); + } + ic->op = '='; + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + return; + } + /* swap literal to right ic */ + if (IS_OP_LITERAL (IC_LEFT (ic))) + { + operand *op; + + op = IC_LEFT (ic); + IC_LEFT (ic) = IC_RIGHT (ic); + IC_RIGHT (ic) = op; + } + if (IS_OP_LITERAL (IC_RIGHT (ic))) + { + unsigned val; + + /* if BITWISEOR then check if one of them is a zero */ + /* if yes turn it into assignment */ + if (isEqualVal (OP_VALUE (IC_RIGHT (ic)), 0)) + { + ic->op = '='; + IC_RIGHT (ic) = IC_LEFT (ic); + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + return; + } + /* if BITWISEOR then check if one of them is 0xff... */ + /* if yes turn it into 0xff... assignment */ + switch (bitsForType (operandType (IC_RIGHT (ic)))) + { + case 1: + val = 0x01; + break; + case 8: + val = 0xff; + break; + case 16: + val = 0xffff; + break; + case 32: + val = 0xffffffff; + break; + default: + return; + } + if (((unsigned) double2ul (operandLitValue (IC_RIGHT (ic))) & val) == val) + { + if (IS_OP_VOLATILE (IC_LEFT (ic))) + { + iCode *newic = newiCode (DUMMY_READ_VOLATILE, NULL, IC_LEFT (ic)); + IC_RESULT (newic) = IC_LEFT (ic); + newic->filename = ic->filename; + newic->lineno = ic->lineno; + addiCodeToeBBlock (ebp, newic, ic->next); + } + ic->op = '='; + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + return; + } + } + break; + case '^': + /* if both operands are equal */ + /* if yes turn it into 0 assignment */ + if (isOperandEqual (IC_LEFT (ic), IC_RIGHT (ic))) + { + if (IS_OP_VOLATILE (IC_LEFT (ic))) + { + iCode *newic = newiCode (DUMMY_READ_VOLATILE, NULL, IC_LEFT (ic)); + IC_RESULT (newic) = IC_LEFT (ic); + newic->filename = ic->filename; + newic->lineno = ic->lineno; + addiCodeToeBBlock (ebp, newic, ic->next); + + newic = newiCode (DUMMY_READ_VOLATILE, NULL, IC_LEFT (ic)); + IC_RESULT (newic) = IC_LEFT (ic); + newic->filename = ic->filename; + newic->lineno = ic->lineno; + addiCodeToeBBlock (ebp, newic, ic->next); + } + ic->op = '='; + IC_RIGHT (ic) = operandFromLit (0); + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + return; + } + /* swap literal to right ic */ + if (IS_OP_LITERAL (IC_LEFT (ic))) + { + operand *op; + + op = IC_LEFT (ic); + IC_LEFT (ic) = IC_RIGHT (ic); + IC_RIGHT (ic) = op; + } + /* if XOR then check if one of them is a zero */ + /* if yes turn it into assignment */ + if (IS_OP_LITERAL (IC_RIGHT (ic))) + { + if (isEqualVal (OP_VALUE (IC_RIGHT (ic)), 0)) + { + ic->op = '='; + IC_RIGHT (ic) = IC_LEFT (ic); + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + return; + } + } + /* if XOR then check if one of them is a zero or one */ + /* if yes turn it into assignment or invert */ + if (IS_OP_LITERAL (IC_RIGHT (ic)) && + IS_BOOLEAN (operandType (IC_LEFT (ic))) && + IS_BOOLEAN (operandType (IC_RESULT (ic))) + ) + { + if (isEqualVal (OP_VALUE (IC_RIGHT (ic)), 1)) + { + ic->op = '!'; + IC_RIGHT (ic) = NULL; + return; + } + else + { + ic->op = '='; + IC_RIGHT (ic) = operandFromLit (1); + IC_LEFT (ic) = NULL; + SET_RESULT_RIGHT (ic); + return; + } + } + break; + } + + return; +} + +#define OTHERS_PARM(s) (s->_isparm && !s->ismyparm) +/*-----------------------------------------------------------------*/ +/* updateSpillLocation - keeps track of register spill location */ +/*-----------------------------------------------------------------*/ +void +updateSpillLocation (iCode * ic, int induction) +{ + sym_link *setype; + + if (POINTER_SET (ic)) + return; + + if (ic->nosupdate) + return; + +#if 0 + /* for the form true_symbol := iTempNN */ + if (ASSIGN_ITEMP_TO_SYM (ic) && + !SPIL_LOC (IC_RIGHT (ic))) + { + setype = getSpec (operandType (IC_RESULT (ic))); + + if (!OP_SYMBOL(IC_RIGHT (ic))->noSpilLoc && + !IS_VOLATILE (setype) && + !IN_FARSPACE (SPEC_OCLS (setype)) && + !OTHERS_PARM (OP_SYMBOL (IC_RESULT (ic)))) + { + wassert(IS_SYMOP(IC_RESULT (ic))); + wassert(IS_SYMOP(IC_RIGHT (ic))); + SPIL_LOC (IC_RIGHT (ic)) = IC_RESULT (ic)->operand.symOperand; + } + } +#endif + +#if 0 /* this needs furthur investigation can save a lot of code */ + if (ASSIGN_SYM_TO_ITEMP(ic) && + !SPIL_LOC(IC_RESULT(ic))) + { + if (!OTHERS_PARM (OP_SYMBOL (IC_RIGHT (ic)))) + SPIL_LOC (IC_RESULT (ic)) = IC_RIGHT (ic)->operand.symOperand; + } +#endif + if (ASSIGN_ITEMP_TO_ITEMP (ic)) + { + if (!SPIL_LOC (IC_RIGHT (ic)) && + !bitVectBitsInCommon (OP_DEFS (IC_RIGHT (ic)), OP_USES (IC_RESULT (ic))) && + OP_SYMBOL (IC_RESULT (ic))->isreqv) + { + setype = getSpec (operandType (IC_RESULT (ic))); + + if (!OP_SYMBOL(IC_RIGHT (ic))->noSpilLoc && + !IS_VOLATILE (setype) && + !IN_FARSPACE (SPEC_OCLS (setype)) && + !OTHERS_PARM (OP_SYMBOL (IC_RESULT (ic)))) + { + SPIL_LOC (IC_RIGHT (ic)) = SPIL_LOC (IC_RESULT (ic)); + OP_SYMBOL (IC_RIGHT (ic))->prereqv = OP_SYMBOL (IC_RESULT (ic))->prereqv; + } + } + /* special case for inductions */ + if (induction && + OP_SYMBOL(IC_RIGHT(ic))->isreqv && + !OP_SYMBOL(IC_RESULT (ic))->noSpilLoc && + !SPIL_LOC(IC_RESULT(ic))) + { + SPIL_LOC (IC_RESULT (ic)) = SPIL_LOC (IC_RIGHT (ic)); + OP_SYMBOL (IC_RESULT (ic))->prereqv = OP_SYMBOL (IC_RIGHT (ic))->prereqv; + } + } +} + +/*-----------------------------------------------------------------*/ +/* setUsesDef - sets the uses def bitvector for a given operand */ +/*-----------------------------------------------------------------*/ +void +setUsesDefs (operand * op, bitVect * bdefs, + bitVect * idefs, bitVect ** oud) +{ + /* compute the definitions alive at this point */ + bitVect *adefs = bitVectUnion (bdefs, idefs); + + /* of these definitions find the ones that are */ + /* for this operand */ + adefs = bitVectInplaceIntersect (adefs, OP_DEFS (op)); + + /* these are the definitions that this operand can use */ + /* Nothing uses op->usesDefs, so why? EEP - 2018-06-10 */ + //op->usesDefs = adefs; + + /* the out defs is an union */ + *oud = bitVectInplaceUnion (*oud, adefs); + + /* If not assigning op->usesDefs, we can safely free adefs */ + freeBitVect(adefs); +} + +/*-----------------------------------------------------------------*/ +/* unsetDefsAndUses - clear this operation for the operands */ +/*-----------------------------------------------------------------*/ +void +unsetDefsAndUses (iCode * ic) +{ + if (ic->op == JUMPTABLE) + { + if (IS_SYMOP (IC_JTCOND (ic))) + bitVectUnSetBit (OP_USES (IC_JTCOND (ic)), ic->key); + return; + } + + /* take away this definition from the def chain of the */ + /* result & take away from use set of the operands */ + if (ic->op != IFX) + { + /* turn off def set */ + if (IS_SYMOP (IC_RESULT (ic))) + { + if (!POINTER_SET (ic)) + bitVectUnSetBit (OP_DEFS (IC_RESULT (ic)), ic->key); + else + bitVectUnSetBit (OP_USES (IC_RESULT (ic)), ic->key); + } + /* turn off the useSet for the operands */ + if (IS_SYMOP (IC_LEFT (ic))) + bitVectUnSetBit (OP_USES (IC_LEFT (ic)), ic->key); + + if (IS_SYMOP (IC_RIGHT (ic))) + bitVectUnSetBit (OP_USES (IC_RIGHT (ic)), ic->key); + } + else + /* must be ifx turn off the use */ + if (IS_SYMOP (IC_COND (ic))) + bitVectUnSetBit (OP_USES (IC_COND (ic)), ic->key); +} + +/*-----------------------------------------------------------------*/ +/* ifxOptimize - changes ifx conditions if it can */ +/*-----------------------------------------------------------------*/ +void +ifxOptimize (iCode * ic, set * cseSet, + int computeOnly, + eBBlock * ebb, int *change, + ebbIndex * ebbi) +{ + operand *pdop; + symbol *label; + + /* if the condition can be replaced */ + if (!computeOnly) + { + pdop = NULL; + applyToSetFTrue (cseSet, findCheaperOp, IC_COND (ic), &pdop, 0); + if (pdop) + { + ReplaceOpWithCheaperOp(&IC_COND (ic), pdop); + (*change)++; + } + else if(ic->prev && /* Remove unnecessary casts */ + (ic->prev->op == '=' || ic->prev->op == CAST || ic->prev->op == '!') && IS_ITEMP (IC_RESULT (ic->prev)) && + IC_RESULT (ic->prev)->key == IC_COND (ic)->key && bitVectnBitsOn (OP_USES (IC_RESULT (ic->prev))) <= 1) + { + sym_link *type = operandType (IC_RESULT (ic->prev)); + if (ic->prev->op != CAST || IS_BOOL (type) || bitsForType (operandType (IC_RIGHT (ic->prev))) < bitsForType (type)) + { + if (!isOperandVolatile (ic->prev->op == '!' ? IC_LEFT (ic->prev) : IC_RIGHT (ic->prev), FALSE)) + { + if (ic->prev->op =='!') /* Invert jump logic */ + { + symbol *tmp = IC_TRUE (ic); + IC_TRUE (ic) = IC_FALSE (ic); + IC_FALSE (ic) = tmp; + } + bitVectUnSetBit (OP_USES (IC_COND (ic)), ic->key); + ReplaceOpWithCheaperOp(&IC_COND (ic), ic->prev->op == '!' ? IC_LEFT (ic->prev) : IC_RIGHT (ic->prev)); + (*change)++; + } +/* There's an optimization opportunity here, but OP_USES doesn't seem to be */ +/* initialized properly at this point. - EEP 2016-08-04 */ +#if 0 + else if (bitVectnBitsOn (OP_USES(IC_COND (ic))) == 1) + { + /* We can replace the iTemp with the original volatile symbol */ + /* but we must make sure the volatile symbol is still accessed */ + /* only once. */ + bitVectUnSetBit (OP_USES (IC_COND (ic)), ic->key); + ReplaceOpWithCheaperOp(&IC_COND (ic), IC_RIGHT (ic->prev)); + (*change)++; + /* Make previous assignment an assignment to self. */ + /* killDeadCode() will eliminiate it. */ + IC_RIGHT (ic->prev) = IC_RESULT (ic->prev); + IC_LEFT (ic->prev) = NULL; + ic->prev->op = '='; + } +#endif + } + } + } + + /* if the conditional is a literal then */ + if (IS_OP_LITERAL (IC_COND (ic))) + { + if ((operandLitValue (IC_COND (ic)) != 0.0) && IC_TRUE (ic)) + { + /* change to a goto */ + ic->op = GOTO; + IC_LABEL (ic) = IC_TRUE (ic); + (*change)++; + } + else + { + if (!operandLitValue (IC_COND (ic)) && IC_FALSE (ic)) + { + ic->op = GOTO; + IC_LABEL (ic) = IC_FALSE (ic); + (*change)++; + } + else + { + /* then kill this if condition */ + remiCodeFromeBBlock (ebb, ic); + } + } + + /* now we need to recompute the control flow */ + /* since the control flow has changed */ + /* this is very expensive but it does not happen */ + /* too often, if it does happen then the user pays */ + /* the price */ + computeControlFlow (ebbi); + werrorfl (ic->filename, ic->lineno, W_CONTROL_FLOW); + return; + } + + /* if there is only one successor and that successor + is the same one we are conditionally going to then + we can remove this conditional statement */ + label = (IC_TRUE (ic) ? IC_TRUE (ic) : IC_FALSE (ic)); + if (elementsInSet (ebb->succList) == 1 && + isinSet (ebb->succList, eBBWithEntryLabel (ebbi, label))) + { + werrorfl (ic->filename, ic->lineno, W_CONTROL_FLOW); + if (IS_OP_VOLATILE (IC_COND (ic))) + { + IC_RIGHT (ic) = IC_COND (ic); + IC_LEFT (ic) = NULL; + IC_RESULT (ic) = NULL; + ic->op = DUMMY_READ_VOLATILE; + } + else + { + remiCodeFromeBBlock (ebb, ic); + computeControlFlow (ebbi); + return; + } + } + + /* if it remains an IFX then update the use Set */ + if (ic->op == IFX) + { + OP_USES(IC_COND (ic))=bitVectSetBit (OP_USES (IC_COND (ic)), ic->key); + setUsesDefs (IC_COND (ic), ebb->defSet, ebb->outDefs, &ebb->usesDefs); + } + else if (ic->op == DUMMY_READ_VOLATILE) + { + OP_USES(IC_RIGHT (ic))=bitVectSetBit (OP_USES (IC_RIGHT (ic)), ic->key); + setUsesDefs (IC_RIGHT (ic), ebb->defSet, ebb->outDefs, &ebb->usesDefs); + } + return; +} + +/*-----------------------------------------------------------------*/ +/* diCodeForSym - finds the definiting instruction for a symbol */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (diCodeForSym) +{ + cseDef *cdp = item; + V_ARG (operand *, sym); + V_ARG (iCode **, dic); + + /* if already found */ + if (*dic) + return 0; + + /* if not if this is the defining iCode */ + if (sym->key == cdp->key) + { + *dic = cdp->diCode; + return 1; + } + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* constFold - does some constant folding */ +/*-----------------------------------------------------------------*/ +int +constFold (iCode * ic, set * cseSet) +{ + iCode *dic = NULL; + iCode *ldic = NULL; + /* this routine will change + a = b + 10; + c = a + 10; + to + c = b + 20; */ + + /* deal with only + & - */ + if (ic->op != '+' && + ic->op != '-' && + ic->op != BITWISEAND) + return 0; + + /* check if operation with a literal */ + if (!IS_OP_LITERAL (IC_RIGHT (ic))) + return 0; + + /* check if we can find a definition for the + left hand side */ + if (!(applyToSet (cseSet, diCodeForSym, IC_LEFT (ic), &dic))) + return 0; + + if (ic->op == BITWISEAND) /* Optimize out bitwise and of comparion results */ + { + /* check that this results in 0 or 1 only */ + if(dic->op != EQ_OP && dic->op != NE_OP && dic->op != LE_OP && dic->op != GE_OP && dic->op != '<' && dic->op != '>' && dic->op != '!') + return 0; + + IC_RIGHT (ic) = (operandLitValueUll (IC_RIGHT (ic)) & 1) ? IC_LEFT (ic) : operandFromLit (0); + + ic->op = '='; + IC_LEFT (ic) = 0; + + return 1; + } + + /* check that this is also a +/- */ + if (dic->op != '+' && dic->op != '-') + return 0; + + /* with a literal */ + if (!IS_OP_LITERAL (IC_RIGHT (dic))) + return 0; + + /* find the definition of the left operand + of dic.then check if this defined with a + get_pointer return 0 if the pointer size is + less than 2 (MCS51 specific) */ + if (!(applyToSet (cseSet, diCodeForSym, IC_LEFT (dic), &ldic))) + return 0; + + if (POINTER_GET (ldic) && getSize (operandType (IC_LEFT (ldic))) <= 1) + return 0; + + /* it is if the operations are the same */ + /* the literal parts need to be added */ + IC_LEFT (ic) = operandFromOperand (IC_LEFT (dic)); + if (ic->op == dic->op) + IC_RIGHT (ic) = operandFromLit (operandLitValue (IC_RIGHT (ic)) + + operandLitValue (IC_RIGHT (dic))); + else + IC_RIGHT (ic) = operandFromLit (operandLitValue (IC_RIGHT (ic)) - + operandLitValue (IC_RIGHT (dic))); + + if (IS_ITEMP (IC_RESULT (ic))) + { + SPIL_LOC (IC_RESULT (ic)) = NULL; + OP_SYMBOL(IC_RESULT (ic))->noSpilLoc = 1; + } + + return 1; +} + +/* Remove casts to bool from results of logical operations. */ +static int +boolCast (iCode * ic, set * cseSet) +{ + iCode *dic = NULL; + + /* Only casts to booleans are optimized away. */ + if (ic->op != CAST || !IS_BOOL ( operandType (IC_RESULT (ic)))) + return 0; + + /* Find the definition for the right hand side. */ + if (!(applyToSet (cseSet, diCodeForSym, IC_RIGHT (ic), &dic))) + return 0; + + /* Check that this is a logic op. */ + switch (dic->op) + { + case '!': + case '<': + case '>': + case LE_OP: + case GE_OP: + case EQ_OP: + case NE_OP: + case AND_OP: + case OR_OP: + case GETHBIT: + case GETABIT: + break; + case BITWISEAND: + if (IS_BOOL (operandType (IC_LEFT (dic))) || IS_BOOL (operandType (IC_RIGHT (dic)))) + break; + if (IS_OP_LITERAL (IC_RIGHT (dic)) && operandLitValue (IC_RIGHT (dic)) == 1) + break; + default: + return 0; + } + + /* Replace cast by assignment. */ + ic->op = '='; + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* deleteGetPointers - called when a pointer is passed as parm */ +/* will delete from cseSet all get pointers computed from this */ +/* pointer. A simple ifOperandsHave is not good enough here */ +/*-----------------------------------------------------------------*/ +static void +deleteGetPointers (set ** cseSet, set ** pss, operand * op, eBBlock * ebb) +{ + set *compItems = NULL; + cseDef *cdp; + operand *cop; + int changes; + + /* easy return */ + if (!*cseSet && !*pss) + return; + + addSet (&compItems, op); + + /* Recursively find all items computed from this operand . + This done fairly simply go thru the list and find + those that are computed by arthimetic with these + ops */ + /* Also check for those computed from our computed + list . This will take care of situations like + iTemp1 = iTemp0 + 8; + iTemp2 = iTemp1 + 8; */ + do + { + changes = 0; + for (cdp = setFirstItem (*cseSet); cdp; cdp = setNextItem (*cseSet)) + { + if (IS_ARITHMETIC_OP (cdp->diCode) || POINTER_GET(cdp->diCode)) + { + if (isinSetWith (compItems, (void*)IC_LEFT (cdp->diCode), + (insetwithFunc)isOperandEqual) || + isinSetWith (compItems, (void*)IC_RIGHT (cdp->diCode), + (insetwithFunc)isOperandEqual)) + { + if (!isinSetWith (compItems, (void*)IC_RESULT (cdp->diCode), + (insetwithFunc)isOperandEqual)) + { + addSet (&compItems, IC_RESULT (cdp->diCode)); + changes++; + } + } + } + } + } + while (changes); + + /* now for the computed items */ + for (cop = setFirstItem (compItems); cop; cop = setNextItem (compItems)) + { + ebb->ptrsSet = bitVectSetBit (ebb->ptrsSet, cop->key); + deleteItemIf (cseSet, ifPointerGet, cop); + deleteItemIf (cseSet, ifDefSymIsX, cop); + deleteItemIf (pss, ifPointerSet, cop); + } + deleteSet (&compItems); +} + +/*-----------------------------------------------------------------*/ +/* delGetPointerSucc - delete get pointer from inExprs of succ with */ +/* dfnum > supplied */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC (delGetPointerSucc) +{ + eBBlock *ebp = item; + V_ARG (operand *, op); + V_ARG (int, dfnum); + + if (ebp->visited) + return 0; + + ebp->visited = 1; + if (ebp->dfnum > dfnum) + { + deleteItemIf (&ebp->inExprs, ifPointerGet, op); + } + + return applyToSet (ebp->succList, delGetPointerSucc, op, dfnum); +} + +/*-----------------------------------------------------------------*/ +/* fixUpTypes - KLUGE HACK fixup a lowering problem */ +/*-----------------------------------------------------------------*/ +static void +fixUpTypes (iCode * ic) +{ + sym_link *t1 = operandType (IC_LEFT (ic)), *t2; + + /* if (TARGET_IS_DS390) */ + if (options.model == MODEL_FLAT24) + { + /* hack-o-matic! */ + return; + } + + /* for pointer_gets if the types of result & left r the + same then change it type of result to next */ + if (IS_PTR (t1) && + compareType (t2 = operandType (IC_RESULT (ic)), t1) == 1) + { + setOperandType (IC_RESULT (ic), t2->next); + } +} + +/*-----------------------------------------------------------------*/ +/* isSignedOp - will return 1 if sign is important to operation */ +/*-----------------------------------------------------------------*/ +static int isSignedOp (iCode *ic) +{ + switch (ic->op) { + case '!': + case '~': + case UNARYMINUS: + case IPUSH: + case IPOP: + case CALL: + case PCALL: + case RETURN: + case '+': + case '-': + case EQ_OP: + case AND_OP: + case OR_OP: + case '^': + case '|': + case BITWISEAND: + case INLINEASM: + case LEFT_OP: + case GET_VALUE_AT_ADDRESS: + case '=': + case IFX: + case RECEIVE: + case SEND: + return 0; + case '*': + case '/': + case '%': + case '>': + case '<': + case LE_OP: + case GE_OP: + case NE_OP: + case RRC: + case RLC: + case GETHBIT: + case GETABIT: + case GETBYTE: + case GETWORD: + case RIGHT_OP: + case CAST: + case ARRAYINIT: + return 1; + default: + return 0; + } + } + +#if 0 +static void +dumpCseSet(set *cseSet) +{ + while (cseSet) + { + cseDef *item=cseSet->item; + printf("->"); + printOperand (item->sym, NULL); + printf(" "); + piCode (item->diCode, NULL); + cseSet = cseSet->next; + } +} +#endif + +/*-----------------------------------------------------------------*/ +/* cseBBlock - common subexpression elimination for basic blocks */ +/* this is the hackiest kludgiest routine in the whole */ +/* system. also the most important, since almost all */ +/* data flow related information is computed by it */ +/*-----------------------------------------------------------------*/ +int +cseBBlock (eBBlock * ebb, int computeOnly, ebbIndex * ebbi) +{ + eBBlock ** ebbs = ebbi->bbOrder; + int count = ebbi->count; + set *cseSet; + set *setnode; + iCode *ic; + int change = 0; + int i; + set *ptrSetSet = NULL; + cseDef *expr; + int replaced; + int recomputeDataFlow = 0; + + /* if this block is not reachable */ + if (ebb->noPath) + { + for (ic = ebb->sch; ic; ic = ic->next) + if (!SKIP_IC2 (ic)) + unsetDefsAndUses (ic); + return 0; + } + + /* Mark incoming subexpressions as non-local */ + for (setnode = ebb->inExprs; setnode; setnode = setnode->next) + { + expr = (cseDef *)setnode->item; + expr->nonLocalCSE = 1; + } + /* set of common subexpressions */ + cseSet = setFromSet (ebb->inExprs); + + + /* these will be computed by this routine */ + freeBitVect(ebb->outDefs); ebb->outDefs = NULL; + freeBitVect(ebb->defSet); ebb->defSet = NULL; + freeBitVect(ebb->usesDefs); ebb->usesDefs = NULL; + freeBitVect(ebb->ptrsSet); ebb->ptrsSet = NULL; + deleteSet(&ebb->addrOf); + freeBitVect(ebb->ldefs); ebb->ldefs = NULL; + ebb->outDefs = bitVectCopy (ebb->inDefs); + bitVectDefault = iCodeKey; + ebb->defSet = newBitVect (iCodeKey); + ebb->usesDefs = newBitVect (iCodeKey); + + /* for all the instructions in this block do */ + for (ic = ebb->sch; ic; ic = ic->next) + { + iCode *pdic; + operand *pdop; + iCode *defic; + int checkSign ; + + ic->eBBlockNum = ebb->bbnum; + + if (SKIP_IC2 (ic)) + continue; + + /* if this is an assignment from true symbol + to a temp then do pointer post inc/dec optimization */ + if (ic->op == '=' && !POINTER_SET (ic) && + IS_PTR (operandType (IC_RESULT (ic)))) + { + ptrPostIncDecOpt (ic, ebb); + } + + /* clear the def & use chains for the operands involved */ + /* in this operation since it can change due to opts */ + unsetDefsAndUses (ic); + + if (ic->op == PCALL || ic->op == CALL || ic->op == RECEIVE) + { + /* add to defSet of the symbol */ + OP_DEFS (IC_RESULT (ic)) = bitVectSetBit (OP_DEFS (IC_RESULT (ic)), ic->key); + /* add to the definition set of this block */ + ebb->defSet = bitVectSetBit (ebb->defSet, ic->key); + ebb->ldefs = bitVectSetBit (ebb->ldefs, ic->key); + ebb->outDefs = bitVectCplAnd (ebb->outDefs, OP_DEFS (IC_RESULT (ic))); + setUsesDefs (IC_RESULT (ic), ebb->defSet, ebb->outDefs, &ebb->usesDefs); + /* delete global variables from the cseSet + since they can be modified by the function call */ + destructItemIf (&cseSet, freeLocalCseDef, ifDefGlobal); + + /* and also iTemps derived from globals */ + destructItemIf (&cseSet, freeLocalCseDef, ifFromGlobal); + + /* Delete iTemps derived from symbols whose address */ + /* has been taken */ + destructItemIf (&cseSet, freeLocalCseDef, ifFromAddrTaken); + + /* delete all getpointer iCodes from cseSet, this should + be done only for global arrays & pointers but at this + point we don't know if globals, so to be safe do all */ + destructItemIf (&cseSet, freeLocalCseDef, ifAnyGetPointer); + + /* can't cache pointer set/get operations across a call */ + deleteSet (&ptrSetSet); + } + + /* for pcall & ipush we need to add to the useSet */ + if ((ic->op == PCALL || + ic->op == IPUSH || + ic->op == IPOP || + ic->op == SEND) && + IS_SYMOP (IC_LEFT (ic))) + { + /* check if they can be replaced */ + if (!computeOnly) + { + pdop = NULL; + applyToSetFTrue (cseSet, findCheaperOp, IC_LEFT (ic), &pdop, 0); + if (pdop) + ReplaceOpWithCheaperOp(&IC_LEFT(ic), pdop); + } + /* the lookup could have changed it */ + if (IS_SYMOP (IC_LEFT (ic))) + { + OP_USES(IC_LEFT (ic))= + bitVectSetBit (OP_USES (IC_LEFT (ic)), ic->key); + setUsesDefs (IC_LEFT (ic), ebb->defSet, + ebb->outDefs, &ebb->usesDefs); + } + + /* if we are sending a pointer as a parameter + then kill all cse since the pointed to item + might be changed in the function being called */ + if ((ic->op == IPUSH || ic->op == SEND) && + IS_PTR (operandType (IC_LEFT (ic)))) + { + deleteGetPointers (&cseSet, &ptrSetSet, IC_LEFT (ic), ebb); + ebb->ptrsSet = bitVectSetBit (ebb->ptrsSet, IC_LEFT (ic)->key); + for (i = 0; i < count; ebbs[i++]->visited = 0); + applyToSet (ebb->succList, delGetPointerSucc, + IC_LEFT (ic), ebb->dfnum); + } + continue; + } + + /* if jumptable then mark the usage */ + if (ic->op == JUMPTABLE) + { + if (IS_SYMOP (IC_JTCOND (ic))) + { + OP_USES(IC_JTCOND (ic)) = + bitVectSetBit (OP_USES (IC_JTCOND (ic)), ic->key); + setUsesDefs (IC_JTCOND (ic), ebb->defSet, + ebb->outDefs, &ebb->usesDefs); + } + continue; + } + + if (SKIP_IC (ic)) + continue; + + if (!computeOnly) + { + /* do some algebraic optimizations if possible */ + algebraicOpts (ic, ebb); + while (constFold (ic, cseSet)); + while (boolCast (ic, cseSet)); + } + + /* small kludge */ + if (POINTER_GET (ic)) + { + if (!IS_PTR (operandType (IC_LEFT (ic)))) + { + setOperandType (IC_LEFT (ic), + aggrToPtr (operandType (IC_LEFT (ic)), FALSE)); + IC_LEFT (ic)->aggr2ptr = 0; + fixUpTypes (ic); + } + else if (IC_LEFT (ic)->aggr2ptr == 1) + {/* band aid for kludge */ + setOperandType (IC_LEFT (ic), + aggrToPtr (operandType (IC_LEFT (ic)), TRUE)); + IC_LEFT (ic)->aggr2ptr++; + fixUpTypes (ic); + } + } + + if (POINTER_SET (ic)) + { + if (!IS_PTR (operandType (IC_RESULT (ic)))) + { + setOperandType (IC_RESULT (ic), + aggrToPtr (operandType (IC_RESULT (ic)), FALSE)); + IC_RESULT (ic)->aggr2ptr = 0; + } + else if (IC_RESULT (ic)->aggr2ptr == 1) + {/* band aid for kludge */ + setOperandType (IC_RESULT (ic), + aggrToPtr (operandType (IC_RESULT (ic)), TRUE)); + IC_RESULT (ic)->aggr2ptr++; + } + } + + /* if this is a condition statement then */ + /* check if the condition can be replaced */ + if (ic->op == IFX) + { + ifxOptimize (ic, cseSet, computeOnly, ebb, &change, ebbi); + continue; + } + + /* if the assignment & result is a temp */ + /* see if we can replace it */ + if (!computeOnly && ic->op == '=') + { + /* update the spill location for this */ + updateSpillLocation (ic, 0); + + if (POINTER_SET (ic) && IS_SYMOP (IC_RESULT (ic)) && + !(IS_BITFIELD (OP_SYMBOL (IC_RESULT (ic))->etype))) + { + pdop = NULL; + applyToSetFTrue (cseSet, findCheaperOp, IC_RESULT (ic), &pdop, 0); + if (pdop && !computeOnly && IS_ITEMP (pdop)) + { + ReplaceOpWithCheaperOp (&IC_RESULT(ic), pdop); + if (!IS_PTR (operandType (IC_RESULT (ic)))) + { + setOperandType (IC_RESULT (ic), + aggrToPtr (operandType (IC_RESULT (ic)), FALSE)); + } + } + } + } + + checkSign = isSignedOp(ic); + replaced = 0; + + /* do the operand lookup i.e. for both the */ + /* right & left operand : check the cseSet */ + /* to see if they have been replaced if yes */ + /* then replace them with those from cseSet */ + /* left operand */ + /* and left is a symbol */ + if (!computeOnly && + ic->op != ADDRESS_OF && + IS_SYMOP (IC_LEFT (ic)) && + !IS_BITFIELD (OP_SYM_ETYPE (IC_LEFT (ic)))) + { + pdop = NULL; + applyToSetFTrue (cseSet, findCheaperOp, IC_LEFT (ic), &pdop, checkSign); + if (pdop) + { + if (POINTER_GET (ic)) + { + if (IS_ITEMP (pdop) || IS_OP_LITERAL (pdop)) + { + /* some non dominating block does POINTER_SET with + this variable .. unsafe to remove any POINTER_GETs */ + if (bitVectBitValue (ebb->ndompset, IC_LEFT (ic)->key)) + ebb->ptrsSet = bitVectSetBit (ebb->ptrsSet, pdop->key); + ReplaceOpWithCheaperOp (&IC_LEFT (ic), pdop); + change = replaced = 1; + } + /* check if there is a pointer set + for the same pointer visible if yes + then change this into an assignment */ + pdop = NULL; + if (applyToSetFTrue (cseSet, findPointerSet, IC_LEFT (ic), &pdop, IC_RESULT (ic)) && + !bitVectBitValue (ebb->ptrsSet, pdop->key)) + { + ic->op = '='; + IC_LEFT (ic) = NULL; + ReplaceOpWithCheaperOp (&IC_RIGHT (ic), pdop); + SET_ISADDR (IC_RESULT (ic), 0); + replaced = 1; + } + } + else + { + ReplaceOpWithCheaperOp (&IC_LEFT (ic), pdop); + change = replaced = 1; + } + } + } + + /* right operand */ + if (!computeOnly && IS_SYMOP (IC_RIGHT (ic))) + { + pdop = NULL; + applyToSetFTrue (cseSet, findCheaperOp, IC_RIGHT (ic), &pdop, checkSign); + if (pdop) + { + ReplaceOpWithCheaperOp (&IC_RIGHT (ic), pdop); + change = replaced = 1; + } + } + + if (!computeOnly && + POINTER_SET (ic) && + IS_SYMOP (IC_RESULT (ic)) && + !IS_BITFIELD (OP_SYM_ETYPE (IC_RESULT (ic)))) + { + pdop = NULL; + applyToSetFTrue (cseSet, findCheaperOp, IC_RESULT (ic), &pdop, checkSign); + if (pdop) + { + ReplaceOpWithCheaperOp (&IC_RESULT (ic), pdop); + change = 1; + } + } + + /* if left or right changed then do algebraic */ + if (!computeOnly && change) + { + algebraicOpts (ic, ebb); + while (constFold (ic, cseSet)); + while (boolCast (ic, cseSet)); + } + + /* if after all this it becomes an assignment to self + then delete it and continue */ + if (ASSIGNMENT_TO_SELF (ic) && !isOperandVolatile (IC_RIGHT(ic), FALSE)) + { + bitVectUnSetBit (OP_DEFS (IC_RESULT (ic)), ic->key); + if (IS_SYMOP (IC_RIGHT (ic))) + bitVectUnSetBit (OP_USES (IC_RIGHT (ic)), ic->key); + remiCodeFromeBBlock (ebb, ic); + continue; + } + + /* now we will check to see if the entire */ + /* operation has been performed before */ + /* and is available */ + /* don't do assignments they will be killed */ + /* by dead code elimination if required do */ + /* it only if result is a temporary */ + pdic = NULL; + if (!(POINTER_GET (ic) && + (IS_BITFIELD (OP_SYMBOL (IC_RESULT (ic))->etype) || + isOperandVolatile (IC_LEFT (ic), TRUE) || IS_VOLATILE (operandType (IC_LEFT (ic))->next) || + bitVectBitValue (ebb->ndompset, IC_LEFT (ic)->key))) && + !ASSIGNMENT (ic) && + IS_ITEMP (IC_RESULT (ic)) && + !computeOnly) + { + applyToSet (cseSet, findPrevIc, ic, &pdic); + if (pdic && compareType (operandType (IC_RESULT (pdic)), + operandType (IC_RESULT (ic))) != 1) + { + pdic = NULL; + } + if (pdic && port->cseOk && (*port->cseOk)(ic, pdic) == 0) + { + pdic = NULL; + } + } + + /* Alternate code */ + if (pdic && IS_ITEMP (IC_RESULT (ic))) + { + if (POINTER_GET (ic) && bitVectBitValue (ebb->ptrsSet, IC_LEFT (ic)->key)) + { + /* Mmm, found an equivalent pointer get at a lower level. + This could be a loop however with the same pointer set + later on */ + } + else + { + /* if previous definition found change this to an assignment */ + ic->op = '='; + IC_LEFT (ic) = NULL; + IC_RIGHT (ic) = operandFromOperand (IC_RESULT (pdic)); + SET_ISADDR (IC_RESULT (ic), 0); + SET_ISADDR (IC_RIGHT (ic), 0); + } + } + + if (!(POINTER_SET (ic)) && IC_RESULT (ic)) + { + cseDef *csed; + destructItemIf (&cseSet, freeLocalCseDef, ifDefSymIsX, IC_RESULT (ic)); + csed = newCseDef (IC_RESULT (ic), ic); + updateCseDefAncestors (csed, cseSet); + addSetHead (&cseSet, csed); + } + defic = ic; + + /* if assignment to a parameter which is not + mine and type is a pointer then delete + pointerGets to take care of aliasing */ + if (ASSIGNMENT (ic) && + IS_SYMOP (IC_RESULT (ic)) && + OTHERS_PARM (OP_SYMBOL (IC_RESULT (ic))) && + IS_PTR (operandType (IC_RESULT (ic)))) + { + deleteGetPointers (&cseSet, &ptrSetSet, IC_RIGHT (ic), ebb); + for (i = 0; i < count; ebbs[i++]->visited = 0); + applyToSet (ebb->succList, delGetPointerSucc, IC_RIGHT (ic), ebb->dfnum); + ebb->ptrsSet = bitVectSetBit (ebb->ptrsSet, IC_RIGHT (ic)->key); + } + + /* if this is a pointerget then see if we can replace + this with a previously assigned pointer value */ + if (POINTER_GET (ic) && + !(IS_BITFIELD (OP_SYMBOL (IC_RESULT (ic))->etype) || + isOperandVolatile (IC_LEFT (ic), TRUE))) + { + pdop = NULL; + applyToSet (ptrSetSet, findPointerSet, IC_LEFT (ic), &pdop, IC_RESULT (ic)); + /* if we find it then locally replace all + references to the result with what we assigned */ + if (pdop) + { + replaceAllSymBySym (ic->next, IC_RESULT (ic), pdop, &ebb->ndompset); + } + } + + /* delete from the cseSet anything that has */ + /* operands matching the result of this */ + /* except in case of pointer access */ + if (!(POINTER_SET (ic)) && IS_SYMOP (IC_RESULT (ic))) + { + destructItemIf (&cseSet, freeLocalCseDef, ifOperandsHave, IC_RESULT (ic)); + deleteItemIf (&ptrSetSet, ifOperandsHave, IC_RESULT (ic)); + /* delete any previous definitions */ + ebb->defSet = bitVectCplAnd (ebb->defSet, OP_DEFS (IC_RESULT (ic))); + + /* Until pointer tracking is complete, by conservative and delete all */ + /* pointer accesses that might alias this symbol. */ + if (isOperandGlobal (IC_RESULT (ic)) || OP_SYMBOL (IC_RESULT (ic))->addrtaken) + { + memmap *map = SPEC_OCLS (getSpec (operandType (IC_RESULT (ic)))); + destructItemIf (&cseSet, freeLocalCseDef, ifAnyUnrestrictedGetPointer, map->ptrType); + deleteItemIf (&ptrSetSet, ifAnyUnrestrictedSetPointer, map->ptrType); + } + } + + /* add the left & right to the defUse set */ + if (IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic))) + { + OP_USES (IC_LEFT (ic)) = + bitVectSetBit (OP_USES (IC_LEFT (ic)), ic->key); + setUsesDefs (IC_LEFT (ic), ebb->defSet, ebb->outDefs, &ebb->usesDefs); + } + + if (IC_RIGHT (ic) && IS_SYMOP (IC_RIGHT (ic))) + { + OP_USES (IC_RIGHT (ic)) = + bitVectSetBit (OP_USES (IC_RIGHT (ic)), ic->key); + setUsesDefs (IC_RIGHT (ic), ebb->defSet, ebb->outDefs, &ebb->usesDefs); + } + + /* for the result it is special case, put the result */ + /* in the defuseSet if it is a pointer or array access */ + if (POINTER_SET (defic) && + (IS_SYMOP (IC_RESULT (ic)) || IS_OP_LITERAL (IC_RESULT (ic)))) + { + sym_link *ptype = operandType (IC_RESULT (ic)); + + if (IS_SYMOP (IC_RESULT (ic))) + { + OP_USES (IC_RESULT (ic)) = + bitVectSetBit (OP_USES (IC_RESULT (ic)), ic->key); + setUsesDefs (IC_RESULT (ic), ebb->defSet, ebb->outDefs, &ebb->usesDefs); + } + deleteItemIf (&cseSet, ifPointerGet, IC_RESULT (ic)); + ebb->ptrsSet = bitVectSetBit (ebb->ptrsSet, IC_RESULT (ic)->key); + /* delete from inexpressions of all successors which + have dfNum > than this block */ + for (i = 0; i < count; ebbs[i++]->visited = 0); + applyToSet (ebb->succList, delGetPointerSucc, IC_RESULT (ic), ebb->dfnum); + + /* delete from cseSet all other pointer sets + for this operand */ + deleteItemIf (&ptrSetSet, ifPointerSet, IC_RESULT (ic)); + /* add to the local pointerset set */ + addSetHead (&ptrSetSet, newCseDef (IC_RESULT (ic), ic)); + + /* A write via a non-restrict pointer may modify a global */ + /* variable used by this function, so delete them */ + /* and any derived symbols from cseSet. */ + if (!IS_PTR_RESTRICT (ptype)) + { + destructItemIf (&cseSet, freeLocalCseDef, ifDefGlobalAliasableByPtr, DCL_TYPE(ptype)); + destructItemIf (&cseSet, freeLocalCseDef, ifFromGlobalAliasableByPtr, DCL_TYPE(ptype)); + } + + /* This could be made more specific for better optimization, but */ + /* for safety, delete anything this write may have modified. */ + destructItemIf (&cseSet, freeLocalCseDef, ifFromAddrTaken); + destructItemIf (&cseSet, freeLocalCseDef, ifAnyGetPointer); + } + else + { + /* add the result to definition set */ + if (IS_SYMOP (IC_RESULT (ic))) + { + OP_DEFS(IC_RESULT (ic))= + bitVectSetBit (OP_DEFS (IC_RESULT (ic)), ic->key); + ebb->defSet = bitVectSetBit (ebb->defSet, ic->key); + ebb->outDefs = bitVectCplAnd (ebb->outDefs, OP_DEFS (IC_RESULT (ic))); + ebb->ldefs = bitVectSetBit (ebb->ldefs, ic->key); + } + } + + /* if this is an addressof instruction then */ + /* put the symbol in the address of list & */ + /* delete it from the cseSet */ + if (defic->op == ADDRESS_OF) + { + addSetHead (&ebb->addrOf, IC_LEFT (ic)); + destructItemIf (&cseSet, freeLocalCseDef, ifDefSymIsX, IC_LEFT (ic)); + } + + /* If this was previously in the out expressions in the */ + /* original form, it might need to be killed by another block */ + /* in the new form if we have replaced operands, so recompute */ + /* the data flow after we finish this block */ + if (replaced && ifDiCodeIs (ebb->outExprs, ic)) + recomputeDataFlow = 1; + } + + for (expr=setFirstItem (ebb->inExprs); expr; expr=setNextItem (ebb->inExprs)) + if (!isinSetWith (cseSet, expr, isCseDefEqual) && + !isinSetWith (ebb->killedExprs, expr, isCseDefEqual)) + { + addSetHead (&ebb->killedExprs, expr); + } + + deleteSet (&ptrSetSet); + deleteSet (&ebb->outExprs); + ebb->outExprs = cseSet; + ebb->outDefs = bitVectInplaceUnion (ebb->outDefs, ebb->defSet); + ebb->ptrsSet = bitVectInplaceUnion (ebb->ptrsSet, ebb->inPtrsSet); + + for (setnode = ebb->outExprs; setnode; setnode = setnode->next) + { + expr = (cseDef *)setnode->item; + expr->nonLocalCSE = 1; + } + + if (recomputeDataFlow) + computeDataFlow (ebbi); + + return change; +} + +/*------------------------------------------------------------------*/ +/* cseAllBlocks - will sequentially go thru & do cse for all blocks */ +/*------------------------------------------------------------------*/ +int +cseAllBlocks (ebbIndex * ebbi, int computeOnly) +{ + eBBlock ** ebbs = ebbi->dfOrder; + int count = ebbi->count; + int i; + int change = 0; + + /* if optimization turned off */ + + for (i = 0; i < count; i++) + change += cseBBlock (ebbs[i], computeOnly, ebbi); + + return change; +} + + +/*------------------------------------------------------------------*/ +/* freeCSEdata - free data created by cseBBlock */ +/*------------------------------------------------------------------*/ +void +freeCSEdata (eBBlock * ebb) +{ + set * s; + + /* We should really free the cseDefs too, but I haven't */ + /* found a good way to do this yet. For the moment, at */ + /* least free up the associated bitVects - EEP */ + for (s = ebb->outExprs; s; s = s->next) + { + cseDef *cdp = s->item; + if (!cdp) continue; + if (cdp->ancestors) + { + freeBitVect (cdp->ancestors); + cdp->ancestors = NULL; + } + } + + deleteSet (&ebb->inExprs); + deleteSet (&ebb->outExprs); + deleteSet (&ebb->killedExprs); + + freeBitVect (ebb->inDefs); + freeBitVect (ebb->outDefs); + freeBitVect (ebb->defSet); + freeBitVect (ebb->ldefs); + freeBitVect (ebb->usesDefs); + freeBitVect (ebb->ptrsSet); + freeBitVect (ebb->inPtrsSet); + freeBitVect (ebb->ndompset); + deleteSet (&ebb->addrOf); + +} |
