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/SDCCptropt.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/SDCCptropt.c')
| -rw-r--r-- | src/SDCCptropt.c | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/src/SDCCptropt.c b/src/SDCCptropt.c new file mode 100644 index 0000000..8f706dc --- /dev/null +++ b/src/SDCCptropt.c @@ -0,0 +1,420 @@ +/*------------------------------------------------------------------------- + + SDCCptropt.c - source file for pointer arithmetic Optimizations + + 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" + +/*-----------------------------------------------------------------------*/ +/* findPointerGetSet - find the pointer get or set for a operand */ +/*-----------------------------------------------------------------------*/ +static iCode * +findPointerGetSet (iCode * sic, operand * op) +{ + iCode *ic = sic; + + for (; ic; ic = ic->next) + { + if ((POINTER_SET (ic) && isOperandEqual (op, IC_RESULT (ic))) || (POINTER_GET (ic) && isOperandEqual (op, IC_LEFT (ic)))) + return ic; + + /* if we find any other usage or definition of op null */ + if (IC_RESULT (ic) && isOperandEqual (IC_RESULT (ic), op)) + return NULL; + + if (IC_RIGHT (ic) && isOperandEqual (IC_RIGHT (ic), op)) + return NULL; + + if (IC_LEFT (ic) && isOperandEqual (IC_LEFT (ic), op)) + return NULL; + + } + + return NULL; +} + +static int +pattern1 (iCode * sic, eBBlock * ebb) +{ + /* this is what we do. look for sequences like + + iTempX := _SOME_POINTER_; + iTempY := _SOME_POINTER_ + nn ; nn = sizeof (pointed to object) sic->next + _SOME_POINTER_ := iTempY; sic->next->next + either + iTempZ := @[iTempX]; sic->next->next->next + or + *(iTempX) := ..something.. sic->next->next->next + if we find this then transform this to + iTempX := _SOME_POINTER_; + either + iTempZ := @[iTempX]; + or + *(iTempX) := ..something.. + iTempY := _SOME_POINTER_ + nn ; nn = sizeof (pointed to object) + _SOME_POINTER_ := iTempY; */ + + /* sounds simple enough so let's start , here I use negative + tests all the way to return if any test fails */ + iCode *pgs, *sh, *st; + + if (!(sic->next && sic->next->next && sic->next->next->next)) + return 0; + if (sic->next->op != '+' && sic->next->op != '-') + return 0; + if (!(sic->next->next->op == '=' && !POINTER_SET (sic->next->next))) + return 0; + if (!isOperandEqual (IC_LEFT (sic->next), IC_RIGHT (sic)) || !IS_OP_LITERAL (IC_RIGHT (sic->next))) + return 0; + if (operandLitValue (IC_RIGHT (sic->next)) != getSize (operandType (IC_RIGHT (sic))->next)) + return 0; + if (!isOperandEqual (IC_RESULT (sic->next->next), IC_RIGHT (sic))) + return 0; + if (!isOperandEqual (IC_RESULT (sic->next), IC_RIGHT (sic->next->next))) + return 0; + if (!(pgs = findPointerGetSet (sic->next->next, IC_RESULT (sic)))) + return 0; + + /* found the pattern .. now do the transformation */ + sh = sic->next; + st = sic->next->next; + + /* take the two out of the chain */ + sic->next = st->next; + st->next->prev = sic; + + /* and put them after the pointer get/set icode */ + if ((st->next = pgs->next)) + st->next->prev = st; + if (!st->next) + ebb->ech = st; + pgs->next = sh; + sh->prev = pgs; + return 1; +} + +static int +pattern2 (iCode * sic, eBBlock * ebb) +{ + /* this is what we do. look for sequences like + + iTempX := _SOME_POINTER_; + iTempY := _SOME_POINTER_ + nn ; nn = sizeof (pointed to object) sic->next + iTempK := iTempY; sic->next->next + _SOME_POINTER_ := iTempK; sic->next->next->next + either + iTempZ := @[iTempX]; sic->next->next->next->next + or + *(iTempX) := ..something.. sic->next->next->next->next + if we find this then transform this to + iTempX := _SOME_POINTER_; + either + iTempZ := @[iTempX]; + or + *(iTempX) := ..something.. + iTempY := _SOME_POINTER_ + nn ; nn = sizeof (pointed to object) + iTempK := iTempY; + _SOME_POINTER_ := iTempK; */ + + /* sounds simple enough so let's start , here I use negative + tests all the way to return if any test fails */ + iCode *pgs, *sh, *st; + + if (!(sic->next && sic->next->next && sic->next->next->next && sic->next->next->next->next)) + return 0; + + /* yes I can OR them together and make one large if... but I have + simple mind and like to keep things simple & readable */ + if (!(sic->next->op == '+' || sic->next->op == '-')) + return 0; + if (!isOperandEqual (IC_RIGHT (sic), IC_LEFT (sic->next))) + return 0; + if (!IS_OP_LITERAL (IC_RIGHT (sic->next))) + return 0; + if (operandLitValue (IC_RIGHT (sic->next)) != getSize (operandType (IC_RIGHT (sic))->next)) + return 0; + if (!IS_ASSIGN_ICODE (sic->next->next)) + return 0; + if (!isOperandEqual (IC_RIGHT (sic->next->next), IC_RESULT (sic->next))) + return 0; + if (!IS_ASSIGN_ICODE (sic->next->next->next)) + return 0; + if (!isOperandEqual (IC_RIGHT (sic->next->next->next), IC_RESULT (sic->next->next))) + return 0; + if (!isOperandEqual (IC_RESULT (sic->next->next->next), IC_LEFT (sic->next))) + return 0; + if (!(pgs = findPointerGetSet (sic->next->next->next, IC_RESULT (sic)))) + return 0; + + /* found the pattern .. now do the transformation */ + sh = sic->next; + st = sic->next->next->next; + + /* take the three out of the chain */ + sic->next = st->next; + st->next->prev = sic; + + /* and put them after the pointer get/set icode */ + if ((st->next = pgs->next)) + st->next->prev = st; + if (!st->next) + ebb->ech = st; + pgs->next = sh; + sh->prev = pgs; + return 1; +} + +/*-----------------------------------------------------------------------*/ +/* ptrPostIncDecOpts - will do some pointer post increment optimizations */ +/* this will help register allocation amongst others */ +/*-----------------------------------------------------------------------*/ +void +ptrPostIncDecOpt (iCode * sic, eBBlock * ebb) +{ + if (pattern1 (sic, ebb)) + return; + pattern2 (sic, ebb); +} + +/*-----------------------------------------------------------------------*/ +/* addPattern1 - transform addition to pointer of variables */ +/*-----------------------------------------------------------------------*/ +static int +addPattern1 (iCode * ic) +{ + iCode *dic; + operand *tmp; + /* transform : + iTempAA = iTempBB + iTempCC + iTempDD = iTempAA + CONST + to + iTempAA = iTempBB + CONST + iTempDD = iTempAA + iTempCC + */ + if (!isOperandLiteral (IC_RIGHT (ic))) + return 0; + if ((dic = findBackwardDef (IC_LEFT (ic), ic->prev)) == NULL) + return 0; + if (bitVectnBitsOn (OP_SYMBOL (IC_RESULT (dic))->uses) > 1) + return 0; + if (dic->op != '+') + return 0; + tmp = IC_RIGHT (ic); + IC_RIGHT (ic) = IC_RIGHT (dic); + IC_RIGHT (dic) = tmp; + return 1; +} + +/*-----------------------------------------------------------------------*/ +/* ptrAddition - optimize pointer additions */ +/*-----------------------------------------------------------------------*/ +int +ptrAddition (iCode * sic) +{ + if (addPattern1 (sic)) + return 1; + return 0; +} + +/*--------------------------------------------------------------------*/ +/* ptrBaseRematSym - find the base symbol of a remat. pointer */ +/*--------------------------------------------------------------------*/ +symbol * +ptrBaseRematSym (symbol * ptrsym) +{ + iCode *ric; + + if (!ptrsym->remat) + return NULL; + + ric = ptrsym->rematiCode; + while (ric) + { + if (ric->op == '+' || ric->op == '-') + ric = OP_SYMBOL (IC_LEFT (ric))->rematiCode; + else if (IS_CAST_ICODE (ric)) + ric = OP_SYMBOL (IC_RIGHT (ric))->rematiCode; + else + break; + } + + if (ric && IS_SYMOP (IC_LEFT (ric))) + return OP_SYMBOL (IC_LEFT (ric)); + else + return NULL; +} + + +/*--------------------------------------------------------------------*/ +/* ptrPseudoSymSafe - check to see if the conversion of the result of */ +/* a pointerGet of a rematerializable pointer to a pseudo symbol is */ +/* safe. Returns true if safe, or false if hazards were detected. */ +/*--------------------------------------------------------------------*/ +int +ptrPseudoSymSafe (symbol * sym, iCode * dic) +{ + symbol *ptrsym; + symbol *basesym; + iCode *ric; + iCode *ic; + int ptrsymDclType; + //int isGlobal; + + assert (POINTER_GET (dic)); + + /* Can't if spills to this symbol are prohibited */ + if (sym->noSpilLoc) + return 0; + + /* Get the pointer */ + if (!IS_SYMOP (IC_LEFT (dic))) + return 0; + ptrsym = OP_SYMBOL (IC_LEFT (dic)); + + /* Must be a rematerializable pointer */ + if (!ptrsym->remat) + return 0; + + /* The pointer type must be uncasted */ + if (IS_CAST_ICODE (ptrsym->rematiCode)) + return 0; + + /* The symbol's live range must not preceed its definition */ + if (dic->seq > sym->liveFrom) + return 0; + + /* Ok, this is a good candidate for a pseudo symbol. */ + /* However, we must check for two hazards: */ + /* 1) The symbol's live range must not include a CALL */ + /* or PCALL iCode. */ + /* 2) The symbol's live range must not include any */ + /* writes to the variable the pointer rematerializes */ + /* within (to avoid aliasing problems) */ + + /* Find the base symbol the rematerialization is based on */ + ric = ptrsym->rematiCode; + while (ric->op == '+' || ric->op == '-') + ric = OP_SYMBOL (IC_LEFT (ric))->rematiCode; + if (IS_CAST_ICODE (ric)) + return 0; + basesym = OP_SYMBOL (IC_LEFT (ric)); + + //isGlobal = !basesym->islocal && !basesym->ismyparm; + ptrsymDclType = aggrToPtrDclType (ptrsym->type, FALSE); + + ic = dic->next; + while (ic && ic->seq <= sym->liveTo) + { + if (!(SKIP_IC3 (ic) || ic->op == IFX)) + { + /* Check for hazard #1 */ + if ((ic->op == CALL || ic->op == PCALL) /* && isGlobal */ ) + { + if (ic->seq <= sym->liveTo) + return 0; + } + /* Check for hazard #2 */ + else if (POINTER_SET (ic)) + { + symbol *ptrsym2; + + if (!IS_SYMOP (IC_RESULT (ic))) + return 0; + + ptrsym2 = OP_SYMBOL (IC_RESULT (ic)); + + if (ptrsym2->remat) + { + /* Must not be the same base symbol */ + if (basesym == ptrBaseRematSym (ptrsym2)) + return 0; + } + else + { + int ptrsym2DclType = aggrToPtrDclType (ptrsym2->type, FALSE); + + /* Pointer must have no memory space in common */ + if (ptrsym2DclType == ptrsymDclType || ptrsym2DclType == GPOINTER || ptrsymDclType == GPOINTER) + return 0; + } + } + else if (IC_RESULT (ic)) + { + symbol *rsym; + + if (!IS_SYMOP (IC_RESULT (ic))) + return 0; + + rsym = OP_SYMBOL (IC_RESULT (ic)); + + /* Make sure there is no conflict with another pseudo symbol */ + if (rsym->psbase == basesym) + return 0; + if (rsym->isspilt && rsym->usl.spillLoc) + rsym = rsym->usl.spillLoc; + if (rsym->psbase == basesym) + return 0; + } + } + + if (ic->seq == sym->liveTo) + break; + ic = ic->next; + } + + /* If the live range went past the end of the defining basic */ + /* block, then a full analysis is too complicated to attempt */ + /* here. To be safe, we must assume the worst. */ + if (!ic) + return 0; + + /* Ok, looks safe */ + return 1; +} + +/*--------------------------------------------------------------------*/ +/* ptrPseudoSymConvert - convert the result of a pointerGet to a */ +/* pseudo symbol. The pointer must be rematerializable. */ +/*--------------------------------------------------------------------*/ +void +ptrPseudoSymConvert (symbol * sym, iCode * dic, const char *name) +{ + symbol *psym = newSymbol (name, 1); + psym->psbase = ptrBaseRematSym (OP_SYMBOL (IC_LEFT (dic))); + psym->type = sym->type; + psym->etype = psym->psbase->etype; + + strcpy (psym->rname, psym->name); + sym->isspilt = 1; + sym->usl.spillLoc = psym; +#if 0 // an alternative fix for bug #480076 + /* now this is a useless assignment to itself */ + remiCodeFromeBBlock (ebbs, dic); +#else + /* now this really is an assignment to itself, make it so; + it will be optimized out later */ + dic->op = '='; + ReplaceOpWithCheaperOp (&IC_RIGHT (dic), IC_RESULT (dic)); + IC_LEFT (dic) = NULL; +#endif +} |
