diff options
author | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
---|---|---|
committer | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
commit | 094b96ca1df4a035b5f93c351f773306c0241f3f (patch) | |
tree | 95ce05e3ebe816c7ee7996206bb37ea17d8ca33c /compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.c | |
parent | fc0c4c0df7b583b55a08317cf1ef6a71d27c0440 (diff) | |
download | MWCC-main.tar.gz MWCC-main.zip |
move lots of source files around to match their actual placement in the original treemain
Diffstat (limited to 'compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.c')
-rw-r--r-- | compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.c | 560 |
1 files changed, 560 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.c b/compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.c new file mode 100644 index 0000000..23d5d4a --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.c @@ -0,0 +1,560 @@ +#include "IroEmptyLoop.h" +#include "IroDump.h" +#include "IroFlowgraph.h" +#include "IroLinearForm.h" +#include "IroLoop.h" +#include "IroUtil.h" +#include "IroVars.h" +#include "compiler/CInt64.h" + +// forward decls +static Boolean EmptyLoop(IRONode *fnode); +static int CanRemoveRedundantLoop(IROLoop *loop); +static int CanRemoveRedundantLoop1(IROLoop *loop); +static int RedundantLoopCheck(IROLoop *loop); +static int CheckStepOverFlow1_EmptyLoop(IROLoop *loop, CInt64 *val1, CInt64 *val2); +static int CheckStepOverFlow2_EmptyLoop(IROLoop *loop, CInt64 *val1, CInt64 *val2); + +void IRO_FindEmptyLoops(void) { + IRONode *fnode; + IRONode *pred; + UInt16 i; + UInt16 x; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + x = 0; + for (i = 0; i < fnode->numpred; i++) { + pred = IRO_NodeTable[fnode->pred[i]]; + if (Bv_IsBitSet(fnode->index, pred->dom)) { + if (!x) { + Bv_AllocVector(&InLoop, IRO_NumNodes + 1); + Bv_Clear(InLoop); + Bv_SetBit(fnode->index, InLoop); + } + x = 1; + Bv_SetBit(pred->index, InLoop); + if (pred != fnode) + AddPreds(pred); + } + } + + if (x) { + IRO_Dump("IRO_FindEmptyLoops:Found loop with header %d\n", fnode->index); + IRO_DumpBits("Loop includes: ", InLoop); + EmptyLoop(fnode); + IRO_UpdateFlagsOnInts(); + } + } + + IRO_CheckForUserBreak(); +} + +static Boolean EmptyLoop(IRONode *fnode) { + VarRecord *var; + IRONode *bestpred; + IRONode *pred; + UInt16 i; + int flag2; + IRONode *r24; + Boolean flag; + int counter; + int j; + IRONode *succ; + IRONode *bestsucc; + int counter2; + UInt32 counter3; + IROLoop *loop; + IRONode *r21; + IRONode *r20; + IROLinear *constnd; + Type *type20; + ENode *enode; + IROLinear *save; + + flag = 0; + counter = 0; + LoopNode = fnode; + FindMustReach(); + + for (var = IRO_FirstVar; var; var = var->next) + var->xA = 1; + + ComputeLoopKills(); + ComputeLoopInvariance(); + ComputeLoopInduction(); + + LoopNode = fnode; + ConditionalHeaderAtBottom = 0; + + bestpred = NULL; + flag2 = 0; + for (i = 0; i < LoopNode->numpred; i++) { + pred = IRO_NodeTable[LoopNode->pred[i]]; + if (!Bv_IsBitSet(pred->index, InLoop)) { + flag2 = 1; + if (pred->nextnode == fnode) { + CError_ASSERT(173, !bestpred || pred == bestpred); + bestpred = pred; + } + } + } + + if (!flag2) { + IRO_Dump("No predecessor outside the loop\n"); + return 0; + } + + bestsucc = NULL; + for (i = 0; i < LoopNode->numsucc; i++) { + succ = IRO_NodeTable[LoopNode->succ[i]]; + if (Bv_IsBitSet(succ->index, InLoop)) { + bestsucc = succ; + counter++; + } + } + + if (LoopNode == bestsucc && counter == 1) + flag = 1; + + if (LoopNode->last->type != IROLinearIf || LoopNode->last->type != IROLinearIfNot || flag) { + counter2 = 0; + for (j = 0; j < LoopNode->numpred; j++) { + if (Bv_IsBitSet(IRO_NodeTable[LoopNode->pred[j]]->index, InLoop)) { + r21 = IRO_NodeTable[LoopNode->pred[j]]; + counter2++; + } + } + + r24 = NULL; + counter3 = 0; + for (j = 0; j < LoopNode->numpred; j++) { + if (!Bv_IsBitSet(IRO_NodeTable[LoopNode->pred[j]]->index, InLoop)) { + r24 = IRO_NodeTable[LoopNode->pred[j]]; + counter3++; + } + } + + if (counter2 == 1 && counter3 == 1) { + if (r21->last->type == IROLinearIf) { + if ((Bv_IsBitSet(LoopNode->nextnode->index, InLoop) && !Bv_IsBitSet(r21->nextnode->index, InLoop)) || flag) { + IRO_Dump("Standard while loop layout\n"); + loop = ExtractLoopInfo(r21); + if (flag) + loop->flags |= LoopFlags_20000; + FindAssignmenttoInductionVar(loop, r24); + r20 = r24; + while (r20 && !loop->nd14 && r20->numpred == 1 && IRO_NodeTable[r20->pred[0]]->numsucc == 1) { + FindAssignmenttoInductionVar(loop, IRO_NodeTable[r20->pred[0]]); + r20 = IRO_NodeTable[r20->pred[0]]; + } + + if (CanRemoveRedundantLoop(loop)) { + IRO_Dump("EmptyLoop: # of iterations =%" PRId32 ", FinalStoreVal=%" PRId32 "\n", CInt64_GetULong(&loop->x28), CInt64_GetULong(&loop->x30)); + IRO_NopOut(r21->last->u.label.x4); + r21->last->type = IROLinearNop; + type20 = loop->induction->nd->rtype; + constnd = IRO_NewLinear(IROLinearOperand); + constnd->index = ++IRO_NumLinear; + enode = IRO_NewENode(EINTCONST); + enode->rtype = type20; + enode->data.intval = loop->x30; + constnd->u.node = enode; + constnd->rtype = type20; + + if (loop->induction->nd->type == IROLinearOp1Arg) { + save = loop->induction->nd->u.monadic; + loop->induction->nd->type = IROLinearOp2Arg; + loop->induction->nd->nodetype = EASS; + loop->induction->nd->u.diadic.left = save; + loop->induction->nd->u.diadic.right = constnd; + IRO_Paste(constnd, constnd, loop->induction->nd); + } else if (loop->induction->nd->type == IROLinearOp2Arg) { + loop->induction->nd->nodetype = EASS; + IRO_NopOut(loop->induction->nd->u.diadic.right); + loop->induction->nd->u.diadic.right = constnd; + IRO_Paste(constnd, constnd, loop->induction->nd); + } + } else if (CanRemoveRedundantLoop1(loop)) { + IRO_Dump("EmptyLoop: self recursive dowhile(--n ) loop\n"); + + r21->last->type = IROLinearNop; + type20 = loop->induction->nd->rtype; + constnd = IRO_NewLinear(IROLinearOperand); + constnd->index = ++IRO_NumLinear; + enode = IRO_NewENode(EINTCONST); + enode->rtype = type20; + enode->data.intval = cint64_zero; + constnd->u.node = enode; + constnd->rtype = type20; + + save = loop->induction->nd->u.monadic; + loop->induction->nd->type = IROLinearOp2Arg; + loop->induction->nd->nodetype = EASS; + loop->induction->nd->u.diadic.left = save; + loop->induction->nd->u.diadic.right = constnd; + IRO_Paste(constnd, constnd, loop->induction->nd); + } + } else { + IRO_Dump("NonStandard while loop layout\n"); + } + } else { + IRO_Dump("NonStandard while loop layout\n"); + } + } else { + IRO_Dump("Cannot handle Do While Loop with multiple tails\n"); + } + } + + return 0; +} + +static int CanRemoveRedundantLoop(IROLoop *loop) { + IROLinear *inner; + + if (loop->flags & LoopFlags_10000) { + IRO_Dump("CanRemoveRedundantLoop:No because detection of dowhile(n--) loop not supported\n"); + return 0; + } + + if (loop->flags & LP_LOOP_HAS_ASM) { + IRO_Dump("CanRemoveRedundantLoop:No due to LP_LOOP_HAS_ASM \n"); + return 0; + } + + if (loop->flags & LP_IFEXPR_NON_CANONICAL) { + IRO_Dump("CanRemoveRedundantLoop:No due to LP_IFEXPR_NON_CANONICAL \n"); + return 0; + } + + if (loop->flags & LP_LOOP_HAS_CALLS) { + IRO_Dump("CanRemoveRedundantLoop:No due to LP_LOOP_HAS_CALLS \n"); + return 0; + } + + if (loop->flags & LP_LOOP_HAS_CNTRLFLOW) { + IRO_Dump("CanRemoveRedundantLoop:No due to LP_LOOP_HAS_CNTRLFLOW \n"); + return 0; + } + + if (loop->flags & LP_INDUCTION_NOT_FOUND) { + IRO_Dump("CanRemoveRedundantLoop:No due to LP_INDUCTION_NOT_FOUND \n"); + return 0; + } + + if (loop->flags & LP_HAS_MULTIPLE_INDUCTIONS) { + IRO_Dump("CanRemoveRedundantLoop:No due to LP_HAS_MULTIPLE_INDUCTIONS \n"); + return 0; + } + + if (loop->flags & LP_LOOP_HDR_HAS_SIDEEFFECTS) { + IRO_Dump("CanRemoveRedundantLoop:No due to LP_LOOP_HDR_HAS_SIDEEFFECTS \n"); + return 0; + } + + if (!(loop->flags & LoopFlags_200)) { + IRO_Dump("CanRemoveRedundantLoop:No because header does not follow induction update \n"); + return 0; + } + + if (!(loop->flags & LoopFlags_10000)) { + inner = loop->nd18->u.diadic.right; + if (!IRO_IsIntConstant(inner) && !(inner->flags & IROLF_LoopInvariant)) { + IRO_Dump("CanRemoveRedundantLoop:No because Loop Upper Bound is Variant in the loop\n"); + return 0; + } + + if (!loop->nd14) { + IRO_Dump("CanRemoveRedundantLoop:No because there is no initialization of loop index in PreHeader\n"); + return 0; + } + + if (!IRO_IsVariable(loop->nd14->u.diadic.left)) { + IRO_Dump("CanRemoveRedundantLoop:No because initial value of induction stored thru pointer\n"); + return 0; + } + + if (!IRO_IsUnsignedType(loop->nd14->rtype)) { + if (IRO_IsIntConstant(loop->nd14->u.diadic.right)) { + if (!CInt64_GreaterEqual(loop->nd14->u.diadic.right->u.node->data.intval, cint64_zero)) { + IRO_Dump("CanRemoveRedundantLoop:No because initial value of induction is signed but < 0\n"); + return 0; + } + } else { + IRO_Dump("CanRemoveRedundantLoop:No because initial value of induction is signed and not constant\n"); + return 0; + } + } + + if (!(loop->flags & LP_LOOP_STEP_ISPOS) && !(loop->flags & LP_LOOP_STEP_ISNEG)) { + IRO_Dump("CanRemoveRedundantLoop:No because LP_LOOP_STEP_ISPOS/LP_LOOP_STEP_ISNEG is not set\n"); + return 0; + } + + if ((loop->flags & LP_LOOP_STEP_ISPOS) && CheckStepOverFlow1_EmptyLoop(loop, &loop->x28, &loop->x30)) { + IRO_Dump("CanRemoveRedundantLoop:No because Final Value of indution will overflow\n"); + return 0; + } + + if ((loop->flags & LP_LOOP_STEP_ISNEG) && CheckStepOverFlow2_EmptyLoop(loop, &loop->x28, &loop->x30)) { + IRO_Dump("CanRemoveRedundantLoop:No because Final Value of indution will overflow\n"); + return 0; + } + } + + return RedundantLoopCheck(loop) != 0; +} + +static int CanRemoveRedundantLoop1(IROLoop *loop) { + if ((loop->flags & LoopFlags_10000) && (loop->flags & LoopFlags_20000)) { + if (loop->flags & LP_LOOP_HAS_ASM) { + IRO_Dump("CanRemoveRedundantLoop1:No due to LP_LOOP_HAS_ASM \n"); + return 0; + } + + if (loop->flags & LP_IFEXPR_NON_CANONICAL) { + IRO_Dump("CanRemoveRedundantLoop1:No due to LP_IFEXPR_NON_CANONICAL \n"); + return 0; + } + + if (loop->flags & LP_LOOP_HAS_CALLS) { + IRO_Dump("CanRemoveRedundantLoop1:No due to LP_LOOP_HAS_CALLS \n"); + return 0; + } + + if (loop->flags & LP_LOOP_HAS_CNTRLFLOW) { + IRO_Dump("CanRemoveRedundantLoop1:No due to LP_LOOP_HAS_CNTRLFLOW \n"); + return 0; + } + + if (loop->flags & LP_INDUCTION_NOT_FOUND) { + IRO_Dump("CanRemoveRedundantLoop1:No due to LP_INDUCTION_NOT_FOUND \n"); + return 0; + } + + if (loop->flags & LP_HAS_MULTIPLE_INDUCTIONS) { + IRO_Dump("CanRemoveRedundantLoop1:No due to LP_HAS_MULTIPLE_INDUCTIONS \n"); + return 0; + } + + if (loop->flags & LP_LOOP_HDR_HAS_SIDEEFFECTS) { + IRO_Dump("CanRemoveRedundantLoop1:No due to LP_LOOP_HDR_HAS_SIDEEFFECTS \n"); + return 0; + } + + if (!(loop->flags & LoopFlags_200)) { + IRO_Dump("CanRemoveRedundantLoop1:No because header does not follow induction update \n"); + return 0; + } + + if (loop->induction->nd->type == IROLinearOp1Arg && loop->induction->nd->nodetype == EPREDEC) { + if (IRO_IsUnsignedType(loop->induction->nd->rtype)) + return 1; + IRO_Dump("CanRemoveRedundantLoop1:No because induction not of the right type \n"); + return 0; + } + + IRO_Dump("CanRemoveRedundantLoop1:No because induction operator not a predec \n"); + return 0; + } else { + return 0; + } +} + +static int RedundantLoopCheck(IROLoop *loop) { + IRONode *fnode; + IROLinear *nd; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (Bv_IsBitSet(fnode->index, InLoop) && fnode != loop->fnode && (nd = fnode->first)) { + while (1) { + if ((nd->index < loop->index20 || nd->index > loop->index24) && nd->type != IROLinearNop && nd->type != IROLinearLabel) { + if (IS_LINEAR_DIADIC(nd, EASS)) { + if (!(nd->flags & IROLF_Reffed)) { + if (IS_LINEAR_MONADIC(nd->u.diadic.left, EINDIRECT)) { + if (nd->u.diadic.left->rtype && CParser_IsVolatile(nd->u.diadic.left->rtype, nd->u.diadic.left->nodeflags & ENODE_FLAG_QUALS)) { + IRO_Dump(" EASS at %d fail as store to volatile memory \n", nd->index); + return 0; + } + + if ((nd->u.diadic.left->u.monadic->flags & IROLF_LoopInvariant) && (nd->u.diadic.right->flags & IROLF_LoopInvariant)) { + IRO_Dump(" EASS at %d pass\n", nd->index); + } else { + IRO_Dump(" EASS at %d fail, either LHS address or RHS is variant \n", nd->index); + return 0; + } + } else { + IRO_Dump("Found EASS nodes whose lhs root is not a EINDIRECT node\n"); + return 0; + } + } else { + IRO_Dump("Found EASS node that is referenced i.e embedded assignment\n"); + return 0; + } + } else { + if (!(nd->flags & IROLF_Reffed)) { + IRO_Dump("Found non EASS top level node in the loop\n"); + return 0; + } + } + } + + if (nd == fnode->last) + break; + nd = nd->next; + } + } + } + + return 1; +} + +static int CheckStepOverFlow1_EmptyLoop(IROLoop *loop, CInt64 *val1, CInt64 *val2) { + Boolean isUnsigned; + IROLinear *nd2; + IROLinear *nd1; + CInt64 nd2value; + CInt64 nd1value; + CInt64 addConst; + CInt64 work; + CInt64 neg1; + + nd2 = loop->nd14->u.diadic.right; + nd1 = loop->nd18->u.diadic.right; + isUnsigned = IRO_IsUnsignedType(loop->nd18->u.diadic.right->rtype); + + if (IRO_IsIntConstant(nd2) && IRO_IsIntConstant(nd1)) { + nd2value = nd2->u.node->data.intval; + nd1value = nd1->u.node->data.intval; + if (isUnsigned) { + if (CInt64_LessEqualU(nd1value, nd2value)) + return 1; + } else { + if (CInt64_LessEqual(nd1value, nd2value)) + return 1; + } + + CInt64_SetLong(&addConst, loop->induction->addConst); + CInt64_SetLong(&neg1, -1); + *val1 = CInt64_Sub(nd1value, nd2value); + *val1 = CInt64_Add(*val1, addConst); + if (IS_LINEAR_DIADIC(loop->nd18, ELESS)) + *val1 = CInt64_Add(*val1, neg1); + + CError_ASSERT(855, !CInt64_IsZero(&addConst)); + + if (isUnsigned) + *val1 = CInt64_DivU(*val1, addConst); + else + *val1 = CInt64_Div(*val1, addConst); + + if (CInt64_Equal(*val1, cint64_zero)) + return 1; + + if (isUnsigned) { + if (CInt64_LessEqualU(*val1, cint64_zero)) + CError_FATAL(877); + } else { + if (CInt64_LessEqual(*val1, cint64_zero)) + CError_FATAL(886); + } + + if (isUnsigned) { + *val2 = CInt64_MulU(*val1, addConst); + *val2 = CInt64_Add(*val2, nd2value); + } else { + *val2 = CInt64_Mul(*val1, addConst); + *val2 = CInt64_Add(*val2, nd2value); + } + } else { + return 1; + } + + CInt64_SetLong(&addConst, loop->induction->addConst); + work = CInt64_Add(nd1value, addConst); + + if (isUnsigned) { + if (CInt64_LessU(work, nd1value)) + return 1; + } else { + if (CInt64_Less(work, nd1value)) + return 1; + } + + return 0; +} + +static int CheckStepOverFlow2_EmptyLoop(IROLoop *loop, CInt64 *val1, CInt64 *val2) { + Boolean isUnsigned; + IROLinear *nd2; + IROLinear *nd1; + CInt64 nd2value; + CInt64 nd1value; + CInt64 addConst; + CInt64 work; + CInt64 neg1; + + nd1 = loop->nd14->u.diadic.right; + nd2 = loop->nd18->u.diadic.right; + isUnsigned = IRO_IsUnsignedType(loop->nd18->u.diadic.right->rtype); + + if (IRO_IsIntConstant(nd2) && IRO_IsIntConstant(nd1)) { + nd2value = nd2->u.node->data.intval; + nd1value = nd1->u.node->data.intval; + if (isUnsigned) { + if (CInt64_LessEqualU(nd1value, nd2value)) + return 1; + } else { + if (CInt64_LessEqual(nd1value, nd2value)) + return 1; + } + + CInt64_SetLong(&addConst, loop->induction->addConst); + CInt64_SetLong(&neg1, -1); + *val1 = CInt64_Sub(nd1value, nd2value); + *val1 = CInt64_Add(*val1, addConst); + if (IS_LINEAR_DIADIC(loop->nd18, EGREATER)) + *val1 = CInt64_Add(*val1, neg1); + + CError_ASSERT(995, !CInt64_IsZero(&addConst)); + + if (isUnsigned) + *val1 = CInt64_DivU(*val1, addConst); + else + *val1 = CInt64_Div(*val1, addConst); + + if (CInt64_Equal(*val1, cint64_zero)) + return 1; + + if (isUnsigned) { + if (CInt64_LessEqualU(*val1, cint64_zero)) + return 0; + } else { + if (CInt64_LessEqual(*val1, cint64_zero)) + return 0; + } + + if (isUnsigned) { + *val2 = CInt64_MulU(*val1, addConst); + *val2 = CInt64_Sub(nd1value, *val2); + } else { + *val2 = CInt64_Mul(*val1, addConst); + *val2 = CInt64_Sub(nd1value, *val2); + } + } else { + return 1; + } + + CInt64_SetLong(&addConst, loop->induction->addConst); + work = CInt64_Sub(nd2value, addConst); + + if (isUnsigned) { + if (CInt64_GreaterU(work, nd2value)) + return 1; + } else { + if (CInt64_Greater(work, nd1value)) + return 1; + } + + return 0; +} + |