summaryrefslogtreecommitdiff
path: root/src/SDCCptropt.c
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/SDCCptropt.c
downloadsdcc-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.c420
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
+}