diff options
Diffstat (limited to 'compiler_and_linker/FrontEnd/Optimizer/IroLoop.c')
-rw-r--r-- | compiler_and_linker/FrontEnd/Optimizer/IroLoop.c | 2324 |
1 files changed, 2324 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroLoop.c b/compiler_and_linker/FrontEnd/Optimizer/IroLoop.c new file mode 100644 index 0000000..850146d --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroLoop.c @@ -0,0 +1,2324 @@ +#include "IroLoop.h" +#include "IroCSE.h" +#include "IroDump.h" +#include "IroFlowgraph.h" +#include "IroLinearForm.h" +#include "IroPropagate.h" +#include "IroSubable.h" +#include "IroUtil.h" +#include "IroVars.h" +#include "compiler/CFunc.h" +#include "compiler/CInt64.h" +#include "compiler/CMachine.h" +#include "compiler/objects.h" +#include "compiler/types.h" + +IRONode *LoopNode; +Boolean ConditionalHeaderAtBottom; +IROLoopInd *FirstInd; +BitVector *InLoop; +IROList IRO_InitLList; +BitVector *InLoop_Exits; +BitVector *InLoop_Tails; +UInt32 LoopExitNumber; +UInt32 LoopTailNum; +IRONode *LoopExitSuccessor; +IRONode *LoopTail; +IROLoopMemRef *IRO_LoopMemRefFirst; +IROLoopMemRef *IRO_LoopMemRefCurrent; +static IROExpr *RisList; +static BitVector *AllKills; +static Boolean KnownBounds; +static SInt32 Times; +static IROLinear *PredInt; +static IROElmList *FirstAddendLinear; +static IROElmList *LastAddendLinear; +static int NoSubableSubs; + +// forward decls +static void MyHandleLoop_Vector(IRONode *fnode); +static void MyHandleLoop_Motion(IRONode *fnode); +static void CheckAllLoopAddresses(IRONode *fnode, BitVector *bv, Boolean *resultFlag); +static void MakeLoopEntry(IROLinear *nd, IROAddrRecord *rec, Boolean mustreach1, Boolean flag2); +static void MoveInvarianceInAddressExpr(void); +static IROLinear *RearrangeInvarianceInAddressExpr(IROLinear *nd, IROList *list); +static UInt32 IsAssignmentReductionCandidate(IROLinear *nd); + +void FindMustReach(void) { + IRONode *fnode; + IRONode *fnode2; + IRONode *pred; + int i; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + fnode->mustreach = 0; + if (Bv_IsBitSet(fnode->index, InLoop)) { + fnode->mustreach = 1; + + for (i = 0; i < LoopNode->numpred; i++) { + pred = IRO_NodeTable[LoopNode->pred[i]]; + if (Bv_IsBitSet(pred->index, InLoop) && !Bv_IsBitSet(fnode->index, pred->dom)) { + fnode->mustreach = 0; + break; + } + } + + for (fnode2 = IRO_FirstNode; fnode2; fnode2 = fnode2->nextnode) { + if (Bv_IsBitSet(fnode2->index, InLoop)) { + for (i = 0; i < fnode2->numsucc; i++) { + if (!Bv_IsBitSet(fnode2->succ[i], InLoop) && !Bv_IsBitSet(fnode->index, fnode2->dom)) { + fnode->mustreach = 0; + break; + } + } + + if (!fnode->mustreach) + break; + } + } + } + } +} + +void FindMustReach1(IRONode *checkfnode) { + IRONode *fnode; + IRONode *fnode2; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (Bv_IsBitSet(fnode->index, InLoop)) { + fnode->mustreach1 = 1; + for (fnode2 = IRO_FirstNode; fnode2; fnode2 = fnode2->nextnode) { + if (Bv_IsBitSet(fnode2->index, InLoop)) { + if (Bv_IsBitSet(fnode2->index, InLoop_Tails) && !Bv_IsBitSet(fnode->index, fnode2->dom)) + fnode->mustreach1 = 0; + + if (Bv_IsBitSet(fnode2->index, InLoop_Exits) && fnode2 != checkfnode && !Bv_IsBitSet(fnode->index, fnode2->dom)) + fnode->mustreach1 = 0; + + if (!fnode->mustreach1) + break; + } + } + } + } +} + +static void IRO_FindLoopTailsAndExits(IRONode *fnode) { + IRONode *scan; + IRONode *succ; + int i; + + for (scan = IRO_FirstNode; scan; scan = scan->nextnode) { + if (Bv_IsBitSet(scan->index, InLoop)) { + for (i = 0; i < scan->numsucc; i++) { + succ = IRO_NodeTable[scan->succ[i]]; + if (succ == fnode) { + Bv_SetBit(scan->index, InLoop_Tails); + LoopTail = scan; + LoopTailNum++; + } + if (!Bv_IsBitSet(succ->index, InLoop)) { + LoopExitNumber++; + LoopExitSuccessor = succ; + Bv_SetBit(scan->index, InLoop_Exits); + } + } + } + } + + IRO_Dump("IRO_FindLoopTailsAndExits:For header %d, Loop exits and loop tails are \n", fnode->index); + IRO_DumpBits("Loop Exits: ", InLoop_Exits); + IRO_DumpBits("Loop Tails: ", InLoop_Tails); + IRO_Dump("LoopExitNum=%d: \n", LoopExitNumber); + if (LoopExitSuccessor) + IRO_Dump("LoopExitSuccessor node =%d: \n", LoopExitSuccessor->index); +} + +static int IsSafeTypcon(IROLinear *nd) { + Type *srcType; + Type *destType; + SInt32 srcSize; + SInt32 destSize; + Boolean srcUnsigned; + Boolean destUnsigned; + + srcType = nd->u.monadic->rtype; + destType = nd->rtype; + if (!IS_TYPE_INT(srcType) || !IS_TYPE_INT(destType)) + return 0; + + srcSize = srcType->size; + destSize = destType->size; + srcUnsigned = IRO_IsUnsignedType(srcType); + destUnsigned = IRO_IsUnsignedType(destType); + + if (srcUnsigned == destUnsigned && destSize >= srcSize) + return 1; + if (srcUnsigned == 1 && destUnsigned == 0 && destSize > srcSize) + return 1; + return 0; +} + +static int Reducable(IROLinear *nd, IROLinear **resultNd1, IROLinear **resultNd2, VarRecord **resultVar) { + IROLinear *indirect; + IROLinear *left; + IROLinear *right; + Boolean leftInvariant; + Boolean rightInvariant; + Boolean leftTypcon; + Boolean rightTypcon; + Object *obj; + ENode *enode; + IROLoopInd *ind; + CInt64 val64; + SInt32 val; + SInt32 div; + + leftInvariant = 0; + rightInvariant = 0; + leftTypcon = 0; + rightTypcon = 0; + + if (nd->type == IROLinearOp2Arg && nd->nodetype == EADD && (IS_TYPE_INT(nd->rtype) || IS_TYPE_POINTER_ONLY(nd->rtype))) { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + if (left->type == IROLinearOp1Arg && left->nodetype == ETYPCON) { + leftTypcon = 1; + leftInvariant = (left->flags & IROLF_LoopInvariant) != 0; + left = left->u.monadic; + } + if (right->type == IROLinearOp1Arg && right->nodetype == ETYPCON) { + rightTypcon = 1; + rightInvariant = (right->flags & IROLF_LoopInvariant) != 0; + right = right->u.monadic; + } + + if (((left->flags & IROLF_LoopInvariant) || leftInvariant) && IRO_IsVariable(right)) { + if (leftInvariant || ((!(obj = IRO_IsVariable(left)) || !IRO_IsRegable(obj)) && !IRO_IsConstant(left))) { + if ( + left->type == IROLinearOp2Arg && + left->nodetype == EADD && + (obj = IRO_IsVariable(left->u.diadic.left)) && + IRO_IsRegable(obj) && + IRO_IsConstant(left->u.diadic.right) + ) + return 0; + + if (rightTypcon) { + if (!IsSafeTypcon(nd->u.diadic.right)) + return 0; + *resultNd2 = nd->u.diadic.right; + } else { + *resultNd2 = right; + } + + indirect = right; + *resultNd1 = IRO_NewLinear(IROLinearOperand); + + enode = IRO_NewENode(EINTCONST); + enode->data.intval = cint64_one; + enode->rtype = nd->u.diadic.right->rtype; + (*resultNd1)->rtype = nd->u.diadic.right->rtype; + (*resultNd1)->u.node = enode; + } else { + return 0; + } + } else if ( + ((left->flags & IROLF_LoopInvariant) || leftInvariant) && + right->type == IROLinearOp2Arg && + !rightTypcon && + (right->nodetype == EMUL || right->nodetype == ESHL) + ) { + if (IRO_IsConstant(right->u.diadic.right)) { + if (right->nodetype == ESHL) { + right->nodetype = EMUL; + right->u.diadic.right->u.node->data.intval = CInt64_Shl(cint64_one, right->u.diadic.right->u.node->data.intval); + } + if (right->u.diadic.left->type == IROLinearOp1Arg) { + if (IRO_IsVariable(right->u.diadic.left)) { + *resultNd2 = right->u.diadic.left; + indirect = right->u.diadic.left; + *resultNd1 = right->u.diadic.right; + } else if (right->u.diadic.left->nodetype == ETYPCON && IRO_IsVariable(right->u.diadic.left->u.monadic)) { + if (!IsSafeTypcon(right->u.diadic.left)) + return 0; + *resultNd2 = right->u.diadic.left; + indirect = right->u.diadic.left->u.monadic; + *resultNd1 = right->u.diadic.right; + } else { + return 0; + } + } else { + return 0; + } + } else { + return 0; + } + } else if ( + ((right->flags & IROLF_LoopInvariant) || rightInvariant) && + left->type == IROLinearOp2Arg && + !leftTypcon && + (left->nodetype == EMUL || left->nodetype == ESHL) + ) { + if (IRO_IsConstant(left->u.diadic.right)) { + if (left->nodetype == ESHL) { + left->nodetype = EMUL; + left->u.diadic.right->u.node->data.intval = CInt64_Shl(cint64_one, left->u.diadic.right->u.node->data.intval); + } + if (left->u.diadic.left->type == IROLinearOp1Arg) { + if (IRO_IsVariable(left->u.diadic.left)) { + *resultNd2 = left->u.diadic.left; + indirect = left->u.diadic.left; + *resultNd1 = left->u.diadic.right; + } else if (left->u.diadic.left->nodetype == ETYPCON && IRO_IsVariable(left->u.diadic.left->u.monadic)) { + if (!IsSafeTypcon(left->u.diadic.left)) + return 0; + *resultNd2 = left->u.diadic.left; + indirect = left->u.diadic.left->u.monadic; + *resultNd1 = left->u.diadic.right; + } else { + return 0; + } + } else { + return 0; + } + } else { + return 0; + } + } else if ( + ((right->flags & IROLF_LoopInvariant) || rightInvariant) && + IRO_IsVariable(left) + ) { + if (rightInvariant || ((!(obj = IRO_IsVariable(right)) || !IRO_IsRegable(obj)) && !IRO_IsConstant(right))) { + if ( + right->type == IROLinearOp2Arg && + right->nodetype == EADD && + (obj = IRO_IsVariable(right->u.diadic.left)) && + IRO_IsRegable(obj) && + IRO_IsConstant(right->u.diadic.right) + ) + return 0; + + if (leftTypcon) { + if (!IsSafeTypcon(nd->u.diadic.left)) + return 0; + *resultNd2 = nd->u.diadic.left; + } else { + *resultNd2 = left; + } + + indirect = left; + *resultNd1 = IRO_NewLinear(IROLinearOperand); + + enode = IRO_NewENode(EINTCONST); + enode->data.intval = cint64_one; + enode->rtype = nd->u.diadic.left->rtype; + (*resultNd1)->rtype = nd->u.diadic.left->rtype; + (*resultNd1)->u.node = enode; + } else { + return 0; + } + } else { + return 0; + } + } else if (nd->type == IROLinearOp2Arg && (nd->nodetype == EMUL || nd->nodetype == ESHL) && nd->rtype->size <= 4 && (IS_TYPE_INT(nd->rtype) || IS_TYPE_POINTER_ONLY(nd->rtype))) { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + + if (IRO_IsConstant(right) && IRO_IsVariable(left)) { + *resultNd2 = left; + indirect = left; + *resultNd1 = right; + } else if (IRO_IsConstant(nd->u.diadic.right) && left->type == IROLinearOp1Arg && left->nodetype == ETYPCON && + IRO_IsVariable(left->u.monadic)) { + if (!IsSafeTypcon(left)) + return 0; + *resultNd2 = left; + indirect = left->u.monadic; + *resultNd1 = right; + } else { + if (nd->type == IROLinearOp2Arg && nd->nodetype == ESHL) + return 0; + + if (nd->u.diadic.right->flags & IROLF_LoopInvariant) { + if (IRO_IsVariable(left)) { + *resultNd2 = left; + indirect = left; + *resultNd1 = right; + } else if (left->type == IROLinearOp1Arg && left->nodetype == ETYPCON && IRO_IsVariable(left->u.monadic)) { + if (!IsSafeTypcon(left)) + return 0; + *resultNd2 = left; + indirect = left->u.monadic; + *resultNd1 = right; + } else { + return 0; + } + } else if (nd->u.diadic.left->flags & IROLF_LoopInvariant) { + if (IRO_IsVariable(right)) { + *resultNd2 = right; + indirect = right; + *resultNd1 = left; + } else if (right->type == IROLinearOp1Arg && right->nodetype == ETYPCON && IRO_IsVariable(right->u.monadic) && nd->type == IROLinearOp2Arg && nd->nodetype == EMUL) { + if (!IsSafeTypcon(right)) + return 0; + *resultNd2 = right; + indirect = right->u.monadic; + *resultNd1 = left; + } else { + return 0; + } + } else { + return 0; + } + } + } else if (nd->type == IROLinearOp2Arg && (nd->nodetype == EDIV || nd->nodetype == ESHR) && nd->rtype->size <= 4 && IS_TYPE_INT(nd->rtype)) { + if (IRO_IsVariable(nd->u.diadic.left) && IRO_IsConstant(nd->u.diadic.right)) { + val64 = nd->u.diadic.right->u.node->data.intval; + if (nd->type == IROLinearOp2Arg && nd->nodetype == ESHR) { + CInt64_GetULong(&val64); + if (CInt64_GetULong(&val64) > 32 || CTool_EndianReadWord32(&val64.hi)) + return 0; + val64 = CInt64_Shl(cint64_one, val64); + } + *resultNd2 = nd->u.diadic.left; + indirect = nd->u.diadic.left; + } else { + return 0; + } + } else { + return 0; + } + + if ( + nd->type == IROLinearOp2Arg && + nd->nodetype == ESHL && + ( + !IRO_IsConstant(*resultNd1) || + (SInt32) CInt64_GetULong(&(*resultNd1)->u.node->data.intval) < 0 || + (SInt32) CInt64_GetULong(&(*resultNd1)->u.node->data.intval) > 32 || + CTool_EndianReadWord32(&(*resultNd1)->u.node->data.intval.hi) + ) + ) + return 0; + + CError_ASSERT(802, indirect->u.monadic->u.node != NULL); + *resultVar = IRO_FindVar(indirect->u.monadic->u.node->data.objref, 0, 1); + if (!*resultVar || (*resultVar)->xA != 2) + return 0; + + if (copts.ANSIstrict || copts.strengthreductionstrict) { + Type *type = (*resultVar)->object->type; + if (IRO_IsUnsignedType(type) && type->size < stunsignedlong.size) + return 0; + } + + if (nd->type == IROLinearOp2Arg && (nd->nodetype == ESHR || nd->nodetype == EDIV)) { + ind = FirstInd; + while (ind && ind->var != *resultVar) + ind = ind->next; + + CError_ASSERT(845, ind != NULL); + + if (ind->addNode == NULL) { + if (ind->addConst < (val = CInt64_GetULong(&val64))) + return 0; + if ((div = ind->addConst / val) <= 0) + return 0; + + *resultNd1 = IRO_NewLinear(IROLinearOperand); + enode = IRO_NewENode(EINTCONST); + CInt64_SetULong(&enode->data.intval, div); + enode->rtype = nd->u.diadic.left->rtype; + (*resultNd1)->rtype = nd->u.diadic.left->rtype; + (*resultNd1)->u.node = enode; + } else { + return 0; + } + } + + return 1; +} + +static void IRO_RemoveExpr_Action(IROLinear *linear, Boolean isFirst) { + if (isFirst && linear->expr) + IRO_RemoveExpr(linear->expr); +} + +static void IRO_ActUnmarkRISCandidate(IROLinear *linear, Boolean isFirst) { + if (isFirst && linear->expr) + linear->flags &= ~IROLF_Ris; +} + +static IROExpr *CreateRIS(IROExpr *expr, IROLinear *nd1, IROLinear *nd2, IROLoopInd *induction, int unk) { + Object *tempObj; + Type *type; + Boolean flag23; + Object *tempObj2; + IROLinear *firstnode; + IROLinear *fourthnode; + IROLinear *fifthnode; + IROLinear *secondnode; + IROLinear *thirdnode; + IROLinear *tmp; + ENode *enode; + IROList list1; + IROList list2; + + flag23 = 0; + type = expr->linear->rtype; + tempObj = create_temp_object(type); + IRO_FindVar(tempObj, 1, 1); + IRO_InitList(&list1); + + if (IS_LINEAR_DIADIC(expr->linear, EADD)) { + firstnode = IRO_DuplicateExpr(expr->linear, &list1); + } else if (IS_LINEAR_DIADIC_2(expr->linear, EDIV, ESHR)) { + firstnode = IRO_DuplicateExpr(expr->linear, &list1); + } else { + firstnode = IRO_NewLinear(IROLinearOp2Arg); + firstnode->index = ++IRO_NumLinear; + firstnode->rtype = type; + firstnode->nodetype = EMUL; + firstnode->u.diadic.left = IRO_DuplicateExpr(nd1, &list1); + if (unk) + firstnode->u.diadic.right = IRO_DuplicateExpr(nd1, &list1); + else + firstnode->u.diadic.right = IRO_DuplicateExpr(nd2, &list1); + IRO_AddToList(firstnode, &list1); + } + + secondnode = IRO_NewLinear(IROLinearOp2Arg); + secondnode->index = ++IRO_NumLinear; + secondnode->rtype = type; + secondnode->nodetype = EASS; + secondnode->u.diadic.left = IRO_TempReference(tempObj, &list1); + secondnode->u.diadic.left->flags |= IROLF_Ind | IROLF_Assigned; + secondnode->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Assigned; + secondnode->u.diadic.right = firstnode; + IRO_AddToList(secondnode, &list1); + IRO_Paste(list1.head, list1.tail, PredInt); + if ( + !IS_LINEAR_DIADIC_2(expr->linear, EDIV, ESHR) && + induction->addConst != 1 && + (induction->addNode || !IRO_IsConstant(nd2)) + ) { + flag23 = 1; + IRO_InitList(&list1); + thirdnode = IRO_NewLinear(IROLinearOp2Arg); + thirdnode->index = ++IRO_NumLinear; + thirdnode->rtype = nd2->rtype; + thirdnode->nodetype = EMUL; + + if (!induction->addNode) { + thirdnode->u.diadic.left = IRO_DuplicateExpr(nd2, &list1); + thirdnode->u.diadic.right = IRO_NewLinear(IROLinearOperand); + thirdnode->u.diadic.right->index = ++IRO_NumLinear; + enode = IRO_NewENode(EINTCONST); + enode->rtype = nd2->rtype; + thirdnode->u.diadic.right->rtype = nd2->rtype; + CInt64_SetLong(&enode->data.intval, induction->addConst); + thirdnode->u.diadic.right->u.node = enode; + IRO_AddToList(thirdnode->u.diadic.right, &list1); + } else { + thirdnode->u.diadic.left = IRO_DuplicateExpr(nd2, &list1); + thirdnode->u.diadic.right = IRO_DuplicateExpr(induction->addNode, &list1); + if (nd2->rtype != induction->addNode->rtype) { + tmp = IRO_NewLinear(IROLinearOp1Arg); + tmp->nodetype = ETYPCON; + tmp->index = ++IRO_NumLinear; + tmp->rtype = nd2->rtype; + tmp->u.monadic = thirdnode->u.diadic.right; + IRO_AddToList(tmp, &list1); + thirdnode->u.diadic.right = tmp; + } + } + IRO_AddToList(thirdnode, &list1); + + tempObj2 = create_temp_object(nd2->rtype); + + fourthnode = IRO_NewLinear(IROLinearOp2Arg); + fourthnode->index = ++IRO_NumLinear; + fourthnode->rtype = nd2->rtype; + fourthnode->nodetype = EASS; + fourthnode->u.diadic.left = IRO_TempReference(tempObj2, &list1); + fourthnode->u.diadic.left->flags |= IROLF_Ind | IROLF_Assigned; + fourthnode->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Assigned; + fourthnode->u.diadic.right = thirdnode; + IRO_AddToList(fourthnode, &list1); + IRO_Paste(list1.head, list1.tail, PredInt); + } + + IRO_InitList(&list2); + fifthnode = IRO_NewLinear(IROLinearOp2Arg); + fifthnode->index = ++IRO_NumLinear; + fifthnode->rtype = type; + if (induction->nd->type == IROLinearOp2Arg) { + if (induction->nd->nodetype == EASS && IS_LINEAR_DIADIC(induction->nd->u.diadic.right, EADD)) + fifthnode->nodetype = EADDASS; + else if (induction->nd->nodetype == EASS && IS_LINEAR_DIADIC(induction->nd->u.diadic.right, ESUB)) + fifthnode->nodetype = ESUBASS; + else + fifthnode->nodetype = induction->nd->nodetype; + } else { + if (induction->nd->nodetype == EPREINC || induction->nd->nodetype == EPOSTINC) + fifthnode->nodetype = EADDASS; + else + fifthnode->nodetype = ESUBASS; + } + + fifthnode->u.diadic.left = IRO_TempReference(tempObj, &list2); + fifthnode->u.diadic.left->flags |= IROLF_Ind | IROLF_Used | IROLF_Assigned; + fifthnode->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Used | IROLF_Assigned; + if (!unk) { + if (!flag23) { + if (induction->addConst == 1 || IS_LINEAR_DIADIC_2(expr->linear, EDIV, ESHR)) { + fifthnode->u.diadic.right = IRO_DuplicateExpr(nd2, &list2); + } else { + fifthnode->u.diadic.right = IRO_NewLinear(IROLinearOperand); + fifthnode->u.diadic.right->index = ++IRO_NumLinear; + enode = IRO_NewENode(EINTCONST); + enode->rtype = nd2->rtype; + fifthnode->u.diadic.right->rtype = nd2->rtype; + CInt64_SetLong(&enode->data.intval, induction->addConst * CInt64_GetULong(&nd2->u.node->data.intval)); + fifthnode->u.diadic.right->u.node = enode; + IRO_AddToList(fifthnode->u.diadic.right, &list2); + } + } else { + fifthnode->u.diadic.right = IRO_TempReference(tempObj2, &list2); + fifthnode->u.diadic.right->flags |= IROLF_Used; + } + } + + fifthnode->index = ++IRO_NumLinear; + IRO_AddToList(fifthnode, &list2); + IRO_Paste(list2.head, list2.tail, IRO_FindStart(induction->nd)); + IRO_WalkTree(expr->linear, IRO_RemoveExpr_Action); + expr->x8 = tempObj; + expr->next = RisList; + RisList = expr; + return expr; +} + +static IRONode *CreatePreHeader(IRONode *fnode1, IRONode *fnode2) { + IROLinear *labelnode; + IRONode *newfnode; + IRONode *iter; + CLabel *oldlabel; + CLabel *newlabel; + SwitchInfo *swinfo; + SwitchCase *swcase; + + newfnode = oalloc(sizeof(IRONode)); + memset(newfnode, 0, sizeof(IRONode)); + newfnode->index = IRO_NumNodes; + IRO_NumNodes++; + + labelnode = IRO_NewLinear(IROLinearLabel); + labelnode->index = IRO_NumLinear++; + labelnode->next = NULL; + labelnode->u.label.label = IRO_NewLabel(); + labelnode->flags |= IROLF_1; + labelnode->u.label.label->stmt = (Statement *) newfnode; + newfnode->first = labelnode; + newfnode->last = labelnode; + + if (fnode2) { + fnode2->last->next = labelnode; + labelnode->next = IRO_NewLinear(IROLinearNop); + labelnode->next->next = fnode1->first; + fnode2->nextnode = newfnode; + newfnode->nextnode = fnode1; + } else { + CError_ASSERT(1254, fnode1->first->type == IROLinearLabel); + labelnode->next = IRO_NewLinear(IROLinearGoto); + labelnode->next->u.label.label = fnode1->first->u.label.label; + IRO_LastNode->last->next = labelnode; + IRO_LastNode->nextnode = newfnode; + IRO_LastNode = newfnode; + IRO_LastLinear = labelnode->next; + } + + newfnode->last = labelnode->next; + + IRO_NodeTable = oalloc(sizeof(IRONode *) * IRO_NumNodes); + memset(IRO_NodeTable, 0, sizeof(IRONode *) * IRO_NumNodes); + for (iter = IRO_FirstNode; iter; iter = iter->nextnode) + IRO_NodeTable[iter->index] = iter; + + if (fnode1->first->type == IROLinearLabel) { + oldlabel = fnode1->first->u.label.label; + newlabel = newfnode->first->u.label.label; + for (iter = IRO_FirstNode; iter; iter = iter->nextnode) { + if (!Bv_IsBitSet(iter->index, InLoop) && iter != newfnode) { + switch (iter->last->type) { + case IROLinearGoto: + if (iter->last->u.label.label == oldlabel) + iter->last->u.label.label = newlabel; + break; + case IROLinearIf: + case IROLinearIfNot: + if (iter->last->u.label.label == oldlabel) + iter->last->u.label.label = newlabel; + break; + case IROLinearSwitch: + swinfo = iter->last->u.swtch.info; + for (swcase = swinfo->cases; swcase; swcase = swcase->next) { + if (swcase->label == oldlabel) + swcase->label = newlabel; + } + if (swinfo->defaultlabel == oldlabel) + swinfo->defaultlabel = newlabel; + break; + } + } + } + } + + IRO_ComputeSuccPred(); + IRO_ComputeDom(); + return newfnode; +} + +static IRONode *CreateNewLoopExitSuccessor(IRONode *fnode1) { + IROLinear *labelnode; + IRONode *fnode2; + IRONode *newfnode; + Boolean flag; + IRONode *iter; + CLabel *oldlabel; + CLabel *newlabel; + SwitchInfo *swinfo; + SwitchCase *swcase; + UInt16 i; + + CError_ASSERT(1355, fnode1 != NULL && LoopExitNumber == 1); + + fnode2 = NULL; + flag = 0; + + for (i = 0; i < fnode1->numpred; i++) { + iter = IRO_NodeTable[fnode1->pred[i]]; + if (Bv_IsBitSet(iter->index, InLoop_Exits)) { + CError_ASSERT(1366, fnode2 == NULL); + fnode2 = iter; + if (!flag) { + if ( + !iter->last || + !fnode1->first || + fnode1->first->type != IROLinearLabel || + ( + (iter->last->type == IROLinearIf || iter->last->type == IROLinearIfNot) && + iter->last->u.label.label != fnode1->first->u.label.label + )) + flag = 1; + } + } + } + + CError_ASSERT(1382, fnode2 != NULL); + + newfnode = oalloc(sizeof(IRONode)); + memset(newfnode, 0, sizeof(IRONode)); + newfnode->index = IRO_NumNodes; + IRO_NumNodes++; + + labelnode = IRO_NewLinear(IROLinearLabel); + labelnode->index = IRO_NumLinear++; + labelnode->next = NULL; + labelnode->u.label.label = IRO_NewLabel(); + labelnode->flags |= IROLF_1; + labelnode->u.label.label->stmt = (Statement *) newfnode; + newfnode->first = labelnode; + newfnode->last = labelnode; + + if (flag) { + fnode2->last->next = labelnode; + labelnode->next = IRO_NewLinear(IROLinearNop); + labelnode->next->next = fnode1->first; + fnode2->nextnode = newfnode; + newfnode->nextnode = fnode1; + } else { + CError_ASSERT(1422, fnode1->first->type == IROLinearLabel); + labelnode->next = IRO_NewLinear(IROLinearGoto); + labelnode->next->u.label.label = fnode1->first->u.label.label; + IRO_LastNode->last->next = labelnode; + IRO_LastNode->nextnode = newfnode; + IRO_LastNode = newfnode; + IRO_LastLinear = labelnode->next; + } + + newfnode->last = labelnode->next; + + IRO_NodeTable = oalloc(sizeof(IRONode *) * IRO_NumNodes); + memset(IRO_NodeTable, 0, sizeof(IRONode *) * IRO_NumNodes); + for (iter = IRO_FirstNode; iter; iter = iter->nextnode) + IRO_NodeTable[iter->index] = iter; + + if (fnode1->first->type == IROLinearLabel) { + oldlabel = fnode1->first->u.label.label; + newlabel = newfnode->first->u.label.label; + switch (fnode2->last->type) { + case IROLinearGoto: + if (fnode2->last->u.label.label == oldlabel) + fnode2->last->u.label.label = newlabel; + break; + case IROLinearIf: + case IROLinearIfNot: + if (fnode2->last->u.label.label == oldlabel) + fnode2->last->u.label.label = newlabel; + break; + case IROLinearSwitch: + swinfo = fnode2->last->u.swtch.info; + for (swcase = swinfo->cases; swcase; swcase = swcase->next) { + if (swcase->label == oldlabel) + swcase->label = newlabel; + } + if (swinfo->defaultlabel == oldlabel) + swinfo->defaultlabel = newlabel; + break; + } + } + + IRO_ComputeSuccPred(); + IRO_ComputeDom(); + return newfnode; +} + +void AddPreds(IRONode *fnode) { + IRONode *pred; + int i; + + for (i = 0; i < fnode->numpred; i++) { + pred = IRO_NodeTable[fnode->pred[i]]; + if (!Bv_IsBitSet(pred->index, InLoop)) { + Bv_SetBit(pred->index, InLoop); + AddPreds(pred); + } + } +} + +static void RemoveNoopsFromExprList(void) { + IROExpr *expr; + IROExpr *prev; + + expr = IRO_FirstExpr; + prev = NULL; + while (expr) { + if (expr->linear->type == IROLinearNop) { + if (prev) + prev->next = expr->next; + else + IRO_FirstExpr = expr->next; + expr = expr->next; + } else { + prev = expr; + expr = expr->next; + } + } +} + +void IncLoopDepth(void) { + IRONode *fnode; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (Bv_IsBitSet(fnode->index, InLoop)) + fnode->loopdepth++; + } +} + +void IRO_SetLoopDepth(void) { + IRONode *fnode; + IRONode *pred; + UInt16 i; + UInt16 flag; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) + fnode->loopdepth = 0; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + flag = 0; + + for (i = 0; i < fnode->numpred; i++) { + pred = IRO_NodeTable[fnode->pred[i]]; + if (Bv_IsBitSet(fnode->index, pred->dom)) { + if (!flag) { + Bv_AllocVector(&InLoop, IRO_NumNodes + 1); + Bv_Clear(InLoop); + Bv_SetBit(fnode->index, InLoop); + } + flag = 1; + Bv_SetBit(pred->index, InLoop); + if (pred != fnode) + AddPreds(pred); + } + } + + if (flag) + IncLoopDepth(); + } + + IRO_CheckForUserBreak(); +} + +static void InsertBranchAroundLoopPreheaders(void) { + IRONode *fnode; + CLabel *label; + IRONode *iter; + IROLinear *endnode; + IROLinear *labelnode; + + if (IRO_EndNode && IRO_EndNode->last && IRO_EndNode->last->type == IROLinearEnd) { + label = IRO_NewLabel(); + fnode = IRO_NewFlowGraphNode(); + IRO_LastNode->nextnode = fnode; + label->stmt = (Statement *) fnode; + + IRO_NodeTable = oalloc(sizeof(IRONode *) * IRO_NumNodes); + memset(IRO_NodeTable, 0, sizeof(IRONode *) * IRO_NumNodes); + for (iter = IRO_FirstNode; iter; iter = iter->nextnode) + IRO_NodeTable[iter->index] = iter; + + labelnode = IRO_NewLinear(IROLinearLabel); + labelnode->index = ++IRO_NumLinear; + labelnode->u.label.label = label; + labelnode->flags |= IROLF_1; + fnode->first = labelnode; + IRO_LastLinear->next = labelnode; + + endnode = IRO_NewLinear(IROLinearEnd); + memcpy(endnode, IRO_EndNode->last, sizeof(IROLinear)); + endnode->index = ++IRO_NumLinear; + endnode->next = NULL; + fnode->last = endnode; + labelnode->next = endnode; + IRO_LastLinear = endnode; + + IRO_EndNode->last->type = IROLinearGoto; + IRO_EndNode->last->u.label.label = label; + IRO_LastNode = fnode; + IRO_EndNode = fnode; + + IRO_ComputeSuccPred(); + IRO_ComputeDom(); + } +} + +void IRO_FindLoops(void) { + IRONode *fnode; + IRONode *pred; + UInt16 i; + UInt16 flag; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + flag = 0; + + for (i = 0; i < fnode->numpred; i++) { + pred = IRO_NodeTable[fnode->pred[i]]; + if (Bv_IsBitSet(fnode->index, pred->dom)) { + if (!flag) { + Bv_AllocVector(&InLoop, IRO_NumNodes + 1); + Bv_Clear(InLoop); + Bv_SetBit(fnode->index, InLoop); + } + flag = 1; + Bv_SetBit(pred->index, InLoop); + if (pred != fnode) + AddPreds(pred); + } + } + + if (flag) { + IncLoopDepth(); + IRO_Dump("IRO_FindLoops:Found loop with header %d\n", fnode->index); + IRO_DumpBits("Loop includes: ", InLoop); + MyHandleLoop_Motion(fnode); + IRO_UpdateFlagsOnInts(); + MyHandleLoop_Vector(fnode); + RemoveNoopsFromExprList(); + IRO_UpdateFlagsOnInts(); + IRO_UpdateVars(); + } + } + + if (!IRO_FunctionHasReturn && IRO_EndNode != IRO_LastNode) + InsertBranchAroundLoopPreheaders(); +} + +static void CheckSubableSub(IROLinear *linear, Boolean isFirst) { + if (isFirst && IRO_IsSubableExpression(linear)) { + IRO_Dump("Subable Expression is %d\n", linear->index); + NoSubableSubs = 0; + } +} + +static int NoSubableSubExprs(IROLinear *nd) { + NoSubableSubs = 1; + IRO_WalkTree(nd, CheckSubableSub); + return NoSubableSubs; +} + +void ComputeLoopKills(void) { + IRONode *fnode; + IROLinear *nd; + + Bv_AllocVector(&AllKills, IRO_NumVars + 1); + Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1); + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (Bv_IsBitSet(fnode->index, InLoop) && (nd = fnode->first)) { + Bv_AllocVector(&fnode->x16, IRO_NumVars + 1); + Bv_AllocVector(&fnode->x1E, IRO_NumVars + 1); + while (1) { + Bv_Clear(IRO_VarKills); + IRO_GetKills(nd); + Bv_Or(IRO_VarKills, AllKills); + if (nd == fnode->last) + break; + nd = nd->next; + } + } + } +} + +void ComputeLoopInvariance(void) { + IRONode *fnode; + IROLinear *nd; + + IRO_Depends = IRO_VarKills; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (Bv_IsBitSet(fnode->index, InLoop) && (nd = fnode->first)) { + nd->flags &= ~IROLF_LoopInvariant; + while (1) { + if ((nd->flags & IROLF_Reffed) && nd->type != IROLinearNop) { + IRO_FindDepends_NoAlloc(nd); + if (!IRO_IsVolatile && !Bv_BitsInCommon(IRO_Depends, AllKills)) + nd->flags |= IROLF_LoopInvariant; + + if (IRO_CouldError) + nd->flags |= IROLF_CouldError; + else + nd->flags &= ~IROLF_CouldError; + } + + if (nd == fnode->last) + break; + nd = nd->next; + } + } + } +} + +void ComputeLoopInduction(void) { + IRONode *fnode; + IROLinear *nd; + Boolean flag; + Object *obj; + Object *obj2; + Object *obj3; + VarRecord *var; + IROLinear *tmpnd; + IROLoopInd *ind; + Boolean isUnsigned; + + Bv_AllocVector(&AllKills, IRO_NumVars + 1); + Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1); + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (Bv_IsBitSet(fnode->index, InLoop) && (nd = fnode->first)) { + while (1) { + Bv_Clear(IRO_VarKills); + IRO_GetKills(nd); + Bv_Or(IRO_VarKills, AllKills); + flag = 0; + if ( + ( + nd->type == IROLinearOp2Arg && + nd->rtype->size <= 4 && + (nd->nodetype == EADDASS || nd->nodetype == ESUBASS) && + (obj = IRO_IsVariable(nd->u.diadic.left)) && + obj->type->size == nd->rtype->size && + IS_TYPE_INT(obj->type) && + ( + (IRO_IsIntConstant(nd->u.diadic.right) && CInt64_GetULong(&nd->u.diadic.right->u.node->data.intval)) + || + (nd->u.diadic.right->flags & IROLF_LoopInvariant) + ) + ) + || + ( + nd->type == IROLinearOp1Arg && + nd->rtype->size <= 4 && + (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC || nd->nodetype == EPREINC || nd->nodetype == EPREDEC) && + (obj = IRO_IsVariable(nd->u.monadic)) && + obj->type->size == nd->rtype->size && + IS_TYPE_INT(obj->type) + ) + ) + { + flag = 1; + } + else if ( + nd->type == IROLinearOp2Arg && + nd->rtype->size <= 4 && + nd->nodetype == EASS && + (obj = IRO_IsVariable(nd->u.diadic.left)) && + obj->type->size == nd->rtype->size && + IS_TYPE_INT(obj->type) && + nd->u.diadic.right->type == IROLinearOp2Arg && + (nd->u.diadic.right->nodetype == EADD || nd->u.diadic.right->nodetype == ESUB) + ) + { + if (nd->u.diadic.right->nodetype == EADD) { + obj2 = IRO_IsVariable(nd->u.diadic.right->u.diadic.left); + obj3 = IRO_IsVariable(nd->u.diadic.right->u.diadic.right); + if (obj2 == obj && obj3 != obj && (nd->u.diadic.right->u.diadic.right->flags & IROLF_LoopInvariant)) + flag = 1; + + if (obj3 == obj && obj2 != obj && (nd->u.diadic.right->u.diadic.left->flags & IROLF_LoopInvariant)) { + flag = 1; + tmpnd = nd->u.diadic.right->u.diadic.left; + nd->u.diadic.right->u.diadic.left = nd->u.diadic.right->u.diadic.right; + nd->u.diadic.right->u.diadic.right = tmpnd; + } + } else { + obj2 = IRO_IsVariable(nd->u.diadic.right->u.diadic.left); + obj3 = IRO_IsVariable(nd->u.diadic.right->u.diadic.right); + if (obj2 == obj && obj3 != obj && (nd->u.diadic.right->u.diadic.right->flags & IROLF_LoopInvariant)) + flag = 1; + } + } + + if (flag) { + if ((var = IRO_FindAssigned(nd))) { + if (var->xA == 2) + var->xA = 0; + else if (var->xA == 1) + var->xA = 2; + } + } else { + for (var = IRO_FirstVar; var; var = var->next) { + if (Bv_IsBitSet(var->index, IRO_VarKills)) + var->xA = 0; + } + } + + if (nd == fnode->last) + break; + nd = nd->next; + } + } + } + + IRO_DumpBits("Killed in loop: ", AllKills); + + for (fnode = IRO_FirstNode, FirstInd = NULL; fnode; fnode = fnode->nextnode) { + if (Bv_IsBitSet(fnode->index, InLoop) && (nd = fnode->first)) { + while (1) { + if ( + ( + nd->type == IROLinearOp2Arg && + (nd->nodetype == EADDASS || nd->nodetype == ESUBASS || nd->nodetype == EASS) + ) + || + ( + nd->type == IROLinearOp1Arg && + (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC || nd->nodetype == EPREINC || nd->nodetype == EPREDEC) + ) + ) { + if ((var = IRO_FindAssigned(nd)) && var->xA == 2 && var->object->type->size <= 4) { + ind = oalloc(sizeof(IROLoopInd)); + ind->fnode = fnode; + ind->var = var; + ind->nd = nd; + ind->next = FirstInd; + ind->addNode = NULL; + ind->addConst = 0; + ind->flags = 0; + + if (nd->type == IROLinearOp2Arg) { + isUnsigned = IRO_IsUnsignedType(nd->rtype); + if (IRO_IsIntConstant(nd->u.diadic.right)) { + CInt64 val = nd->u.diadic.right->u.node->data.intval; + if (IS_LINEAR_DIADIC(nd, EADDASS) && CInt64_Less(val, cint64_zero)) { + nd->nodetype = ESUBASS; + nd->u.diadic.right->u.node->data.intval = CInt64_Neg(val); + } + if (isUnsigned) { + CInt64_ConvertUInt32(&nd->u.diadic.right->u.node->data.intval); + ind->addConst = CInt64_GetULong(&nd->u.diadic.right->u.node->data.intval); + } else { + CInt64_ConvertInt32(&nd->u.diadic.right->u.node->data.intval); + ind->addConst = CInt64_GetULong(&nd->u.diadic.right->u.node->data.intval); + } + ind->addNode = NULL; + } else if (nd->nodetype == EADDASS || nd->nodetype == ESUBASS) { + ind->addNode = nd->u.diadic.right; + } else if (nd->nodetype == EASS) { + ind->addNode = nd->u.diadic.right->u.diadic.right; + } + } else { + if (IS_TYPE_POINTER_ONLY(nd->rtype)) + ind->addConst = TPTR_TARGET(nd->rtype)->size; + else + ind->addConst = 1; + ind->addNode = NULL; + } + + FirstInd = ind; + + if (IS_LINEAR_DIADIC_2(nd, EADDASS, ESUBASS)) { + if (nd->u.diadic.right->flags & IROLF_LoopInvariant) + IRO_Dump("Found induction variable the new way: %s\n", var->object->name->name); + else + IRO_Dump("Found induction variable the old way: %s\n", var->object->name->name); + } else if (nd->type == IROLinearOp2Arg && (nd->u.diadic.right->nodetype == EADD || nd->u.diadic.right->nodetype == ESUB)) { + IRO_Dump("Found induction variable the new way: %s\n", var->object->name->name); + } else { + IRO_Dump("Found induction variable the old way: %s\n", var->object->name->name); + } + } + } + + if (nd == fnode->last) + break; + nd = nd->next; + } + } + } +} + +static void IRO_ActUnmarkLoopInvariance(IROLinear *linear, Boolean isFirst) { + if (isFirst) + linear->flags &= ~IROLF_LoopInvariant; +} + +static void UnmarkSubexpressionsOfInvariantExpressions(void) { + IROExpr *expr; + + for (expr = IRO_FirstExpr; expr; expr = expr->next) { + if ( + Bv_IsBitSet(expr->node->index, InLoop) && + !expr->notSubable && + (!expr->couldError || expr->node->mustreach) && + (expr->linear->flags & IROLF_LoopInvariant) + ) { + IRO_WalkTree(expr->linear, IRO_ActUnmarkLoopInvariance); + expr->linear->flags |= IROLF_LoopInvariant; + } + } +} + +static void MyHandleLoop_Vector(IRONode *fnode) { + IRONode *pred; + UInt16 i; + IROExpr *expr; + IROExpr *removedExprs; + IROExpr *exprnext; + IROLoopInd *induction; + IROExpr *exprinner; + Boolean flag24; + IRONode *v2; + IRONode *node22; + int flag21; + IRONode *iter; + IROExpr *searchris; + IROLinear *reduceNd1; + VarRecord *var; + IROLinear *reduceNd2; + + IRO_FirstExpr = NULL; + LoopNode = fnode; + FindMustReach(); + + for (var = IRO_FirstVar; var; var = var->next) + var->xA = 1; + + ComputeLoopKills(); + ComputeLoopInvariance(); + ComputeLoopInduction(); + LoopNode = fnode; + ConditionalHeaderAtBottom = 0; + + v2 = NULL; + flag21 = 0; + node22 = NULL; + for (i = 0; i < LoopNode->numpred; i++) { + pred = IRO_NodeTable[LoopNode->pred[i]]; + if (!Bv_IsBitSet(pred->index, InLoop)) { + if (flag21) + node22 = NULL; + else + node22 = pred; + flag21 = 1; + if (pred->nextnode == fnode) { + CError_ASSERT(2880, v2 == NULL || pred == v2); + v2 = pred; + } + } + } + + if (!flag21) { + IRO_Dump("No predecessor outside the loop\n"); + return; + } + + if (!node22 || node22->last->type != IROLinearGoto) + node22 = CreatePreHeader(fnode, v2); + PredInt = node22->last; + + if (PredInt->type == IROLinearGoto && PredInt->u.label.label != LoopNode->first->u.label.label) { + if (!KnownBounds || !Times) { + for (iter = IRO_FirstNode; iter; iter = iter->nextnode) + iter->mustreach = 0; + } else { + PredInt->u.label.label = LoopNode->first->u.label.label; + IRO_ComputeSuccPred(); + } + } + + if (copts.loopinvariants || copts.strengthreduction) { + MoveInvarianceInAddressExpr(); + IRO_DumpAfterPhase("MoveInvarianceInAddressExpr", 0); + IRO_FindExpressions(InLoop, 1); + IRO_DumpExprs(); + } + + if (copts.loopinvariants) + UnmarkSubexpressionsOfInvariantExpressions(); + + if (!copts.optimizesize && copts.strengthreduction) { + for (expr = IRO_FirstExpr; expr; expr = expr->next) { + if ( + !(expr->x0 & 4) && + Bv_IsBitSet(expr->node->index, InLoop) && + !expr->notSubable && + (!expr->couldError || expr->node->mustreach) && + Reducable(expr->linear, &reduceNd1, &reduceNd2, &var) + ) { + IRO_WalkTree(expr->linear, IRO_ActUnmarkRISCandidate); + expr->linear->flags |= IROLF_Ris; + expr->x1A = reduceNd1; + expr->x1E = var; + expr->x22 = reduceNd2; + } + } + } + + if (!copts.optimizesize && copts.strengthreduction) { + RisList = NULL; + for (expr = IRO_FirstExpr; expr; expr = exprnext) { + exprnext = expr->next; + if (!(expr->x0 & 4) && (expr->linear->flags & IROLF_Ris)) { + reduceNd1 = expr->x1A; + var = expr->x1E; + reduceNd2 = expr->x22; + + induction = FirstInd; + while (induction && induction->var != var) + induction = induction->next; + CError_ASSERT(3529, induction != NULL); + + IRO_FindDepends(reduceNd1); + if (!Bv_BitsInCommon(IRO_Depends, AllKills)) { + IRO_Dump("Found reduction in strength: %d\n", expr->linear->index); + if (IS_LINEAR_DIADIC(expr->linear, ESHL)) { + expr->linear->nodetype = EMUL; + CInt64_SetULong(&reduceNd1->u.node->data.intval, 1 << CInt64_GetULong(&reduceNd1->u.node->data.intval)); + reduceNd1->u.node->rtype = expr->linear->rtype; + } + + searchris = RisList; + while (1) { + if (!searchris) + break; + if (IRO_ExprsSame(expr->linear, searchris->linear)) + break; + searchris = searchris->next; + } + + if (searchris) { + IRO_Dump("Using existing RIS: %d\n", searchris->linear->index); + IRO_WalkTree(expr->linear, IRO_RemoveExpr_Action); + } else { + searchris = CreateRIS(expr, reduceNd2, reduceNd1, induction, 0); + } + IRO_ReplaceReference(expr->linear, searchris->x8, expr->linear); + IRO_ClipExpr(expr); + } + } + } + } + + RisList = NULL; + + expr = IRO_FirstExpr; + removedExprs = NULL; + if (copts.loopinvariants) { + while (expr) { + exprnext = expr->next; + flag24 = 0; + + if ( + Bv_IsBitSet(expr->node->index, InLoop) && + !expr->notSubable && + (!expr->couldError || expr->node->mustreach) && + (expr->linear->flags & IROLF_LoopInvariant) && + !(expr->x0 & 4) + ) { + IRO_Dump("Found loop invariant: %d\n", expr->linear->index); + + for (exprinner = removedExprs; exprinner; exprinner = exprinner->next) { + if (IRO_ExprsSame(exprinner->linear, expr->linear)) { + IRO_ReplaceReference(expr->linear, exprinner->x8, expr->linear); + IRO_NopOut(expr->linear); + IRO_Dump("Using already removed expr: %d\n", exprinner->linear->index); + IRO_RemoveExpr(expr); + flag24 = 1; + } + } + + if (!flag24 && !expr->x8) { + IRO_GetTemp(expr); + IRO_ReplaceReference(expr->linear, expr->x8, expr->linear); + IRO_MoveExpression(expr, PredInt); + IRO_AssignToTemp(expr); + IRO_RemoveExpr(expr); + expr->next = removedExprs; + removedExprs = expr; + } + } + + expr = exprnext; + } + } +} + +static void MyHandleLoop_Motion(IRONode *fnode) { + IROLoopMemRef *memref; + IRONode *pred; + UInt16 i; + IRONode *v2; + IRONode *node21; + Object *tempobj; + int flag20; + IRONode *iter; + IROLinear *ass; + VarRecord *var; + Boolean checkflag; + IROLoop *loop; + IROList list; + IROElmList *refiter; + + IRO_FirstExpr = NULL; + LoopNode = fnode; + FindMustReach(); + + for (var = IRO_FirstVar; var; var = var->next) + var->xA = 1; + + ComputeLoopKills(); + ComputeLoopInvariance(); + ComputeLoopInduction(); + LoopNode = fnode; + ConditionalHeaderAtBottom = 0; + + v2 = NULL; + flag20 = 0; + node21 = NULL; + for (i = 0; i < LoopNode->numpred; i++) { + pred = IRO_NodeTable[LoopNode->pred[i]]; + if (!Bv_IsBitSet(pred->index, InLoop)) { + if (flag20) + node21 = NULL; + else + node21 = pred; + flag20 = 1; + if (pred->nextnode == fnode) { + CError_ASSERT(3880, v2 == NULL || pred == v2); + v2 = pred; + } + } + } + + if (!flag20) { + IRO_Dump("No predecessor outside the loop\n"); + return; + } + + if (!node21 || node21->last->type != IROLinearGoto) + node21 = CreatePreHeader(fnode, v2); + PredInt = node21->last; + + if (PredInt->type == IROLinearGoto && PredInt->u.label.label != LoopNode->first->u.label.label) { + if (!KnownBounds || !Times) { + for (iter = IRO_FirstNode; iter; iter = iter->nextnode) + iter->mustreach = 0; + } else { + PredInt->u.label.label = LoopNode->first->u.label.label; + IRO_ComputeSuccPred(); + } + } + + if (copts.loopinvariants || copts.strengthreduction) { + MoveInvarianceInAddressExpr(); + IRO_DumpAfterPhase("MoveInvarianceInAddressExpr", 0); + IRO_FindExpressions(InLoop, 0); + IRO_DumpExprs(); + } + + if (copts.loopinvariants) + UnmarkSubexpressionsOfInvariantExpressions(); + + checkflag = 1; + Bv_AllocVector(&InLoop_Exits, IRO_NumNodes + 1); + Bv_AllocVector(&InLoop_Tails, IRO_NumNodes + 1); + LoopExitNumber = 0; + LoopExitSuccessor = NULL; + LoopTailNum = 0; + LoopTail = NULL; + IRO_FindLoopTailsAndExits(fnode); + FindMustReach1(fnode); + + loop = NULL; + if (LoopTailNum == 1) { + if (fnode->last->type == IROLinearIf || fnode->last->type == IROLinearIfNot) + loop = ExtractLoopInfo(fnode); + else if (LoopTail->last->type == IROLinearIf || LoopTail->last->type == IROLinearIfNot) + loop = ExtractLoopInfo(LoopTail); + } + + if (loop && !(loop->flags & LP_IFEXPR_NON_CANONICAL) && LoopExitNumber == 1) { + IRO_LoopMemRefFirst = NULL; + IRO_LoopMemRefCurrent = NULL; + CheckAllLoopAddresses(IRO_FirstNode, InLoop, &checkflag); + CheckAllLoopAddresses(IRO_FirstNode, InLoop, &checkflag); + if (checkflag) { + for (memref = IRO_LoopMemRefFirst; memref; memref = memref->next) { + if (memref->flags & LoopMemRef_10) + memref->flags |= LoopMemRef_8; + } + + for (memref = IRO_LoopMemRefFirst; memref; memref = memref->next) { + IRO_Dump("Loop Motion Candidate:: Int= %d", memref->nd->index); + if (memref->flags & LoopMemRef_8) + IRO_Dump("<invalid>"); + if (memref->flags & LoopMemRef_1) + IRO_Dump("<load>"); + if (memref->flags & LoopMemRef_2) + IRO_Dump("<store>"); + IRO_Dump("\n"); + + if (!(memref->flags & LoopMemRef_8)) { + tempobj = create_temp_object(memref->nd->rtype); + IRO_FindVar(tempobj, 1, 1); + if (IRO_FindVar(((IROLinear *) memref->rec->objRefs->element)->u.node->data.objref, 0, 1)) { + IRO_InitList(&list); + ass = IRO_NewLinear(IROLinearOp2Arg); + ass->index = ++IRO_NumLinear; + ass->rtype = memref->nd->rtype; + ass->nodetype = EASS; + ass->u.diadic.left = IRO_TempReference(tempobj, &list); + ass->u.diadic.left->flags |= IROLF_Ind | IROLF_Assigned; + ass->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Assigned; + ass->u.diadic.right = IRO_DuplicateExpr(memref->nd, &list); + IRO_AddToList(ass, &list); + IRO_Paste(list.head, list.tail, PredInt); + } else { + CError_FATAL(4123); + } + + if (LoopExitSuccessor->numpred != 1) + LoopExitSuccessor = CreateNewLoopExitSuccessor(LoopExitSuccessor); + + IRO_InitList(&list); + ass = IRO_NewLinear(IROLinearOp2Arg); + ass->index = ++IRO_NumLinear; + ass->rtype = memref->nd->rtype; + ass->nodetype = EASS; + ass->u.diadic.left = IRO_DuplicateExpr(memref->nd, &list); + ass->u.diadic.left->flags |= IROLF_Ind | IROLF_Assigned; + ass->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Assigned; + ass->u.diadic.right = IRO_TempReference(tempobj, &list); + IRO_AddToList(ass, &list); + + if (LoopExitSuccessor->first->type == IROLinearLabel) + IRO_PasteAfter(list.head, list.tail, LoopExitSuccessor->first); + else + IRO_Paste(list.head, list.tail, LoopExitSuccessor->first); + + for (refiter = memref->list; refiter; refiter = refiter->next) { + IRO_Dump("Loop Motion Candidate Reference at Int= %d\n", ((IROLinear *) refiter->element)->index); + IRO_InitList(&list); + IRO_TempReference(tempobj, &list); + IRO_Paste(list.head, list.tail, refiter->element); + IRO_LocateFather_Cut_And_Paste(refiter->element, list.tail); + } + } + } + } + } + + IRO_DumpAfterPhase("After Motion", 0); +} + +static Boolean CheckLoopAddress(IROLinear *nd, Boolean mustreach1) { + IROLoopMemRef *memref; + IROAddrRecord *rec; + IROAddrRecord *otherrec; + IROLinear *inner; + IROElmList *list; + Boolean flag; + + inner = nd->u.monadic; + rec = IRO_InitAddrRecordPointer(inner); + if (IS_LINEAR_ENODE(inner, EOBJREF)) { + rec->numObjRefs++; + IRO_AddElmToList(inner, &rec->objRefs); + } else if (IS_LINEAR_DIADIC(inner, EADD)) { + IRO_DecomposeAddressExpression(inner, rec); + } else { + return 0; + } + + if (rec->numObjRefs != 1) + return 0; + + flag = (nd->flags & IROLF_CouldError) || !(nd->flags & IROLF_Reffed); + if (!IRO_LoopMemRefFirst) { + MakeLoopEntry(nd, rec, mustreach1, flag); + } else { + for (memref = IRO_LoopMemRefFirst; memref; memref = memref->next) { + otherrec = memref->rec; + if (((IROLinear *) rec->objRefs->element)->u.node->data.objref == ((IROLinear *) otherrec->objRefs->element)->u.node->data.objref) { + if (IRO_ExprsSame(inner, otherrec->linear)) { + list = oalloc(sizeof(IROElmList)); + list->element = nd; + list->next = NULL; + if (!memref->list) { + memref->list = list; + } else { + list->next = memref->list; + memref->list = list; + } + } else { + memref->flags |= LoopMemRef_8; + } + + if (!mustreach1 && flag) + memref->flags |= LoopMemRef_8; + if (mustreach1 || flag) + memref->flags &= ~LoopMemRef_10; + break; + } + } + + if (!memref) + MakeLoopEntry(nd, rec, mustreach1, flag); + } + + return 1; +} + +static void CheckAllLoopAddresses(IRONode *fnode, BitVector *bv, Boolean *resultFlag) { + IROLinear *nd; + Boolean flag; + + flag = *resultFlag; + while (fnode) { + if (Bv_IsBitSet(fnode->index, bv) && (nd = fnode->first)) { + while (flag) { + if (nd->type == IROLinearOp1Arg && nd->nodetype == EINDIRECT) + flag = CheckLoopAddress(nd, fnode->mustreach1); + else if (nd->type == IROLinearFunccall) + flag = 0; + + if (nd == fnode->last) + break; + nd = nd->next; + } + + if (!flag) + break; + } + fnode = fnode->nextnode; + } + *resultFlag = flag; +} + +static void MakeLoopEntry(IROLinear *nd, IROAddrRecord *rec, Boolean mustreach1, Boolean flag2) { + IROElmList *list; + + if (!IRO_IsRegable(((IROLinear *) rec->objRefs->element)->u.node->data.objref) && + (nd->u.monadic->flags & IROLF_LoopInvariant) && + !IRO_HasSideEffect(nd)) { + if (!IRO_LoopMemRefFirst) { + IRO_LoopMemRefCurrent = IRO_LoopMemRefFirst = oalloc(sizeof(IROLoopMemRef)); + } else { + IRO_LoopMemRefCurrent->next = oalloc(sizeof(IROLoopMemRef)); + IRO_LoopMemRefCurrent = IRO_LoopMemRefCurrent->next; + } + IRO_LoopMemRefCurrent->flags = LoopMemRef_10; + IRO_LoopMemRefCurrent->nd = nd; + IRO_LoopMemRefCurrent->rec = rec; + IRO_LoopMemRefCurrent->next = NULL; + IRO_LoopMemRefCurrent->list = NULL; + + list = oalloc(sizeof(IROElmList)); + list->element = nd; + list->next = NULL; + if (!IRO_LoopMemRefCurrent->list) { + IRO_LoopMemRefCurrent->list = list; + } else { + list->next = IRO_LoopMemRefCurrent->list; + IRO_LoopMemRefCurrent->list = list; + } + + if (((IROLinear *) rec->objRefs->element)->flags & IROLF_Assigned) { + IRO_LoopMemRefCurrent->flags |= LoopMemRef_2; + if (((IROLinear *) rec->objRefs->element)->flags & IROLF_Used) + IRO_LoopMemRefCurrent->flags |= LoopMemRef_1; + } else { + IRO_LoopMemRefCurrent->flags |= LoopMemRef_1; + } + + if (!mustreach1 && flag2) + IRO_LoopMemRefCurrent->flags |= LoopMemRef_8; + + if (mustreach1 || flag2) + IRO_LoopMemRefCurrent->flags &= ~LoopMemRef_10; + } +} + +void FindAssignmenttoInductionVar(IROLoop *loop, IRONode *fnode) { + IROLinear *nd; + UInt32 index; + + if (!loop->induction) { + loop->nd14 = NULL; + } else { + index = loop->induction->var->index; + for (nd = fnode->first; nd; nd = nd->next) { + Bv_Clear(IRO_VarKills); + IRO_GetKills(nd); + if (Bv_IsBitSet(index, IRO_VarKills)) + loop->nd14 = nd; + + if (nd == fnode->last) + break; + } + + if (loop->nd14 && loop->nd14->type != IROLinearOp2Arg) + loop->nd14 = NULL; + } +} + +static void ComputeIntWeight(IROLoop *loop, IROLinear *Int) { + loop->sizeBySomeMeasurement++; +} + +static IROLinear *IsTypconVar(IROLinear *nd) { + if (IS_LINEAR_MONADIC(nd, ETYPCON) && IRO_IsVariable(nd->u.monadic)) + return nd->u.monadic; + else + return NULL; +} + +IROLoop *ExtractLoopInfo(IRONode *fnode) { + Boolean flag30; + Boolean flag29; + Boolean flag28; + UInt32 counter27; + IROLoopInd *ind23; + Object *obj; + IROLinear *nd21; + IRONode *scanfnode; + IROLinear *left19; + IROLinear *right18; + IROLinear *tmp18; + IROLinear *scannd; + IROLinear *tmp; + VarRecord *var; + IROLoopInd *scanind; + IROLinear *left; + IROLinear *right; + UInt32 counter2; + UInt32 i; + IROLoop *loop; + + flag30 = 0; + flag29 = 0; + flag28 = 0; + counter27 = 0; + LoopNode = fnode; + + loop = oalloc(sizeof(IROLoop)); + loop->fnode = fnode; + nd21 = LoopNode->last->u.label.x4; + loop->nd18 = nd21; + loop->flags = 0; + loop->x8 = 0; + loop->nd14 = NULL; + loop->induction = NULL; + loop->index20 = -1; + loop->index24 = -1; + loop->sizeBySomeMeasurement = 0; + + if (nd21->type == IROLinearOp2Arg && IS_TYPE_INT(nd21->rtype)) { + ind23 = NULL; + left19 = nd21->u.diadic.left; + right18 = nd21->u.diadic.right; + if (IRO_IsVariable(left19) || (left19 = IsTypconVar(left19))) { + if ((var = IRO_FindVar(left19->u.monadic->u.node->data.objref, 0, 1))) { + scanind = FirstInd; + while (scanind && scanind->var != var) + scanind = scanind->next; + if (scanind) { + ind23 = scanind; + loop->flags |= LoopFlags_1; + loop->induction = scanind; + } + } + } + + if (IRO_IsVariable(right18) || (right18 = IsTypconVar(right18))) { + if ((var = IRO_FindVar(right18->u.monadic->u.node->data.objref, 0, 1))) { + scanind = FirstInd; + while (scanind && scanind->var != var) + scanind = scanind->next; + if (scanind) { + ind23 = scanind; + loop->flags &= ~LoopFlags_1; + loop->induction = scanind; + } + } + } + + if (ind23 && ind23->addConst > 0) { + if (loop->flags & LoopFlags_1) { + if ( + loop->nd18->type != IROLinearOp2Arg || + !(loop->nd18->nodetype == ELESS || loop->nd18->nodetype == EGREATER || loop->nd18->nodetype == ELESSEQU || loop->nd18->nodetype == EGREATEREQU) || + !loop->nd18->u.diadic.left || + !loop->nd18->u.diadic.left->rtype || + !IS_TYPE_INT(loop->nd18->u.diadic.left->rtype) || + !loop->nd18->u.diadic.right || + !loop->nd18->u.diadic.right->rtype || + !IS_TYPE_INT(loop->nd18->u.diadic.right->rtype) + ) { + loop->flags |= LP_IFEXPR_NON_CANONICAL; + return loop; + } + } else { + if ( + loop->nd18->type == IROLinearOp2Arg && + (loop->nd18->nodetype == EGREATER || loop->nd18->nodetype == EGREATEREQU) && + (left = loop->nd18->u.diadic.left) && + left->rtype && + IS_TYPE_INT(left->rtype) && + (right = loop->nd18->u.diadic.right) && + right->rtype && + IS_TYPE_INT(right->rtype) + ) { + loop->nd18->u.diadic.left = right; + loop->nd18->u.diadic.right = left; + if (loop->nd18->nodetype == EGREATER) + loop->nd18->nodetype = ELESS; + else if (loop->nd18->nodetype == EGREATEREQU) + loop->nd18->nodetype = ELESSEQU; + loop->flags |= LoopFlags_1; + } else if ( + loop->nd18->type == IROLinearOp2Arg && + (loop->nd18->nodetype == ELESS || loop->nd18->nodetype == ELESSEQU) && + (left = loop->nd18->u.diadic.left) && + left->rtype && + IS_TYPE_INT(left->rtype) && + (right = loop->nd18->u.diadic.right) && + right->rtype && + IS_TYPE_INT(right->rtype) + ) { + loop->nd18->u.diadic.left = right; + loop->nd18->u.diadic.right = left; + if (loop->nd18->nodetype == ELESS) + loop->nd18->nodetype = EGREATER; + else if (loop->nd18->nodetype == ELESSEQU) + loop->nd18->nodetype = EGREATEREQU; + loop->flags |= LoopFlags_1; + } else { + loop->flags |= LP_IFEXPR_NON_CANONICAL; + return loop; + } + } + } else { + loop->flags |= LP_INDUCTION_NOT_FOUND; + return loop; + } + } else if (nd21->type == IROLinearOp1Arg && IS_TYPE_INT(nd21->rtype)) { + if (nd21->nodetype == EPREINC || nd21->nodetype == EPOSTINC || nd21->nodetype == EPREDEC || nd21->nodetype == EPOSTDEC) { + if (IRO_IsVariable(nd21->u.monadic)) { + if ((var = IRO_FindVar(nd21->u.monadic->u.monadic->u.node->data.objref, 0, 1))) { + scanind = FirstInd; + while (scanind && scanind->var != var) + scanind = scanind->next; + if (scanind) { + ind23 = scanind; + loop->flags |= LoopFlags_10000; + loop->induction = scanind; + } else { + loop->flags |= LP_INDUCTION_NOT_FOUND; + return loop; + } + } else { + loop->flags |= LP_INDUCTION_NOT_FOUND; + return loop; + } + } else { + loop->flags |= LP_INDUCTION_NOT_FOUND; + return loop; + } + } else { + loop->flags |= LP_INDUCTION_NOT_FOUND; + return loop; + } + } else { + loop->flags |= LP_IFEXPR_NON_CANONICAL; + return loop; + } + + counter2 = 0; + scanind = FirstInd; + while (scanind) { + scanind = scanind->next; + counter2++; + } + + if (counter2 > 1) + loop->flags |= LP_HAS_MULTIPLE_INDUCTIONS; + + if ((scanind = loop->induction)) { + nd21 = scanind->nd; + if (nd21->type == IROLinearOp2Arg) { + if (IS_LINEAR_DIADIC_2(loop->nd18, ELESS, ELESSEQU)) { + if (nd21->nodetype == EADDASS) { + if (scanind->addConst == 1) + loop->flags |= LP_LOOP_STEP_ISADD; + if (scanind->addConst > 0) + loop->flags |= LP_LOOP_STEP_ISPOS; + } else if (nd21->nodetype == EASS && + IS_LINEAR_DIADIC(nd21->u.diadic.right, EADD) && + IRO_IsIntConstant(tmp18 = nd21->u.diadic.right->u.diadic.right) && + CTool_EndianReadWord32(&tmp18->u.node->data.intval.hi) == 0) { + if (CInt64_GetULong(&tmp18->u.node->data.intval) == 1) + loop->flags |= LP_LOOP_STEP_ISADD; + if (CInt64_GetULong(&tmp18->u.node->data.intval) > 0) + loop->flags |= LP_LOOP_STEP_ISPOS; + } + } + } else if (nd21->type == IROLinearOp1Arg) { + if (nd21->nodetype == EPREINC || nd21->nodetype == EPOSTINC) { + if (scanind->addConst == 1) + loop->flags |= LP_LOOP_STEP_ISADD; + if (scanind->addConst > 0) + loop->flags |= LP_LOOP_STEP_ISPOS; + } + if (nd21->nodetype == EPREDEC || nd21->nodetype == EPOSTDEC) { + if (scanind->addConst == 1) + loop->flags |= LoopFlags_2000; + if (scanind->addConst > 0) + loop->flags |= LP_LOOP_STEP_ISNEG; + } + } + loop->index24 = nd21->index; + loop->index20 = IRO_FindStart(nd21)->index; + } + + if (ind23) { + tmp = IRO_FindStart(fnode->last->u.diadic.right); + loop->flags |= LoopFlags_200; + if (loop->flags & LoopFlags_10000) { + for (scannd = loop->fnode->first; scannd && scannd != tmp; scannd = scannd->next) { + if (scannd->type != IROLinearLabel && scannd->type != IROLinearNop) + loop->flags &= ~LoopFlags_200; + } + } else { + for (scannd = ind23->nd->next; scannd && scannd != tmp; scannd = scannd->next){ + if (scannd->type != IROLinearLabel && scannd->type != IROLinearNop) + loop->flags &= ~LoopFlags_200; + } + for (scannd = loop->fnode->first; scannd && scannd != tmp; scannd = scannd->next){ + if ((scannd->index < loop->index20 || scannd->index > loop->index24) && scannd->type != IROLinearLabel && scannd->type != IROLinearNop) + loop->flags &= ~LoopFlags_200; + } + } + } + + for (scanfnode = IRO_FirstNode; scanfnode; scanfnode = scanfnode->nextnode) { + if (Bv_IsBitSet(scanfnode->index, InLoop) && scanfnode != fnode && (scannd = scanfnode->first)) { + while (1) { + if (scannd->type == IROLinearFunccall) + flag30 = 1; + if (scannd->type == IROLinearGoto) + flag28++; + if (flag28 >= 1) + flag29 = 1; + if (scannd->type == IROLinearIf || scannd->type == IROLinearIfNot || scannd->type == IROLinearSwitch || scannd->type == IROLinearReturn) + flag29 = 1; + + if (scannd->type == IROLinearAsm) + loop->flags |= LP_LOOP_HAS_ASM; + + if (!(scannd->flags & IROLF_Reffed) && scannd->type != IROLinearNop && scannd->type != IROLinearLabel) { + if (!IRO_IsAssignOp[scannd->nodetype]) { + loop->flags |= LoopFlags_8; + } else if (scannd->index < loop->index20 || scannd->index > loop->index24) { + counter27++; + if (IsAssignmentReductionCandidate(scannd) && counter27 == 1) + loop->flags |= LoopFlags_40000; + if (counter27 > 1) + loop->flags &= ~LoopFlags_40000; + } + } + + if (scannd->index < loop->index20 || scannd->index > loop->index24) { + if (IS_LINEAR_ENODE(scannd, EOBJREF)) { + obj = scannd->u.node->data.objref; + if ((scannd->flags & IROLF_Ind) && obj && obj == loop->induction->var->object) { + if (!(scannd->flags & IROLF_Assigned) && (scannd->flags & IROLF_Used)) { + IRO_Dump("Induction Used in loop\n"); + loop->flags |= LoopFlags_800; + } + } + } + + if (IS_LINEAR_DIADIC(scannd, ESHR) && + (obj = IRO_IsVariable(scannd->u.diadic.left)) && + IRO_IsIntConstant(scannd->u.diadic.right)) { + for (scanind = FirstInd; scanind; scanind = scanind->next) { + if (scanind->var->object == obj) { + IRO_Dump("Induction has DIV: %s\n", obj->name->name); + scanind->flags |= LoopInd_HasDiv; + } + } + } + + if (IS_LINEAR_DIADIC(scannd, EAND) && + (obj = IRO_IsVariable(scannd->u.diadic.left)) && + IRO_IsIntConstant(scannd->u.diadic.right)) { + for (scanind = FirstInd; scanind && obj; scanind = scanind->next) { + if (scanind->var->object == obj) { + IRO_Dump("Induction has MOD: %s\n", obj->name->name); + scanind->flags |= LoopInd_HasMod; + } + } + } + } + + ComputeIntWeight(loop, scannd); + if (scannd == scanfnode->last) + break; + scannd = scannd->next; + } + } + + if (flag30) + loop->flags |= LP_LOOP_HAS_CALLS; + if (flag29) + loop->flags |= LP_LOOP_HAS_CNTRLFLOW; + + for (i = 0; i < scanfnode->numsucc && scanfnode != fnode; i++) { + if (Bv_IsBitSet(scanfnode->index, InLoop) && !Bv_IsBitSet(scanfnode->succ[i], InLoop)) { + IRO_Dump("Node %d has an out of loop successor %d\n", scanfnode->index, scanfnode->succ[i]); + IRO_DumpBits("Loop includes: ", InLoop); + IRO_Dump("loop has multiple exits\n"); + loop->flags |= LoopFlags_1000; + } + } + } + + return loop; +} + +CLabel *BuildLabel(IROList *list) { + IROLinear *nd; + + nd = IRO_NewLinear(IROLinearLabel); + nd->index = IRO_NumLinear++; + nd->u.label.label = IRO_NewLabel(); + nd->flags |= IROLF_1; + IRO_AddToList(nd, list); + return nd->u.label.label; +} + +static void MoveInvarianceInAddressExpr(void) { + IRONode *fnode; + IROLinear *nd; + IROLinear *start; + IROList list; + + IRO_FirstExpr = IRO_LastExpr = NULL; + IRO_NumExprs = 0; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (Bv_IsBitSet(fnode->index, InLoop)) { + for (nd = fnode->first; nd; nd = nd->next) { + if (nd->type == IROLinearOp1Arg && + (nd->nodetype == EINDIRECT || nd->nodetype == EINDIRECT) && + IS_LINEAR_DIADIC(nd->u.monadic, EADD)) { + RearrangeInvarianceInAddressExpr(nd->u.monadic, &list); + start = IRO_FindStart(nd->u.monadic); + IRO_LocateFather_Cut_And_Paste(nd->u.monadic, list.tail); + IRO_Paste(list.head, list.tail, start); + } + + if (nd == fnode->last) + break; + } + } + } + + IRO_UpdateFlagsOnInts(); +} + +static void AddAddendLinear(IROLinear *nd) { + IROElmList *list; + + if (IS_LINEAR_DIADIC(nd, EADD)) { + AddAddendLinear(nd->u.diadic.left); + AddAddendLinear(nd->u.diadic.right); + } else { + list = oalloc(sizeof(IROElmList)); + list->element = nd; + list->next = NULL; + if (FirstAddendLinear) + LastAddendLinear->next = list; + else + FirstAddendLinear = list; + LastAddendLinear = list; + } +} + +static IROLinear *RearrangeInvarianceInAddressExpr(IROLinear *nd, IROList *list) { + IROLinear *result; + IROElmList *scanlist; + IROElmList *elist; + IROLinear *scannd; + + IRO_InitList(list); + FirstAddendLinear = LastAddendLinear = NULL; + AddAddendLinear(nd->u.diadic.left); + AddAddendLinear(nd->u.diadic.right); + + elist = NULL; + result = NULL; + for (scanlist = FirstAddendLinear; scanlist; scanlist = scanlist->next) { + scannd = scanlist->element; + if (!IRO_IsIntConstant(scannd) && (scannd->flags & IROLF_LoopInvariant)) { + if (result) { + IROLinear *tmp = IRO_NewLinear(IROLinearOp2Arg); + tmp->index = ++IRO_NumLinear; + tmp->nodetype = EADD; + tmp->u.diadic.left = result; + tmp->u.diadic.right = IRO_DuplicateExpr(scannd, list); + IRO_AddToList(tmp, list); + tmp->flags |= IROLF_LoopInvariant; + tmp->flags |= IROLF_Reffed; + tmp->rtype = result->rtype; + result = tmp; + } else { + result = IRO_DuplicateExpr(scannd, list); + } + + if (elist) + elist->next = scanlist->next; + else + FirstAddendLinear = scanlist->next; + } else { + elist = scanlist; + } + } + + for (scanlist = FirstAddendLinear, elist = NULL; scanlist; scanlist = scanlist->next) { + scannd = scanlist->element; + if (!IRO_IsIntConstant(scannd)) { + if (result) { + IROLinear *tmp = IRO_NewLinear(IROLinearOp2Arg); + tmp->index = ++IRO_NumLinear; + tmp->nodetype = EADD; + tmp->u.diadic.left = result; + tmp->u.diadic.right = IRO_DuplicateExpr(scannd, list); + IRO_AddToList(tmp, list); + tmp->flags |= IROLF_Reffed; + tmp->rtype = result->rtype; + result = tmp; + } else { + result = IRO_DuplicateExpr(scannd, list); + } + + if (elist) + elist->next = scanlist->next; + else + FirstAddendLinear = scanlist->next; + } else { + elist = scanlist; + } + } + + for (scanlist = FirstAddendLinear; scanlist; scanlist = scanlist->next) { + scannd = scanlist->element; + if (result) { + IROLinear *tmp = IRO_NewLinear(IROLinearOp2Arg); + tmp->index = ++IRO_NumLinear; + tmp->nodetype = EADD; + tmp->u.diadic.left = result; + tmp->u.diadic.right = scannd; + tmp->u.diadic.right = IRO_DuplicateExpr(scannd, list); + IRO_AddToList(tmp, list); + tmp->flags |= IROLF_Reffed; + tmp->rtype = result->rtype; + result = tmp; + } else { + result = IRO_DuplicateExpr(scannd, list); + } + } + + return result; +} + +static IROLinear *FindAddendForReductionPattern(IROLinear *a, IROLinear *b, Boolean *resultFlag) { + IROLinear *left; + IROLinear *right; + IROLinear *node28; + Boolean subflag; + + left = b->u.diadic.left; + right = b->u.diadic.right; + if (b->nodetype == EADD || b->nodetype == ESUB) { + node28 = left; + while (IS_LINEAR_MONADIC(node28, ETYPCON)) + node28 = node28->u.monadic; + + if (IS_LINEAR_MONADIC(node28, EINDIRECT) && (node28->u.monadic->flags & IROLF_LoopInvariant) && IRO_ExprsSame(a, node28)) { + *resultFlag = 1; + return left; + } + + if (IS_LINEAR_DIADIC_2(node28, EADD, ESUB)) { + if ((node28 = FindAddendForReductionPattern(a, node28, &subflag))) { + *resultFlag = 1; + return node28; + } + } + } + + *resultFlag = 0; + if (b->nodetype == EADD) { + node28 = right; + while (IS_LINEAR_MONADIC(node28, ETYPCON)) + node28 = node28->u.monadic; + + if (IS_LINEAR_MONADIC(node28, EINDIRECT) && (node28->u.monadic->flags & IROLF_LoopInvariant) && IRO_ExprsSame(a, node28)) { + return right; + } + + if (IS_LINEAR_DIADIC_2(node28, EADD, ESUB)) { + if ((node28 = FindAddendForReductionPattern(a, node28, &subflag))) { + return node28; + } + } + } + + return NULL; +} + +static void ReorderOperandsForReductionPattern(IROLinear *a, IROLinear *b) { + IROLinear *left; + IROLinear *right; + IROLinear *addend; + IROLinear *tmp; + Boolean flag; + + left = b->u.diadic.left; + right = b->u.diadic.right; + + if (b->nodetype == EADD && (addend = FindAddendForReductionPattern(a, b, &flag)) && addend != left) { + if (flag && IS_LINEAR_DIADIC_2(left, EADD, ESUB) && addend->rtype == right->rtype) { + tmp = left; + b->u.diadic.left = right; + left = right; + b->u.diadic.right = tmp; + right = tmp; + flag = 0; + } + + if (!flag && IS_LINEAR_DIADIC_2(right, EADD, ESUB) && addend->rtype == left->rtype) { + if (IRO_LocateFather_Cut_And_Paste_Without_Nopping(addend, left)) + b->u.diadic.left = addend; + } + } +} + +static UInt32 IsAssignmentReductionCandidate(IROLinear *nd) { + IROLinear *left; + IROLinear *right; + IROLinear *tmp; + + if (nd->type == IROLinearOp2Arg) { + if (nd->nodetype == EASS) { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + if (IS_LINEAR_MONADIC(left, EINDIRECT) && (left->u.monadic->flags & IROLF_LoopInvariant)) { + if (IS_LINEAR_MONADIC(right, ETYPCON) && + right->rtype->type == right->u.monadic->rtype->type && + IS_TYPE_INT(right->rtype) && + right->rtype->size < right->u.monadic->rtype->size) + right = right->u.monadic; + + if (IS_LINEAR_DIADIC_2(right, EADD, ESUB)) { + ReorderOperandsForReductionPattern(left, right); + tmp = right->u.diadic.left; + if (IS_LINEAR_MONADIC(tmp, ETYPCON)) + tmp = tmp->u.monadic; + if (IS_LINEAR_MONADIC(tmp, EINDIRECT) && + (tmp->u.monadic->flags & IROLF_LoopInvariant) && + IRO_ExprsSame(left, tmp) && + right->u.diadic.right->type == IROLinearOp2Arg) { + if (right->u.diadic.right->nodetype == EADD) + return 1; + if (right->u.diadic.right->nodetype == ESUB) + return 1; + if (right->u.diadic.right->nodetype == EMUL) + return 1; + if (right->u.diadic.right->nodetype == EDIV) + return 1; + } + } + } + } else if (nd->nodetype == EADDASS || nd->nodetype == ESUBASS) { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + + if (IS_LINEAR_MONADIC(right, ETYPCON) && + right->rtype->type == right->u.monadic->rtype->type && + IS_TYPE_INT(right->rtype) && + right->rtype->size < right->u.monadic->rtype->size) + right = right->u.monadic; + + if (IS_LINEAR_MONADIC(left, EINDIRECT) && + (left->u.monadic->flags & IROLF_LoopInvariant) && + right->type == IROLinearOp2Arg) { + if (right->nodetype == EADD) + return 1; + if (right->nodetype == ESUB) + return 1; + if (right->nodetype == EMUL) + return 1; + if (right->nodetype == EDIV) + return 1; + } + } + } + + return 0; +} + |