summaryrefslogtreecommitdiff
path: root/src/SDCClabel.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/SDCClabel.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/SDCClabel.c')
-rw-r--r--src/SDCClabel.c535
1 files changed, 535 insertions, 0 deletions
diff --git a/src/SDCClabel.c b/src/SDCClabel.c
new file mode 100644
index 0000000..22ef84e
--- /dev/null
+++ b/src/SDCClabel.c
@@ -0,0 +1,535 @@
+/*-----------------------------------------------------------------
+ SDCClabel.c - label optimizations on iCode (intermediate code)
+
+ 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"
+
+hTab *labelRef = NULL;
+hTab *labelDef = NULL;
+
+/*-----------------------------------------------------------------*/
+/* buildLabelRefTable - creates an hashTable of label references */
+/*-----------------------------------------------------------------*/
+void
+buildLabelRefTable (iCode * ic)
+{
+ iCode *lic;
+
+ setToNull ((void *) &labelRef);
+ setToNull ((void *) &labelDef);
+ labelRef = newHashTable (labelKey + 1);
+ labelDef = newHashTable (labelKey + 1);
+
+ for (lic = ic; lic; lic = lic->next)
+ {
+ if (lic->op == GOTO)
+ hTabAddItem (&labelRef, (IC_LABEL (lic))->key, lic);
+
+ if (lic->op == JUMPTABLE)
+ {
+ symbol *lbl;
+ for (lbl = setFirstItem (IC_JTLABELS (lic)); lbl;
+ lbl = setNextItem (IC_JTLABELS (lic)))
+ {
+ hTabAddItem (&labelRef, lbl->key, lic);
+ }
+ }
+
+ if (lic->op == IFX)
+ {
+ if (IC_TRUE (lic))
+ hTabAddItem (&labelRef, (IC_TRUE (lic))->key, lic);
+ else
+ hTabAddItem (&labelRef, (IC_FALSE (lic))->key, lic);
+ }
+ if (lic->op == LABEL)
+ hTabAddItem (&labelDef, (IC_LABEL (lic))->key, lic);
+
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* labelGotoNext - kills gotos to next statement */
+/*-----------------------------------------------------------------*/
+int
+labelGotoNext (iCode * ic)
+{
+ iCode *loop;
+ int change = 0;
+
+ for (loop = ic; loop; loop = loop->next)
+ {
+
+ if (loop->op == GOTO && /* if this is a goto */
+ loop->next && /* and we have a next one */
+ loop->next->op == LABEL && /* next one is a label */
+ loop->next->label->key == loop->label->key) /* same label */
+ {
+ loop->prev->next = loop->next; /* get this out of the chain */
+ loop->next->prev = loop->prev;
+ hTabDeleteItem (&labelRef, (IC_LABEL (loop))->key, loop, DELETE_ITEM, NULL);
+ change++;
+ }
+ }
+
+ return change;
+}
+
+/*-------------------------------------------------------------------*/
+/* deleteIfx - delete an IFX iCode or convert to DUMMY_READ_VOLATILE */
+/*-------------------------------------------------------------------*/
+static void
+deleteIfx (iCode * loop, int key)
+{
+ werrorfl (loop->filename, loop->lineno, W_CONTROL_FLOW);
+ hTabDeleteItem (&labelRef, key, loop, DELETE_ITEM, NULL);
+
+ /* If the condition was volatile, convert IFX to */
+ /* DUMMY_READ_VOLATILE. Otherwise just delete the */
+ /* IFX iCode */
+ if (IS_OP_VOLATILE (IC_COND (loop)))
+ {
+ IC_RIGHT (loop) = IC_COND (loop);
+ IC_LEFT (loop) = NULL;
+ IC_RESULT (loop) = NULL;
+ loop->op = DUMMY_READ_VOLATILE;
+ }
+ else
+ {
+ loop->prev->next = loop->next;
+ loop->next->prev = loop->prev;
+ }
+}
+
+
+/*-----------------------------------------------------------------*/
+/* labelIfx - special case Ifx elimination */
+/*-----------------------------------------------------------------*/
+int
+labelIfx (iCode * ic)
+{
+ iCode *loop;
+ iCode *stat;
+ int change = 0;
+
+ for (loop = ic; loop; loop = loop->next)
+ {
+ /* if condition goto label */
+ /* goto label */
+ /* i.e. the flow is going to the same location
+ regardless of the condition in this case the
+ condition can be eliminated with a WARNING ofcource */
+ if (loop->op == IFX &&
+ loop->next &&
+ loop->next->op == GOTO)
+ {
+ if (IC_TRUE (loop) && IC_TRUE (loop)->key == IC_LABEL (loop->next)->key)
+ {
+ deleteIfx (loop, IC_TRUE (loop)->key);
+ change++;
+ continue;
+ }
+ else
+ {
+ if (IC_FALSE (loop) && IC_FALSE (loop)->key == IC_LABEL (loop->next)->key)
+ {
+ deleteIfx (loop, IC_FALSE (loop)->key);
+ change++;
+ continue;
+ }
+ }
+ }
+ /* same as above but with a twist */
+ /* if condition goto label */
+ /* label: */
+ if (loop->op == IFX &&
+ loop->next &&
+ loop->next->op == LABEL &&
+ ((IC_TRUE (loop) && IC_TRUE (loop)->key == IC_LABEL (loop->next)->key) ||
+ (IC_FALSE (loop) && IC_FALSE (loop)->key == IC_LABEL (loop->next)->key)))
+ {
+ deleteIfx (loop, IC_LABEL (loop->next)->key);
+ change++;
+ continue;
+ }
+
+ /* we will eliminate certain special case situations */
+ /* of the conditional statement :- */
+ /* if cond != 0 goto _trueLabel */
+ /* goto _falseLabel */
+ /* _trueLabel : */
+ /* ... */
+ /* in these cases we can change it to :- */
+ /* if cond == 0 goto _falseLabel */
+ /* _trueLabel : */
+ /* ... */
+ /* similarly if we have a situation like :- */
+ /* if cond == 0 goto _falseLabel */
+ /* goto _someLabel */
+ /* _falseLabel : */
+ /* we can change this to */
+ /* if cond != 0 goto _someLabel */
+ /* _falseLabel : */
+ /* ... */
+ if (loop->op == IFX && loop->next && loop->next->op == GOTO &&
+ loop->next->next && loop->next->next->op == LABEL)
+ {
+ if (IC_TRUE (loop) && (IC_TRUE (loop))->key != (IC_LABEL (loop->next->next))->key ||
+ (IC_FALSE (loop) && (IC_FALSE (loop))->key != (IC_LABEL (loop->next->next))->key))
+ continue;
+
+ /* now make sure that this is the only */
+ /* referenece to the _trueLabel */
+ if (IC_TRUE (loop) && hTabItemWithKey (labelRef, (IC_TRUE (loop))->key))
+ {
+ /* we just change the falseLabel */
+ /* to the next goto statement */
+ /* unreferenced label will take */
+ /* care of removing the label */
+ /* delete reference to the true label */
+
+ hTabDeleteItem (&labelRef, (IC_TRUE (loop))->key, loop, DELETE_ITEM, NULL);
+ IC_TRUE (loop) = NULL;
+ IC_FALSE (loop) = IC_LABEL (loop->next);
+ /* add reference to the LABEL */
+ hTabAddItem (&labelRef, (IC_FALSE (loop))->key, loop);
+ /* next remove the goto */
+ hTabDeleteItem (&labelRef,
+ (IC_LABEL (loop->next))->key, loop->next, DELETE_ITEM, NULL);
+ loop->next = loop->next->next;
+ loop->next->prev = loop;
+ change++;
+ continue;
+ }
+
+ /* now do the same with the false labels */
+ if (IC_FALSE (loop) && hTabItemWithKey (labelRef, (IC_FALSE (loop))->key))
+ {
+ hTabDeleteItem (&labelRef, (IC_FALSE (loop))->key, loop, DELETE_ITEM, NULL);
+ IC_FALSE (loop) = NULL;
+ IC_TRUE (loop) = IC_LABEL (loop->next);
+ hTabAddItem (&labelRef, (IC_TRUE (loop))->key, loop);
+ hTabDeleteItem (&labelRef, (IC_LABEL (loop->next))->key, loop->next, DELETE_ITEM, NULL);
+ loop->next = loop->next->next;
+ loop->next->prev = loop;
+ change++;
+ continue;
+ }
+ }
+
+ /* Optimize hidden jump-to-jump:
+ Simplify
+ v = 1; stat->prev
+ goto l1; stat
+ l0:
+ v = 0; loop->prev
+ l1: loop
+ if (v) goto l3; loop->next
+ Into
+ v = 1;
+ goto l3;
+ l0:
+ v = 0;
+ l1: */
+ if (loop->op == LABEL &&
+ loop->next && loop->next->op == IFX &&
+ (stat = hTabFirstItemWK (labelRef, (IC_LABEL (loop))->key)) &&
+ !hTabNextItemWK (labelRef) &&
+ stat && stat->op == GOTO &&
+ stat->prev && stat->prev->op == '=' && IS_OP_LITERAL (IC_RIGHT (stat->prev)) &&
+ loop->prev && loop->prev->op == '=' && IS_OP_LITERAL (IC_RIGHT (loop->prev)) &&
+ IC_RESULT (stat->prev)->key == IC_COND (loop->next)->key &&
+ IC_RESULT (loop->prev)->key == IC_COND (loop->next)->key &&
+ !IS_OP_VOLATILE (IC_COND (loop->next)) &&
+ (!operandLitValue (IC_RIGHT (stat->prev)) ^ !operandLitValue (IC_RIGHT (loop->prev))))
+ {
+ if (IC_FALSE (loop->next) && !operandLitValue (IC_RIGHT (loop->prev)) ||
+ IC_TRUE (loop->next) && operandLitValue (IC_RIGHT (loop->prev)))
+ /* Complicated case: Insert goto, remove conditional jump. */
+ {
+ /* Change IFX to GOTO. */
+ stat = loop->next;
+ IC_LABEL (stat) = IC_TRUE (stat) ? IC_TRUE (stat) : IC_FALSE (stat);
+ stat->op = GOTO;
+
+ /* Move to desired location. */
+ if (loop->next->next)
+ loop->next->next->prev = loop;
+ loop->next = loop->next->next;
+ stat->prev = loop->prev;
+ stat->prev->next = stat;
+ stat->next = loop;
+ loop->prev = stat;
+ change++;
+ continue;
+ }
+ else /* Simple case: Redirect goto, remove conditional jump. */
+ {
+ hTabDeleteItem (&labelRef, (IC_LABEL (stat))->key, stat, DELETE_ITEM, NULL);
+ IC_LABEL (stat) = IC_TRUE (loop->next) ? IC_TRUE (loop->next) : IC_FALSE (loop->next);
+ hTabAddItem (&labelRef, (IC_LABEL (stat))->key, stat);
+ hTabDeleteItem (&labelRef, IC_LABEL (stat)->key, loop->next, DELETE_ITEM, NULL);
+ if (loop->next->next)
+ loop->next->next->prev = loop;
+ loop->next = loop->next->next;
+ change++;
+ continue;
+ }
+ }
+ }
+
+ return change;
+}
+
+/*-----------------------------------------------------------------*/
+/* replaceGotoGoto - find new target for jump */
+/* if we have a target statement then check if the next */
+/* one is a goto: this means target of goto is a goto */
+/*-----------------------------------------------------------------*/
+static symbol *
+replaceGotoGoto (const iCode *ic, const symbol *sLabel, const iCode *target)
+{
+ if (!target || !target->next)
+ return 0;
+
+ if (target->next->op != GOTO && target->next->op != LABEL || target->next == ic)
+ return 0;
+
+ symbol *repLabel = target->next->label;
+
+ if (repLabel == sLabel)
+ return 0;
+
+ return repLabel;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* labelGotoGoto - target of a goto is a goto */
+/*-----------------------------------------------------------------*/
+int
+labelGotoGoto (iCode *ic)
+{
+ iCode *loop;
+ int change = 0;
+
+ for (loop = ic; loop; loop = loop->next)
+ {
+ iCode *stat;
+ symbol *sLabel = NULL;
+ symbol *repLabel;
+ stat = NULL;
+ switch (loop->op)
+ {
+ case GOTO: /* for a goto statement */
+
+ stat = hTabItemWithKey (labelDef, (sLabel = IC_LABEL (loop))->key);
+
+ if (repLabel = replaceGotoGoto (loop, sLabel, stat))
+ {
+ hTabDeleteItem (&labelRef, sLabel->key, loop, DELETE_ITEM, NULL);
+ loop->label = repLabel;
+ hTabAddItem (&labelRef, repLabel->key, loop);
+ change++;
+ }
+ break;
+
+ case IFX: /* for a conditional jump */
+
+ if (IC_TRUE (loop))
+ stat = hTabItemWithKey (labelDef, (sLabel = IC_TRUE (loop))->key);
+ else
+ stat = hTabItemWithKey (labelDef, (sLabel = IC_FALSE (loop))->key);
+
+ if (repLabel = replaceGotoGoto (loop, sLabel, stat))
+ {
+ if (IC_TRUE (loop))
+ {
+ hTabDeleteItem (&labelRef, sLabel->key, loop, DELETE_ITEM, NULL);
+ IC_TRUE (loop) = repLabel;
+ }
+ else
+ {
+ hTabDeleteItem (&labelRef, sLabel->key, loop, DELETE_ITEM, NULL);
+ IC_FALSE (loop) = repLabel;
+ }
+ hTabAddItem (&labelRef, repLabel->key, loop);
+ change++;
+ }
+ break;
+ case JUMPTABLE:
+
+ for (sLabel = setFirstItem (IC_JTLABELS (loop)); sLabel; sLabel = setNextItem (IC_JTLABELS (loop)))
+ if (repLabel = replaceGotoGoto (loop, sLabel, hTabItemWithKey (labelDef, sLabel->key)))
+ {
+ hTabDeleteItem (&labelRef, sLabel->key, loop, DELETE_ITEM, NULL);
+ replaceSetItem (IC_JTLABELS (loop), sLabel, repLabel);
+ hTabAddItem (&labelRef, repLabel->key, loop);
+ change++;
+ }
+ }
+ }
+
+ return change;
+}
+
+/*-----------------------------------------------------------------*/
+/* labelUnrefLabel - remove unreferenced labels */
+/*-----------------------------------------------------------------*/
+int
+labelUnrefLabel (iCode * ic)
+{
+ iCode *loop;
+ int change = 0;
+
+ for (loop = ic; loop; loop = loop->next)
+ {
+
+ /* if this is a label */
+ if (loop->op == LABEL)
+ {
+ if (((IC_LABEL (loop))->key == returnLabel->key) ||
+ ((IC_LABEL (loop))->key == entryLabel->key))
+ continue;
+
+ if (hTabItemWithKey (labelRef, (IC_LABEL (loop))->key))
+ continue;
+
+ /* else eliminitate this one */
+ loop->prev->next = loop->next; /* get this out of the chain */
+ loop->next->prev = loop->prev;
+ change++;
+ }
+ }
+
+ return change;
+}
+
+/*-----------------------------------------------------------------*/
+/* labelUnreach - remove unreachable code */
+/*-----------------------------------------------------------------*/
+int
+labelUnreach (iCode * ic)
+{
+ iCode *loop;
+ iCode *tic;
+ int change = 0;
+
+ /* if we hit a return statement or a goto statement */
+ /* remove all statements till we hit the next label */
+ for (loop = ic; loop; loop = loop->next)
+ {
+ iCode *loop2;
+
+ /* found a goto || return && the next */
+ /* statement is not a label */
+ if (loop->op == GOTO || loop->op == RETURN ||
+ loop->op == CALL && IFFUNC_ISNORETURN (operandType (IC_LEFT (loop))))
+ {
+ if (loop->next &&
+ (loop->next->op == LABEL || loop->next->op == ENDFUNCTION))
+ continue;
+
+ /* loop till we find a label */
+ loop2 = loop->next;
+ while (loop2 && loop2->op != LABEL)
+ loop2 = loop2->next;
+
+ /* throw away those in between */
+ for (tic = loop->next; tic && tic != loop2; tic = tic->next)
+ {
+ /* remove label references if any */
+ switch (tic->op)
+ {
+ case GOTO:
+ hTabDeleteItem (&labelRef, IC_LABEL (tic)->key, tic, DELETE_ITEM, NULL);
+ break;
+ case IFX:
+ werrorfl (tic->filename, tic->lineno, W_CODE_UNREACH);
+ if (IC_TRUE (tic))
+ hTabDeleteItem (&labelRef, IC_TRUE (tic)->key, tic, DELETE_ITEM, NULL);
+ else
+ hTabDeleteItem (&labelRef, IC_FALSE (tic)->key, tic, DELETE_ITEM, NULL);
+ break;
+ default:
+ werrorfl (tic->filename, tic->lineno, W_CODE_UNREACH);
+ }
+ }
+
+ /* now set up the pointers */
+ loop->next = loop2;
+ if (loop2)
+ loop2->prev = loop;
+ change++;
+ }
+ }
+ return change;
+}
+
+/*-----------------------------------------------------------------*/
+/* iCodeLabelOptimize - some obvious & general optimizations */
+/*-----------------------------------------------------------------*/
+iCode *
+iCodeLabelOptimize (iCode * ic)
+{
+ if (!optimize.label1 &&
+ !optimize.label2 &&
+ !optimize.label3 &&
+ !optimize.label4)
+ return ic;
+
+ /* build labelreferences */
+ buildLabelRefTable (ic);
+
+ /* the following transformations need to ne done */
+ /* repeatedly till a fixed point is reached */
+ while (1)
+ {
+ int change;
+ change = 0;
+
+ /* first eliminate any goto statement */
+ /* that goes to the next statement */
+ if (optimize.label1)
+ change += labelGotoNext (ic);
+
+ if (optimize.label2)
+ change += labelIfx (ic);
+
+ /* target of a goto is a goto then rename this goto */
+ if (optimize.label3)
+ change += labelGotoGoto (ic);
+
+ /* remove unreference labels */
+ if (optimize.label4)
+ change += labelUnrefLabel (ic);
+
+ /* remove unreachable code */
+ change += labelUnreach (ic);
+
+ if (!change) /* fixed point reached */
+ break;
+ }
+
+ return ic;
+}