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/SDCClabel.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/SDCClabel.c')
| -rw-r--r-- | src/SDCClabel.c | 535 |
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; +} |
