MWCC/compiler_and_linker/unsorted/IroUnrollLoop.c

2306 lines
74 KiB
C

#include "compiler/IroUnrollLoop.h"
#include "compiler/CError.h"
#include "compiler/IroFlowgraph.h"
#include "compiler/IroLinearForm.h"
#include "compiler/IroUtil.h"
#include "compiler/LoopDetection.h"
#include "compiler/IroLoop.h"
#include "compiler/IroDump.h"
#include "compiler/IroVars.h"
#include "compiler/CFunc.h"
#include "compiler/CMachine.h"
#ifdef __MWERKS__
#pragma options align=mac68k
#endif
typedef struct LoopList {
UInt8 flags;
BitVector *bv;
struct LoopList *next;
IRONode *fnode;
int xE;
} LoopList;
#ifdef __MWERKS__
#pragma options align=reset
#endif
// forward decls
static void IRO_FindLoops_Unroll(void);
static void LoopUnroll(int count, IRONode *fnode);
static int IsLoopUnrollable(IROLoop *loop);
static int IsDifferenceOfTermsConstant(IROAddrRecord *lowerRec, IROAddrRecord *upperRec, int isUnsigned, CInt64 *pval);
static IROLinear *BuildOrigIterationCount_DoWhile(IROList *list, IROLoop *loop);
static IROLinear *BuildPreAlignTemp(IROLoopInd *ind, UInt32 unrollFactor, IROList *list);
static IROLinear *BuildNewFinalvalue_DoWhile(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop);
static IROLinear *BuildUnrolledFinalvalue_DoWhile(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop);
void IRO_LoopUnroller(void) {
VectorPhaseCalledFromUnroll = 1;
IRO_FindLoops_Unroll();
IRO_CheckForUserBreak();
}
static void IRO_FindLoops_Unroll(void) {
IRONode *fnode;
IRONode *pred;
UInt16 i;
UInt16 flag;
LoopList *list;
LoopList *list2;
fnode = IRO_FirstNode;
LoopList_First = NULL;
while (fnode) {
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) {
if (!LoopList_First) {
list = oalloc(sizeof(LoopList));
list->next = NULL;
} else {
list = oalloc(sizeof(LoopList));
list->next = LoopList_First;
}
LoopList_First = list;
Bv_AllocVector(&list->bv, IRO_NumNodes + 1);
list->flags |= 1;
Bv_Copy(InLoop, list->bv);
list->fnode = fnode;
list->xE = 0;
}
fnode = fnode->nextnode;
}
list = LoopList_First;
Bv_AllocVector(&LoopTemp, IRO_NumNodes + 1);
while (list) {
for (list2 = LoopList_First; list2; list2 = list2->next) {
if (list2 != list) {
IRO_Dump(" header = %d \n", list2->fnode->index);
IRO_Dump(" l1 bit vector=\n");
IRO_DumpBits("", list2->bv);
IRO_Dump(" l bit vector=\n");
IRO_DumpBits("", list->bv);
if (Bv_IsSubset(list->bv, list2->bv))
list2->flags &= ~1;
}
}
list = list->next;
}
for (list = LoopList_First; list; list = list->next) {
if (list->flags & 1) {
IRONode *listfnode;
Bv_Copy(list->bv, InLoop);
listfnode = list->fnode;
IRO_Dump("IRO_FindLoops_Unroll:Found loop with header %d\n", listfnode->index);
IRO_DumpBits("Loop includes: ", InLoop);
LoopUnroll(copts.loop_unroll_count, listfnode);
IRO_UpdateFlagsOnInts();
}
}
}
static int CheckConstant(CInt64 a, CInt64 b, CInt64 *result) {
CInt64 shl = cint64_zero;
CInt64 work = cint64_zero;
CInt64 and = cint64_zero;
CInt64 i;
for (i = cint64_zero; CInt64_Less(i, a); i = CInt64_Add(i, cint64_one)) {
shl = CInt64_Shl(b, i);
and = CInt64_And(shl, work);
if (CInt64_NotEqual(and, cint64_zero))
return 0;
work = CInt64_Or(shl, work);
}
*result = work;
return 1;
}
typedef struct LoopPattern {
IROLinear *nd0;
IROLinear *nd4;
Type *type;
IROLinear *ndC;
IROLinear *nd10;
CInt64 val14;
CInt64 val1C;
} LoopPattern;
static void UnrollWhileLoopBody(IRONode *header, IRONode *fnode2, IRONode *fnode3, IROLoop *loop, LoopPattern *pattern, UInt32 unrollFactor) {
IRONode *scan;
int pass;
IROLinear *firstnode;
IROLinear *lastnd;
IROLinear *nd;
IROLinear *nd1;
IROLinear *nd2;
IROLinear *nd3;
IROLinear *nd4;
IROLinear *nd5;
IROLinear *nd6;
IROLinear *nd8;
IROLinear *nd7;
ENode *expr;
IROList list;
CInt64 zero;
CInt64 shiftval;
CInt64_SetLong(&zero, 0);
pass = 0;
do {
firstnode = NULL;
for (scan = fnode3; scan && scan != header; scan = scan->nextnode) {
IRO_InitList(&list);
lastnd = scan->last;
nd = scan->first;
while (1) {
if (nd->stmt)
nd->stmt->flags |= StmtFlag_10;
if (
(nd->index < loop->index20 || nd->index > loop->index24) &&
nd->type != IROLinearLabel &&
nd->type != IROLinearNop &&
!(nd->flags & IROLF_Reffed)
)
{
CError_ASSERT(345, nd->nodetype == EORASS || nd->nodetype == EANDASS || nd->nodetype == EXORASS);
IRO_DuplicateExpr(pattern->nd0, &list);
nd1 = list.tail;
shiftval = cint64_one;
shiftval = CInt64_Shl(shiftval, pattern->val1C);
nd2 = IRO_NewLinear(IROLinearOperand);
nd2->index = ++IRO_NumLinear;
nd2->rtype = pattern->nd0->rtype;
expr = IRO_NewENode(EINTCONST);
expr->rtype = pattern->nd0->rtype;
CInt64_SetLong(&expr->data.intval, pass * CInt64_GetULong(&shiftval));
nd2->u.node = expr;
IRO_AddToList(nd2, &list);
IRO_DuplicateExpr(pattern->nd4, &list);
nd3 = IRO_NewLinear(IROLinearOp2Arg);
nd3->index = ++IRO_NumLinear;
nd3->nodetype = EADD;
nd3->rtype = pattern->type;
nd3->u.diadic.left = list.tail;
nd3->u.diadic.right = nd2;
IRO_AddToList(nd3, &list);
nd4 = IRO_NewLinear(IROLinearOp2Arg);
nd4->index = ++IRO_NumLinear;
nd4->nodetype = EADD;
nd4->rtype = pattern->type;
nd4->u.diadic.left = nd3;
nd4->u.diadic.right = nd1;
IRO_AddToList(nd4, &list);
nd5 = IRO_NewLinear(IROLinearOp1Arg);
nd5->index = ++IRO_NumLinear;
nd5->nodetype = EINDIRECT;
nd5->rtype = nd->rtype;
nd5->u.monadic = nd4;
IRO_AddToList(nd5, &list);
nd6 = IRO_NewLinear(IROLinearOp2Arg);
*nd6 = *nd;
nd6->index = ++IRO_NumLinear;
nd6->u.diadic.left = list.tail;
nd6->next = NULL;
nd7 = IRO_NewLinear(IROLinearOperand);
nd7->index = ++IRO_NumLinear;
nd7->rtype = pattern->ndC->rtype;
expr = IRO_NewENode(EINTCONST);
expr->rtype = pattern->ndC->rtype;
nd7->u.node = expr;
nd7->next = NULL;
expr->data.intval = pattern->val14;
if (
IS_LINEAR_DIADIC(nd, EANDASS) &&
CInt64_Equal(pattern->val14, cint64_zero)
)
{
nd6->nodetype = EASS;
} else if (
IS_LINEAR_DIADIC(nd, EORASS) &&
!CTool_EndianReadWord32(&pattern->val14.hi)
)
{
UInt32 tmp = CInt64_GetULong(&pattern->val14);
if (
(nd->rtype->size == 1 && tmp == 0xFF) ||
(nd->rtype->size == 2 && tmp == 0xFFFF) ||
(nd->rtype->size == 4 && tmp == 0xFFFFFFFF)
)
{
nd6->nodetype = EASS;
}
}
IRO_AddToList(nd7, &list);
if (IS_LINEAR_MONADIC(pattern->nd10, ETYPCON)) {
nd8 = IRO_NewLinear(IROLinearOp1Arg);
*nd8 = *pattern->nd10;
nd8->index = ++IRO_NumLinear;
nd8->u.monadic = nd7;
nd8->next = NULL;
IRO_AddToList(nd8, &list);
} else {
nd8 = nd7;
}
nd6->u.diadic.right = nd8;
IRO_AddToList(nd6, &list);
if (!firstnode)
firstnode = list.head;
}
if (nd == lastnd)
break;
nd = nd->next;
}
if (list.head && list.tail)
IRO_Paste(list.head, list.tail, fnode2->last);
}
} while (++pass < 8);
}
static int PatternMatchLoop(IRONode *fnode, IROLoop *loop, IROLoopInd *ind, UInt32 *unrollFactor, SInt32 *result1, SInt32 *result2, LoopPattern *pattern) {
IROLinear *scan;
IROLinear *varnode;
IROLinear *nd1;
IROLinear *nd2;
IROLinear *left1;
IROLinear *left2;
IROLinear *right1;
IROLinear *right2;
Object *obj1;
Object *obj2;
CInt64 shl;
CInt64 val;
*result1 = 0;
*result2 = 0;
if ((scan = fnode->first)) {
while (1) {
if (
(scan->index < loop->index20 || scan->index > loop->index24) &&
!(scan->flags & IROLF_Reffed) &&
scan->type != IROLinearNop &&
scan->type != IROLinearLabel
)
{
if (IS_LINEAR_DIADIC_3(scan, EORASS, EXORASS, EANDASS)) {
(*result2)++;
if (IS_LINEAR_MONADIC(scan->u.diadic.left, EINDIRECT)) {
varnode = scan->u.diadic.left->u.monadic;
if (IS_LINEAR_DIADIC(varnode, EADD)) {
pattern->nd4 = varnode->u.diadic.left;
pattern->type = varnode->rtype;
if (IRO_IsVariable(varnode->u.diadic.left)) {
pattern->nd0 = varnode->u.diadic.right;
if (
IS_LINEAR_DIADIC(pattern->nd0, ESHL) &&
IRO_IsConstant(pattern->nd0->u.diadic.right)
)
{
pattern->val1C = pattern->nd0->u.diadic.right->u.node->data.intval;
nd1 = pattern->nd0->u.diadic.left;
} else {
return 0;
}
} else {
return 0;
}
} else {
return 0;
}
} else {
return 0;
}
pattern->nd10 = scan->u.diadic.right;
if (IS_LINEAR_MONADIC(pattern->nd10, ETYPCON)) {
if (IS_LINEAR_DIADIC(scan, EANDASS)) {
if (IS_LINEAR_MONADIC(pattern->nd10->u.monadic, EBINNOT)) {
pattern->ndC = pattern->nd10->u.monadic->u.monadic;
} else {
return 0;
}
} else {
pattern->ndC = pattern->nd10->u.monadic;
}
if (IS_LINEAR_DIADIC(pattern->ndC, ESHL) && IRO_IsConstant(pattern->ndC->u.diadic.left)) {
val = pattern->ndC->u.diadic.left->u.node->data.intval;
nd2 = pattern->ndC->u.diadic.right;
} else {
return 0;
}
} else if (IS_LINEAR_DIADIC(pattern->nd10, ESHL) && IS_LINEAR_DIADIC_2(scan, EORASS, EXORASS)) {
pattern->ndC = pattern->nd10;
if (IRO_IsConstant(pattern->ndC->u.diadic.left)) {
val = pattern->ndC->u.diadic.left->u.node->data.intval;
nd2 = pattern->ndC->u.diadic.right;
} else {
return 0;
}
} else if (IS_LINEAR_MONADIC(pattern->nd10, EBINNOT) && IS_LINEAR_DIADIC(scan, EANDASS)) {
pattern->ndC = pattern->nd10->u.monadic;
if (IS_LINEAR_DIADIC(pattern->ndC, ESHL) && IRO_IsConstant(pattern->ndC->u.diadic.left)) {
val = pattern->ndC->u.diadic.left->u.node->data.intval;
nd2 = pattern->ndC->u.diadic.right;
} else {
return 0;
}
} else {
return 0;
}
if (IS_LINEAR_DIADIC(nd2, EAND) && IS_LINEAR_DIADIC(nd1, ESHR)) {
left1 = nd1->u.diadic.left;
left2 = nd2->u.diadic.left;
obj1 = IRO_IsVariable(left1);
obj2 = IRO_IsVariable(left2);
if (obj1 == obj2 && obj1 == ind->var->object) {
right1 = nd1->u.diadic.right;
right2 = nd2->u.diadic.right;
if (IRO_IsConstant(right1) && IRO_IsConstant(right2)) {
shl = cint64_one;
shl = CInt64_Shl(shl, right1->u.node->data.intval);
shl = CInt64_Sub(shl, cint64_one);
if (CInt64_Equal(shl, right2->u.node->data.intval)) {
if (CTool_EndianReadWord32(&shl.hi) == 0) {
*unrollFactor = CInt64_GetULong(&shl) + 1;
if (CheckConstant(CInt64_Add(shl, cint64_one), val, &pattern->val14)) {
(*result1)++;
if (IS_LINEAR_DIADIC(scan, EANDASS))
pattern->val14 = CInt64_Not(pattern->val14);
}
} else {
return 0;
}
} else {
return 0;
}
} else {
return 0;
}
} else {
return 0;
}
} else {
return 0;
}
} else {
return 0;
}
}
if (scan == fnode->last)
break;
scan = scan->next;
}
}
return 1;
}
static UInt32 UnrollWhileLoop(IRONode *header, IRONode *fnode2, IRONode *fnode3, IROLoop *loop, UInt32 unrollFactor) {
IROLoopInd *ind;
IRONode *scan;
CLabel *lastlabel;
IROLinear *lastlabelnode;
IROLinear *earlyLoopExitTest;
CLabel *earlyLoopExitTestLabel;
IROLinear *origIterationCount;
IROLinear *unrolledFinalValue;
IROLinear *preAlignTemp;
IROLinear *newFinalValue;
IROLinear *savedHead60;
IROLinear *unrolledBodyEntryTest;
CLabel *label;
IROLinear *savedHead2;
IROLinear *loophead25;
IROLinear *loopend;
IROLinear *loopscan;
IROLinear *indvar;
IROLinear *less;
IROLinear *loopExitTest;
IROLinear *saveTail;
CLabel *label2;
IROLinear *gotond;
CLabel *label3;
IROLinear *savedHead3;
IROLinear *updIndInc;
IROLinear *label2nd;
IROLinear *less2;
IROLinear *saveTail2;
IROLinear *less3;
IROLinear *wtf;
IROLinear *constnd;
IROLinear *ass;
IROLinear *nd18;
IRONode *fn19;
IRONode *newfnode1;
IRONode *newfnode2;
IRONode *newfnode3;
IRONode *newfnode4;
IRONode *newfnode5;
IRONode *newfnode6;
IRONode *newfnode7;
IRONode *newfnode8;
IROLinear *lastnd;
ENode *expr;
SInt32 result1;
SInt32 result2;
LoopPattern pattern;
IROList list;
IRO_Dump("while(n--) loop \n");
if (loop->flags & LoopFlags_800) {
IRO_Dump("loop not unrolled because induction used in loop \n");
return 0;
}
if (loop->flags & LoopFlags_1000) {
IRO_Dump("loop not unrolled because loop has multiple exits \n");
return 0;
}
if (!(loop->flags & LP_HAS_MULTIPLE_INDUCTIONS))
return 0;
for (ind = FirstInd; ind; ind = ind->next) {
if ((ind->flags & LoopInd_HasMod) && (ind->flags & LoopInd_HasDiv))
break;
}
if (!ind) {
IRO_Dump("Could not find loop with and induction with MOD and DIV operation\n");
return 0;
}
if (!IRO_IsUnsignedType(ind->nd->rtype))
return 0;
if (ind->nd->type == IROLinearOp2Arg) {
if (ind->nd->nodetype == EADDASS && IRO_IsConstant(ind->nd->u.diadic.right)) {
if (ind->addConst != 1)
return 0;
} else if (ind->nd->nodetype == EASS) {
if (
ind->nd->u.diadic.right->type != IROLinearOp2Arg ||
ind->nd->u.diadic.right->nodetype != EADD ||
!IRO_IsConstant(ind->nd->u.diadic.right->u.diadic.right)
)
return 0;
if (ind->addConst != 1)
return 0;
} else {
return 0;
}
} else if (ind->nd->type == IROLinearOp1Arg && ind->nd->nodetype != EPREINC && ind->nd->nodetype != EPOSTINC) {
return 0;
}
loop->induction = ind;
loop->index24 = ind->nd->index;
loop->index20 = IRO_FindStart(ind->nd)->index;
scan = IRO_FirstNode;
memset(&pattern, 0, sizeof(pattern));
while (scan) {
if (Bv_IsBitSet(scan->index, InLoop) && scan != header) {
if (!PatternMatchLoop(scan, loop, ind, &unrollFactor, &result1, &result2, &pattern))
return 0;
}
scan = scan->nextnode;
}
if (result1 > 1 || result2 > 1)
return 0;
lastlabel = fnode2->last->u.label.label;
lastlabelnode = IRO_FindLabelNode(fnode2->last->u.label.label, fnode2->last);
IRO_InitList(&list);
IRO_DuplicateExprRange(lastlabelnode->next, LoopNode->last->u.label.x4->u.diadic.left, &list);
IRO_DuplicateExpr(LoopNode->last->u.label.x4, &list);
IRO_Paste(list.head, list.tail, fnode2->last);
lastlabelnode = list.tail;
IRO_InitList(&list);
earlyLoopExitTest = BuildEarlyLoopExitTest(LoopNode->last->type, &list);
earlyLoopExitTestLabel = IRO_NewLabel();
earlyLoopExitTest->u.label.label = earlyLoopExitTestLabel;
earlyLoopExitTest->u.label.x4 = lastlabelnode;
earlyLoopExitTest->u.label.x4->flags |= IROLF_Reffed;
earlyLoopExitTest->rtype = LoopNode->last->rtype;
IRO_Paste(list.head, list.tail, fnode2->last);
IRO_InitList(&list);
origIterationCount = BuildOrigIterationCount_DoWhile(&list, loop);
IRO_Paste(list.head, list.tail, fnode2->last);
savedHead60 = list.head;
IRO_InitList(&list);
preAlignTemp = BuildPreAlignTemp(ind, unrollFactor, &list);
IRO_Paste(list.head, list.tail, fnode2->last);
IRO_InitList(&list);
unrolledFinalValue = BuildUnrolledFinalvalue_DoWhile(origIterationCount, unrollFactor, &list, loop);
IRO_Paste(list.head, list.tail, fnode2->last);
IRO_InitList(&list);
newFinalValue = BuildNewFinalvalue_DoWhile(origIterationCount, unrollFactor, &list, loop);
IRO_Paste(list.head, list.tail, fnode2->last);
IRO_InitList(&list);
BuildUnrolledBodyEntryTest(&list, origIterationCount, unrollFactor, lastlabel);
IRO_Paste(list.head, list.tail, fnode2->last);
unrolledBodyEntryTest = list.tail;
IRO_InitList(&list);
label = BuildLabel(&list);
IRO_Paste(list.head, list.tail, fnode2->last);
savedHead2 = list.head;
loophead25 = NULL;
for (scan = fnode3; scan && scan != header; scan = scan->nextnode) {
IRO_InitList(&list);
loopend = scan->last;
loopscan = scan->first;
while (1) {
if (loopscan->stmt)
loopscan->stmt->flags |= StmtFlag_10;
if (loopscan->type != IROLinearLabel && !(loopscan->flags & IROLF_Reffed)) {
IRO_DuplicateExpr(loopscan, &list);
if (!loophead25)
loophead25 = list.head;
}
if (loopscan == loopend)
break;
loopscan = loopscan->next;
}
if (list.head && list.tail)
IRO_Paste(list.head, list.tail, fnode2->last);
}
IRO_InitList(&list);
if (ind->nd->type == IROLinearOp1Arg)
IRO_DuplicateExpr(ind->nd->u.monadic, &list);
else
IRO_DuplicateExpr(ind->nd->u.diadic.left, &list);
list.tail->flags &= ~IROLF_Assigned;
indvar = list.tail;
IRO_DuplicateExpr(preAlignTemp, &list);
list.tail->flags &= ~IROLF_Assigned;
less = IRO_NewLinear(IROLinearOp2Arg);
less->nodetype = ELESS;
less->rtype = TYPE(&stbool);
less->index = ++IRO_NumLinear;
less->next = NULL;
less->u.diadic.left = indvar;
less->u.diadic.right = list.tail;
IRO_AddToList(less, &list);
less->flags |= IROLF_Reffed;
loopExitTest = BuildLoopExitTest(LoopNode->last->type, &list);
loopExitTest->u.label.label = label;
loopExitTest->u.label.x4 = less;
loopExitTest->u.label.x4->flags |= IROLF_Reffed;
loopExitTest->rtype = LoopNode->last->rtype;
IRO_Paste(list.head, list.tail, fnode2->last);
saveTail = list.tail;
IRO_InitList(&list);
label2 = IRO_NewLabel();
gotond = IRO_NewLinear(IROLinearOp1Arg);
gotond->index = ++IRO_NumLinear;
gotond->type = IROLinearGoto;
gotond->u.label.label = label2;
IRO_AddToList(gotond, &list);
IRO_Paste(list.head, list.tail, fnode2->last);
IRO_InitList(&list);
label3 = BuildLabel(&list);
IRO_Paste(list.head, list.tail, fnode2->last);
savedHead3 = list.head;
UnrollWhileLoopBody(header, fnode2, fnode3, loop, &pattern, unrollFactor);
updIndInc = UpdateInductionIncrement(loop, 8 * unrollFactor, fnode2->last);
IRO_InitList(&list);
label2nd = IRO_NewLinear(IROLinearLabel);
label2nd->index = IRO_NumLinear++;
label2nd->u.label.label = label2;
label2nd->flags |= IROLF_1;
IRO_AddToList(label2nd, &list);
IRO_Paste(list.head, list.tail, fnode2->last);
IRO_InitList(&list);
if (ind->nd->type == IROLinearOp1Arg)
IRO_DuplicateExpr(ind->nd->u.monadic, &list);
else
IRO_DuplicateExpr(ind->nd->u.diadic.left, &list);
list.tail->flags &= ~IROLF_Assigned;
indvar = list.tail;
IRO_DuplicateExpr(unrolledFinalValue, &list);
list.tail->flags &= ~IROLF_Assigned;
less2 = IRO_NewLinear(IROLinearOp2Arg);
less2->nodetype = ELESS;
less2->rtype = TYPE(&stbool);
less2->index = ++IRO_NumLinear;
less2->next = NULL;
less2->u.diadic.left = indvar;
less2->u.diadic.right = list.tail;
IRO_AddToList(less2, &list);
less2->flags |= IROLF_Reffed;
loopExitTest = BuildLoopExitTest(LoopNode->last->type, &list);
loopExitTest->u.label.label = label3;
loopExitTest->u.label.x4 = less2;
loopExitTest->u.label.x4->flags |= IROLF_Reffed;
loopExitTest->rtype = LoopNode->last->rtype;
IRO_Paste(list.head, list.tail, fnode2->last);
saveTail2 = list.tail;
IRO_InitList(&list);
if (ind->nd->type == IROLinearOp1Arg)
IRO_DuplicateExpr(ind->nd->u.monadic, &list);
else
IRO_DuplicateExpr(ind->nd->u.diadic.left, &list);
list.tail->flags &= ~IROLF_Assigned;
indvar = list.tail;
IRO_DuplicateExpr(newFinalValue, &list);
list.tail->flags &= ~IROLF_Assigned;
less3 = IRO_NewLinear(IROLinearOp2Arg);
less3->nodetype = ELESS;
less3->rtype = TYPE(&stbool);
less3->index = ++IRO_NumLinear;
less3->next = NULL;
less3->u.diadic.left = indvar;
less3->u.diadic.right = list.tail;
IRO_AddToList(less3, &list);
less3->flags |= IROLF_Reffed;
wtf = LoopNode->last->u.label.x4;
IRO_Paste(list.head, list.tail, LoopNode->last);
LoopNode->last->u.label.x4 = list.tail;
IRO_InitList(&list);
constnd = IRO_NewLinear(IROLinearOperand);
constnd->index = ++IRO_NumLinear;
expr = IRO_NewENode(EINTCONST);
expr->rtype = wtf->u.diadic.left->rtype;
expr->data.intval = cint64_zero;
constnd->u.node = expr;
constnd->rtype = expr->rtype;
IRO_AddToList(constnd, &list);
constnd->flags |= IROLF_Reffed;
IRO_DuplicateExpr(wtf->u.diadic.left, &list);
ass = IRO_NewLinear(IROLinearOp2Arg);
ass->nodetype = EASS;
ass->rtype = list.tail->rtype;
ass->index = ++IRO_NumLinear;
ass->next = NULL;
ass->u.diadic.left = list.tail;
ass->u.diadic.right = constnd;
IRO_AddToList(ass, &list);
ass->flags |= IROLF_Assigned;
IRO_NopOut(wtf);
fn19 = fnode2->nextnode;
nd18 = fnode2->last;
fnode2->last = earlyLoopExitTest;
newfnode1 = IRO_NewFlowGraphNode();
newfnode1->first = savedHead60;
newfnode1->last = unrolledBodyEntryTest;
fnode2->nextnode = newfnode1;
newfnode2 = IRO_NewFlowGraphNode();
newfnode2->first = savedHead2;
newfnode2->last = saveTail;
savedHead2->u.label.label->stmt = (Statement *) newfnode2;
newfnode1->nextnode = newfnode2;
newfnode3 = IRO_NewFlowGraphNode();
newfnode3->first = gotond;
newfnode3->last = gotond;
newfnode2->nextnode = newfnode3;
newfnode4 = IRO_NewFlowGraphNode();
newfnode4->first = savedHead3;
newfnode4->last = updIndInc;
savedHead3->u.label.label->stmt = (Statement *) newfnode4;
newfnode3->nextnode = newfnode4;
newfnode5 = IRO_NewFlowGraphNode();
newfnode5->first = label2nd;
newfnode5->last = saveTail2;
label2nd->u.label.label->stmt = (Statement *) newfnode5;
newfnode4->nextnode = newfnode5;
newfnode6 = IRO_NewFlowGraphNode();
newfnode6->first = nd18;
newfnode6->last = nd18;
newfnode5->nextnode = newfnode6;
newfnode6->nextnode = fn19;
newfnode7 = oalloc(sizeof(IRONode));
memset(newfnode7, 0, sizeof(IRONode));
newfnode7->index = IRO_NumNodes;
IRO_NumNodes++;
newfnode7->first = list.head;
newfnode7->last = list.tail;
list.tail->next = LoopNode->last->next;
LoopNode->last->next = list.head;
newfnode7->nextnode = LoopNode->nextnode;
LoopNode->nextnode = newfnode7;
newfnode8 = oalloc(sizeof(IRONode));
memset(newfnode8, 0, sizeof(IRONode));
newfnode8->index = IRO_NumNodes;
IRO_NumNodes++;
lastnd = IRO_NewLinear(IROLinearLabel);
lastnd->index = IRO_NumLinear++;
lastnd->next = NULL;
lastnd->u.label.label = earlyLoopExitTestLabel;
lastnd->flags |= IROLF_1;
earlyLoopExitTestLabel->stmt = (Statement *) newfnode8;
newfnode8->first = lastnd;
newfnode8->last = lastnd;
lastnd->next = newfnode7->last->next;
newfnode7->last->next = lastnd;
newfnode8->nextnode = newfnode7->nextnode;
newfnode7->nextnode = newfnode8;
return 1;
}
void IRO_IterateForLoopBody(IRONode *start, IRONode *end, IROLoop *loop, IROLinear *destnode, SInt32 addConst, CInt64 *val, Boolean funkyFlag) {
IROLinear *first = NULL;
IROLinear *last = NULL;
IRONode *fnode;
IROLinear *lastnd;
IROLinear *nd;
IROList list;
for (fnode = start; fnode && fnode != end; fnode = fnode->nextnode) {
IRO_InitList(&list);
lastnd = fnode->last;
nd = fnode->first;
while (1) {
if (nd->stmt)
nd->stmt->flags |= StmtFlag_10;
if (
(nd->index < loop->index20 || nd->index > loop->index24) &&
nd->type != IROLinearLabel &&
!(nd->flags & IROLF_Reffed)
)
{
IRO_DuplicateExpr(nd, &list);
if (!first)
first = list.head;
last = list.tail;
}
if (nd == lastnd)
break;
nd = nd->next;
}
if (list.head && list.tail)
IRO_Paste(list.head, list.tail, destnode);
}
if (funkyFlag) {
*val = CInt64_Add(*val, IRO_MakeLong(loop->induction->addConst));
ChangeInductionReference(first, last, *val, loop);
}
}
void IRO_LinearizeForLoopPostLoop(IRONode *fnode1, IRONode *fnode2, IROLoop *loop, IRONode *fnode3, UInt32 unrollFactor) {
IRONode *newfnode;
IROLinear *newnd;
SInt32 i;
CInt64 val;
newfnode = oalloc(sizeof(IRONode));
memset(newfnode, 0, sizeof(IRONode));
newfnode->index = IRO_NumNodes;
IRO_NumNodes++;
newnd = IRO_NewLinear(IROLinearNop);
newnd->index = IRO_NumLinear++;
newnd->next = NULL;
newnd->flags |= IROLF_1;
newfnode->first = newfnode->last = newnd;
newfnode->nextnode = fnode3->nextnode;
fnode3->nextnode = newfnode;
newnd->next = fnode3->last->next;
fnode3->last->next = newnd;
val = cint64_zero;
for (i = 0; i < unrollFactor; i++)
IRO_IterateForLoopBody(fnode2, fnode1, loop, newfnode->last, loop->induction->addConst, &val, i > 0);
UpdateInductionIncrement(loop, unrollFactor, newfnode->last);
}
static UInt32 UnrollForLoop(IRONode *header, IRONode *fnode2, IRONode *fnode3, IROLoop *loop, UInt32 unrollFactor) {
IROLinear *lastlabelnode;
IROLinear *earlyLoopExitTest;
IROLinear *origIterationCount;
IROLinear *saveHead1;
IROLinear *newFinalValue;
IROLinear *unrolledBodyEntryTest;
IROLinear *gotoNd;
IROLinear *saveHead2;
IROLinear *updIndInc;
IROLinear *labelNd;
IROLinear *saveTail2;
IROLinear *ndCopy;
IROLinear *saveTail3;
IROLinear *loopExitTest;
IROLinear *lastnd;
IROLinear *labelNd2;
IROLinear *saveTail4;
IROLinear *labelNd3;
IROLinear *scan;
IRONode *nd18;
IRONode *newfnode1;
IRONode *newfnode2;
IRONode *newfnode3;
IRONode *newfnode4;
IRONode *newfnode5;
IRONode *newfnode6;
CLabel *lastlabel;
CLabel *earlyLoopExitTestLabel;
CLabel *label;
CLabel *label2;
SInt32 i;
IROList list;
CInt64 iterCount;
int isConstant;
UInt32 needOrigLoop = 0;
UInt32 needUnrollBodyTest = 0;
UInt32 resetUnrolledFinalValue = 0;
SInt32 leftOver;
CInt64 val;
lastlabelnode = IRO_FindLabelNode(fnode2->last->u.label.label, fnode2->last);
lastlabel = IRO_NewLabel();
IRO_InitList(&list);
IRO_DuplicateExprRange(lastlabelnode->next, LoopNode->last->u.label.x4, &list);
IRO_DuplicateExpr(LoopNode->last->u.label.x4, &list);
IRO_Paste(list.head, list.tail, fnode2->last);
lastlabelnode = list.tail;
IRO_InitList(&list);
earlyLoopExitTest = BuildEarlyLoopExitTest(LoopNode->last->type, &list);
earlyLoopExitTestLabel = IRO_NewLabel();
earlyLoopExitTest->u.label.label = earlyLoopExitTestLabel;
earlyLoopExitTest->u.label.x4 = lastlabelnode;
earlyLoopExitTest->u.label.x4->flags |= IROLF_Reffed;
earlyLoopExitTest->rtype = LoopNode->last->rtype;
IRO_Paste(list.head, list.tail, fnode2->last);
isConstant = IsIterationCountConstant(loop, &iterCount);
needOrigLoop = 1;
needUnrollBodyTest = 1;
resetUnrolledFinalValue = 0;
if (isConstant)
IRO_TestConstantIterationCount(loop, &iterCount, 1, &unrollFactor, &leftOver, &needOrigLoop, &needUnrollBodyTest, &resetUnrolledFinalValue);
IRO_InitList(&list);
origIterationCount = BuildOrigIterationCount(&list, loop);
IRO_Paste(list.head, list.tail, fnode2->last);
saveHead1 = list.head;
IRO_InitList(&list);
newFinalValue = BuildNewFinalvalue(origIterationCount, unrollFactor, &list, loop);
IRO_Paste(list.head, list.tail, fnode2->last);
IRO_InitList(&list);
BuildUnrolledBodyEntryTest(&list, origIterationCount, unrollFactor, lastlabel);
IRO_Paste(list.head, list.tail, fnode2->last);
unrolledBodyEntryTest = list.tail;
label = IRO_NewLabel();
IRO_InitList(&list);
gotoNd = IRO_NewLinear(IROLinearOp1Arg);
gotoNd->index = ++IRO_NumLinear;
gotoNd->type = IROLinearGoto;
gotoNd->u.label.label = label;
IRO_AddToList(gotoNd, &list);
IRO_Paste(list.head, list.tail, fnode2->last);
IRO_InitList(&list);
label2 = BuildLabel(&list);
IRO_Paste(list.head, list.tail, fnode2->last);
saveHead2 = list.head;
val = cint64_zero;
for (i = 0; i < unrollFactor; i++)
IRO_IterateForLoopBody(fnode3, header, loop, fnode2->last, loop->induction->addConst, &val, i > 0);
updIndInc = UpdateInductionIncrement(loop, unrollFactor, fnode2->last);
IRO_InitList(&list);
labelNd = IRO_NewLinear(IROLinearLabel);
labelNd->index = IRO_NumLinear++;
labelNd->u.label.label = label;
labelNd->flags |= IROLF_1;
IRO_AddToList(labelNd, &list);
IRO_Paste(list.head, list.tail, fnode2->last);
IRO_InitList(&list);
IRO_DuplicateExpr(LoopNode->last->u.label.x4->u.diadic.left, &list);
saveTail2 = list.tail;
if (resetUnrolledFinalValue)
IRO_DuplicateExpr(loop->nd18->u.diadic.right, &list);
else
IRO_DuplicateExpr(newFinalValue, &list);
ndCopy = IRO_NewLinear(LoopNode->last->u.label.x4->type);
*ndCopy = *LoopNode->last->u.label.x4;
ndCopy->index = ++IRO_NumLinear;
ndCopy->next = NULL;
ndCopy->expr = NULL;
ndCopy->u.diadic.left = saveTail2;
ndCopy->u.diadic.right = list.tail;
IRO_AddToList(ndCopy, &list);
IRO_Paste(list.head, list.tail, fnode2->last);
saveTail3 = list.tail;
IRO_InitList(&list);
loopExitTest = BuildLoopExitTest(LoopNode->last->type, &list);
loopExitTest->u.label.label = label2;
loopExitTest->u.label.x4 = saveTail3;
loopExitTest->u.label.x4->flags |= IROLF_Reffed;
loopExitTest->rtype = LoopNode->last->rtype;
IRO_Paste(list.head, list.tail, fnode2->last);
saveTail4 = list.tail;
IRO_InitList(&list);
labelNd2 = IRO_NewLinear(IROLinearLabel);
labelNd2->index = IRO_NumLinear++;
labelNd2->u.label.label = lastlabel;
labelNd2->flags |= IROLF_1;
IRO_AddToList(labelNd2, &list);
IRO_Paste(list.head, list.tail, fnode2->last);
lastnd = fnode2->last;
nd18 = fnode2->nextnode;
fnode2->last = earlyLoopExitTest;
newfnode1 = IRO_NewFlowGraphNode();
newfnode1->first = saveHead1;
newfnode1->last = unrolledBodyEntryTest;
fnode2->nextnode = newfnode1;
newfnode2 = IRO_NewFlowGraphNode();
newfnode2->first = gotoNd;
newfnode2->last = gotoNd;
newfnode1->nextnode = newfnode2;
newfnode3 = IRO_NewFlowGraphNode();
newfnode3->first = saveHead2;
newfnode3->last = updIndInc;
saveHead2->u.label.label->stmt = (Statement *) newfnode3;
if (newfnode2)
newfnode2->nextnode = newfnode3;
else
newfnode1->nextnode = newfnode3;
newfnode4 = IRO_NewFlowGraphNode();
newfnode4->first = labelNd;
newfnode4->last = saveTail4;
labelNd->u.label.label->stmt = (Statement *) newfnode4;
newfnode3->nextnode = newfnode4;
newfnode5 = IRO_NewFlowGraphNode();
newfnode5->first = labelNd2;
newfnode5->last = lastnd;
newfnode4->nextnode = newfnode5;
newfnode5->nextnode = nd18;
newfnode6 = oalloc(sizeof(IRONode));
memset(newfnode6, 0, sizeof(IRONode));
newfnode6->index = IRO_NumNodes;
IRO_NumNodes++;
labelNd3 = IRO_NewLinear(IROLinearLabel);
labelNd3->index = IRO_NumLinear++;
labelNd3->next = NULL;
labelNd3->u.label.label = earlyLoopExitTestLabel;
labelNd3->flags |= IROLF_1;
earlyLoopExitTestLabel->stmt = (Statement *) newfnode6;
newfnode6->first = labelNd3;
newfnode6->last = labelNd3;
labelNd3->next = LoopNode->last->next;
LoopNode->last->next = labelNd3;
newfnode6->nextnode = LoopNode->nextnode;
LoopNode->nextnode = newfnode6;
if (!needOrigLoop) {
NoOpBlock(newfnode5);
NoOpBlock(header);
NoOpBlock(fnode3);
NoOpBlock(loop->induction->fnode);
IRO_NopOut(newfnode1->last->u.label.x4);
newfnode1->last->type = IROLinearNop;
}
if (!needUnrollBodyTest) {
IRO_NopOut(earlyLoopExitTest->u.label.x4);
earlyLoopExitTest->type = IROLinearNop;
IRO_NopOut(newfnode4->last->u.label.x4);
newfnode4->last->type = IROLinearNop;
if (newfnode2)
newfnode2->last->type = IROLinearNop;
for (scan = newfnode1->first; scan; scan = scan->next) {
if (!(scan->flags & IROLF_Reffed))
IRO_NopOut(scan);
if (scan == newfnode1->last)
break;
}
}
return 1;
}
static UInt32 UnrollStandardLoop(IRONode *header, IRONode *fnode2, IRONode *fnode3, int count) {
IROLoop *loop;
ConditionalHeaderAtBottom = 1;
loop = ExtractLoopInfo(header);
loop->xC = fnode2;
loop->x10 = fnode3;
FindAssignmenttoInductionVar(loop, fnode2);
if (!IsLoopUnrollable(loop)) {
IRO_Dump("LoopUnroll:loop with header %d not unrolled because IsLoopUnrollable failed\n", header->index);
return 0;
}
if (loop->flags & LoopFlags_10000)
return UnrollWhileLoop(header, fnode2, fnode3, loop, count);
else
return UnrollForLoop(header, fnode2, fnode3, loop, count);
}
static void LoopUnroll(int count, IRONode *header) {
VarRecord *var;
IRONode *tmp;
UInt16 i;
UInt16 j;
IRONode *prevpred;
IRONode *prevsucc;
int foundpred;
UInt32 predcount;
UInt32 success = 0;
LoopNode = header;
FindMustReach();
for (var = IRO_FirstVar; var; var = var->next)
var->xA = 1;
ComputeLoopKills();
ComputeLoopInvariance();
ComputeLoopInduction();
LoopNode = header;
ConditionalHeaderAtBottom = 0;
prevpred = NULL;
foundpred = 0;
for (i = 0; i < LoopNode->numpred; i++) {
tmp = IRO_NodeTable[LoopNode->pred[i]];
if (!Bv_IsBitSet(tmp->index, InLoop)) {
foundpred = 1;
if (tmp->nextnode == header) {
CError_ASSERT(2101, !prevpred || tmp == prevpred);
prevpred = tmp;
}
}
}
if (!foundpred) {
IRO_Dump("No predecessor outside the loop\n");
return;
}
if (LoopNode->last->type == IROLinearIf || LoopNode->last->type == IROLinearIfNot) {
if (LoopNode->nextnode && !Bv_IsBitSet(LoopNode->nextnode->index, InLoop)) {
prevsucc = NULL;
for (i = 0; i < LoopNode->numsucc; i++) {
tmp = IRO_NodeTable[LoopNode->succ[i]];
if (Bv_IsBitSet(tmp->index, InLoop)) {
CError_ASSERT(2159, !prevsucc);
prevsucc = tmp;
}
}
prevpred = NULL;
predcount = 0;
for (j = 0; j < LoopNode->numpred; j++) {
tmp = IRO_NodeTable[LoopNode->pred[j]];
if (!Bv_IsBitSet(tmp->index, InLoop)) {
prevpred = tmp;
predcount++;
}
}
if (
predcount == 1 &&
prevpred->last->type == IROLinearGoto &&
prevpred->nextnode == prevsucc &&
prevsucc != LoopNode
)
{
success = UnrollStandardLoop(header, prevpred, prevsucc, count);
}
}
} else {
IRO_Dump(" LoopUnroll:Loop with header = %d is not a conditional loop\n", header->index);
}
if (!success)
return;
IRO_NodeTable = oalloc(sizeof(IRONode *) * IRO_NumNodes);
memset(IRO_NodeTable, 0, sizeof(IRONode *) * IRO_NumNodes);
for (tmp = IRO_FirstNode; tmp; tmp = tmp->nextnode)
IRO_NodeTable[tmp->index] = tmp;
IRO_ComputeSuccPred();
IRO_ComputeDom();
if (success)
IRO_Dump(" LoopUnroll:Loop with header = %d Unrolled\n", header->index);
}
static int IsLoopUnrollable(IROLoop *loop) {
CInt64 tmp;
if (loop->flags & LP_LOOP_HAS_ASM) {
IRO_Dump("IsLoopUnrollable:No due to LP_LOOP_HAS_ASM \n");
return 0;
}
if (loop->flags & LP_IFEXPR_NON_CANONICAL) {
IRO_Dump("IsLoopUnrollable:No due to LP_IFEXPR_NON_CANONICAL \n");
return 0;
}
if (loop->flags & LP_LOOP_HAS_CALLS) {
IRO_Dump("IsLoopUnrollable:No due to LP_LOOP_HAS_CALLS \n");
return 0;
}
if (loop->flags & LP_LOOP_HAS_CNTRLFLOW) {
IRO_Dump("IsLoopUnrollable:No due to LP_LOOP_HAS_CNTRLFLOW \n");
return 0;
}
if (loop->flags & LP_INDUCTION_NOT_FOUND) {
IRO_Dump("IsLoopUnrollable:No due to LP_INDUCTION_NOT_FOUND \n");
return 0;
}
if (loop->flags & LP_LOOP_HDR_HAS_SIDEEFFECTS) {
IRO_Dump("IsLoopUnrollable:No due to LP_LOOP_HDR_HAS_SIDEEFFECTS \n");
return 0;
}
if (!(loop->flags & LoopFlags_200)) {
IRO_Dump("IsLoopUnrollable:No because header does not follow induction update \n");
return 0;
}
if (!(loop->flags & LoopFlags_10000)) {
IROLinear *upperBound = loop->nd18->u.diadic.right;
if (!IRO_IsIntConstant(upperBound) && !(upperBound->flags & IROLF_LoopInvariant)) {
IRO_Dump("IsLoopUnrollable:No because Loop Upper Bound is Variant in the loop\n");
return 0;
}
if (!loop->nd14) {
IRO_Dump("IsLoopUnrollable:No because there is no initialization of loop index in PreHeader\n");
return 0;
}
if (!IRO_IsVariable(loop->nd14->u.diadic.left)) {
IRO_Dump("IsLoopUnrollable: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("IsLoopUnrollable:No because initial value of induction is signed but init < 0\n");
return 0;
}
} else if (IsIterationCountConstant(loop, &tmp)) {
IRO_Dump("IsLoopUnrollable:Yes, the limits substract out to be constants\n");
} else {
IRO_Dump("IsLoopUnrollable:No because initial value of induction is signed and not constant\n");
return 0;
}
}
if (!(loop->flags & LP_LOOP_STEP_ISADD)) {
IRO_Dump("IsLoopUnrollable:No because LP_LOOP_STEP_ISADD is not set i.e induciton is not updated by 1\n");
return 0;
}
} else {
if (!IRO_IsUnsignedType(loop->nd18->u.diadic.left->rtype)) {
IRO_Dump("IsLoopUnrollable:No because the while loop induction is signed\n");
return 0;
}
if (!(loop->flags & LoopFlags_2000)) {
IRO_Dump("IsLoopUnrollable:No because the while loop operator is not of decrement form\n");
return 0;
}
}
if (loop->sizeBySomeMeasurement > copts.loop_unroll_size_threshold) {
IRO_Dump("IsLoopUnrollable:No because loop size greater than threshold\n");
return 0;
}
return 1;
}
IROLinear *BuildEarlyLoopExitTest(IROLinearType type, IROList *list) {
IROLinear *nd = IRO_NewLinear(IROLinearOp1Arg);
nd->index = ++IRO_NumLinear;
if (type == IROLinearIf)
nd->type = IROLinearIfNot;
else
nd->type = IROLinearIf;
IRO_AddToList(nd, list);
return nd;
}
IROLinear *BuildLoopExitTest(IROLinearType type, IROList *list) {
IROLinear *nd = IRO_NewLinear(IROLinearOp1Arg);
nd->index = ++IRO_NumLinear;
nd->type = type;
IRO_AddToList(nd, list);
return nd;
}
int IsIterationCountConstant(IROLoop *loop, CInt64 *pval) {
IROLinear *lowerBound;
IROLinear *upperBound;
Type *type;
int isUnsigned;
IROAddrRecord *lowerRec;
IROAddrRecord *upperRec;
CInt64 lowerval;
CInt64 upperval;
CInt64 incval;
CInt64 negOne;
lowerBound = loop->nd14->u.diadic.right;
if (loop->flags & LoopFlags_1) {
upperBound = loop->nd18->u.diadic.right;
type = loop->nd18->u.diadic.right->rtype;
} else {
upperBound = loop->nd18->u.diadic.left;
type = loop->nd18->u.diadic.left->rtype;
}
isUnsigned = IRO_IsUnsignedType(type);
if (IRO_IsIntConstant(lowerBound) && IRO_IsIntConstant(upperBound)) {
lowerval = lowerBound->u.node->data.intval;
upperval = upperBound->u.node->data.intval;
if (isUnsigned) {
if (CInt64_LessEqualU(upperval, lowerval))
return 0;
} else {
if (CInt64_LessEqual(upperval, lowerval))
return 0;
}
CInt64_SetLong(&incval, loop->induction->addConst);
CInt64_SetLong(&negOne, -1);
*pval = CInt64_Sub(upperval, lowerval);
*pval = CInt64_Add(*pval, incval);
if (IS_LINEAR_DIADIC(loop->nd18, ELESS))
*pval = CInt64_Add(*pval, negOne);
CError_ASSERT(2486, !CInt64_IsZero(&incval));
if (isUnsigned)
*pval = CInt64_DivU(*pval, incval);
else
*pval = CInt64_Div(*pval, incval);
if (CInt64_Equal(*pval, cint64_zero))
return 0;
if (isUnsigned) {
CError_ASSERT(2508, !CInt64_LessEqualU(*pval, cint64_zero));
} else {
CError_ASSERT(2517, !CInt64_LessEqual(*pval, cint64_zero));
}
return 1;
}
lowerRec = IRO_InitAddrRecordPointer(lowerBound);
upperRec = IRO_InitAddrRecordPointer(upperBound);
if (IS_LINEAR_DIADIC(lowerBound, EADD)) {
IRO_DecomposeAddressExpression(lowerBound, lowerRec);
} else if (IRO_IsIntConstant(lowerBound)) {
lowerRec->numInts++;
IRO_AddElmToList(lowerBound, &lowerRec->ints);
lowerRec->numObjRefs = 0;
lowerRec->numMisc = 0;
} else {
lowerRec->numMisc++;
IRO_AddElmToList(lowerBound, &lowerRec->misc);
lowerRec->numObjRefs = 0;
lowerRec->numInts = 0;
}
if (IS_LINEAR_DIADIC(upperBound, EADD)) {
IRO_DecomposeAddressExpression(upperBound, upperRec);
} else if (IRO_IsIntConstant(upperBound)) {
upperRec->numInts++;
IRO_AddElmToList(upperBound, &upperRec->ints);
upperRec->numObjRefs = 0;
upperRec->numMisc = 0;
} else {
upperRec->numMisc++;
IRO_AddElmToList(upperBound, &upperRec->misc);
upperRec->numObjRefs = 0;
upperRec->numInts = 0;
}
if (IsDifferenceOfTermsConstant(lowerRec, upperRec, isUnsigned, pval)) {
if (IS_LINEAR_DIADIC(loop->nd18, ELESSEQU))
*pval = CInt64_Add(*pval, cint64_one);
return 1;
}
return 0;
}
static int IsDifferenceOfTermsConstant(IROAddrRecord *lowerRec, IROAddrRecord *upperRec, int isUnsigned, CInt64 *pval) {
UInt32 i;
CInt64 upperval;
CInt64 lowerval;
IROElmList *el;
IROLinear *nd;
if (upperRec->numObjRefs == lowerRec->numObjRefs && upperRec->numObjRefs != 0)
return 0;
else if (upperRec->numObjRefs != lowerRec->numObjRefs)
return 0;
if (upperRec->numMisc == lowerRec->numMisc && upperRec->numMisc != 0) {
for (i = 0; i < upperRec->numMisc; i++) {
// bug? surely this should index on i...?
if (!IRO_ExprsSame(lowerRec->misc->element, upperRec->misc->element))
return 0;
}
} else if (upperRec->numMisc != lowerRec->numMisc) {
return 0;
}
upperval = cint64_zero;
for (el = upperRec->ints; el; el = el->next) {
nd = el->element;
upperval = CMach_CalcIntDiadic(nd->rtype, upperval, '+', nd->u.node->data.intval);
}
lowerval = cint64_zero;
for (el = lowerRec->ints; el; el = el->next) {
nd = el->element;
lowerval = CMach_CalcIntDiadic(nd->rtype, lowerval, '+', nd->u.node->data.intval);
}
if (CInt64_Equal(upperval, lowerval))
return 0;
if (CInt64_Greater(upperval, lowerval)) {
*pval = CInt64_Sub(upperval, lowerval);
return 1;
} else {
return 0;
}
}
void NoOpBlock(IRONode *fnode) {
IROLinear *last, *scan;
for (scan = fnode->first, last = fnode->last; scan; scan = scan->next) {
scan->type = IROLinearNop;
if (scan == last)
break;
}
}
void IRO_TestConstantIterationCount(IROLoop *loop, CInt64 *iterCount, SInt32 vectorStride, UInt32 *unrollFactor, SInt32 *leftOver, UInt32 *needOrigLoop, UInt32 *needUnrollBodyTest, UInt32 *resetUnrolledFinalValue) {
UInt32 isUnsigned;
CInt64 val;
CInt64 val3;
CInt64 mod;
CInt64 val2;
CInt64 loopvar3;
CInt64 loopvar1;
CInt64 loopvar2;
CInt64 strideVal;
CError_ASSERT(2737, *unrollFactor);
isUnsigned = IRO_IsUnsignedType(
(loop->flags & LoopFlags_1) ? loop->nd18->u.diadic.right->rtype :loop->nd18->u.diadic.left->rtype);
CError_ASSERT(2756, vectorStride);
strideVal = IRO_MakeLong(vectorStride);
if (isUnsigned ? CInt64_LessU(*iterCount, strideVal) : CInt64_Less(*iterCount, strideVal)) {
*needOrigLoop = 1;
*needUnrollBodyTest = 0;
*unrollFactor = 0;
*leftOver = CInt64_GetULong(iterCount);
} else {
switch (vectorStride) {
case 1:
val = *iterCount;
break;
case 2:
val = CInt64_ShrU(*iterCount, cint64_one);
break;
case 4:
val = CInt64_ShrU(*iterCount, IRO_MakeLong(2));
break;
case 8:
val = CInt64_ShrU(*iterCount, IRO_MakeLong(3));
break;
case 16:
val = CInt64_ShrU(*iterCount, IRO_MakeLong(4));
break;
default:
val = CInt64_Div(*iterCount, strideVal);
}
if (CInt64_LessU(val, IRO_MakeLong(*unrollFactor)))
*unrollFactor = CInt64_GetULong(&val);
CInt64_SetLong(&val2, *unrollFactor);
switch (vectorStride) {
case 1:
val3 = cint64_zero;
break;
case 2:
val3 = CInt64_And(*iterCount, cint64_one);
break;
case 4:
val3 = CInt64_And(*iterCount, IRO_MakeLong(3));
break;
case 8:
val3 = CInt64_And(*iterCount, IRO_MakeLong(7));
break;
case 16:
val3 = CInt64_And(*iterCount, IRO_MakeLong(15));
break;
default:
val3 = CInt64_Mod(*iterCount, strideVal);
}
if (CInt64_LessEqualU(val, IRO_MakeLong(8))) {
*needUnrollBodyTest = vectorStride > 1;
*unrollFactor = CInt64_GetULong(&val);
*leftOver = CInt64_GetULong(&val3);
*needOrigLoop = *leftOver != 0;
*resetUnrolledFinalValue = !(*needOrigLoop && *needUnrollBodyTest);
} else {
loopvar1 = IRO_MakeLong(0x7FFFFFFF);
loopvar2 = IRO_MakeLong(0x7FFFFFFF);
do {
mod = CInt64_Mod(val, val2);
loopvar3 = CInt64_Add(CInt64_Mul(mod, strideVal), val3);
if (CInt64_Less(loopvar3, loopvar2)) {
loopvar2 = loopvar3;
loopvar1 = val2;
}
if (vectorStride > 1)
break;
val2 = CInt64_Add(val2, cint64_negone);
} while (CInt64_GreaterEqualU(CInt64_Mul(val2, val2), val));
*unrollFactor = CInt64_GetULong(&loopvar1);
*leftOver = CInt64_GetULong(&loopvar2);
*needOrigLoop = *leftOver != 0;
*needUnrollBodyTest = CInt64_Less(loopvar1, val) || vectorStride > 1;
*resetUnrolledFinalValue = !(*needOrigLoop && *needUnrollBodyTest);
}
}
IRO_Dump(
"---- IterCount = %d, VectorStride = %d, UnrollFactor = %d, LeftOver = %d,\n"
"\tNeedOrigLoop = %d, NeedUnrollBodyTest = %d, ResetUnrolledFinalValue = %d\n",
CInt64_GetULong(iterCount), vectorStride, *unrollFactor, *leftOver,
*needOrigLoop, *needUnrollBodyTest, *resetUnrolledFinalValue
);
}
IROLinear *BuildOrigIterationCount(IROList *list, IROLoop *loop) {
IROLinear *upperBound;
IROLinear *nd29b;
IROLinear *lowerBound;
IROLinear *finalCount;
IROLinear *divisor;
Type *type;
IROLinear *nd25;
IROLinear *tmp;
Boolean isZeroBase;
Object *tempobj;
IROLinear *iterCount;
IROLinear *negone;
IROLinear *ass;
ENode *expr;
SInt32 powval;
isZeroBase = 0;
lowerBound = loop->nd14->u.diadic.right;
if (IRO_IsIntConstant(lowerBound) && CInt64_Equal(lowerBound->u.node->data.intval, cint64_zero))
isZeroBase = 1;
if (!isZeroBase)
lowerBound = IRO_DuplicateExpr(lowerBound, list);
if (loop->flags & LoopFlags_1) {
upperBound = IRO_DuplicateExpr(loop->nd18->u.diadic.right, list);
type = loop->nd18->u.diadic.right->rtype;
} else {
upperBound = IRO_DuplicateExpr(loop->nd18->u.diadic.left, list);
type = loop->nd18->u.diadic.left->rtype;
}
CError_ASSERT(2924, loop->induction);
CError_ASSERT(2929, loop->induction->addConst);
divisor = IRO_NewLinear(IROLinearOperand);
divisor->index = ++IRO_NumLinear;
divisor->rtype = type;
expr = IRO_NewENode(EINTCONST);
expr->rtype = type;
CInt64_SetLong(&expr->data.intval, loop->induction->addConst);
divisor->u.node = expr;
if (isZeroBase) {
iterCount = upperBound;
} else {
iterCount = IRO_NewLinear(IROLinearOp2Arg);
iterCount->index = ++IRO_NumLinear;
iterCount->nodetype = ESUB;
iterCount->u.diadic.left = upperBound;
iterCount->u.diadic.right = lowerBound;
iterCount->rtype = type;
IRO_AddToList(iterCount, list);
}
nd25 = IRO_DuplicateExpr(divisor, list);
nd29b = IRO_NewLinear(IROLinearOp2Arg);
nd29b->index = ++IRO_NumLinear;
nd29b->nodetype = EADD;
nd29b->u.diadic.left = iterCount;
nd29b->u.diadic.right = nd25;
nd29b->rtype = type;
IRO_AddToList(nd29b, list);
if (loop->nd18->type == IROLinearOp2Arg && loop->nd18->nodetype == ELESS) {
tmp = nd29b;
negone = IRO_NewLinear(IROLinearOperand);
negone->index = ++IRO_NumLinear;
negone->rtype = type;
expr = IRO_NewENode(EINTCONST);
expr->rtype = type;
CInt64_SetLong(&expr->data.intval, -1);
negone->u.node = expr;
IRO_AddToList(negone, list);
nd29b = IRO_NewLinear(IROLinearOp2Arg);
nd29b->index = ++IRO_NumLinear;
nd29b->nodetype = EADD;
nd29b->u.diadic.left = tmp;
nd29b->u.diadic.right = negone;
nd29b->rtype = type;
IRO_AddToList(nd29b, list);
}
if (CInt64_Equal(divisor->u.node->data.intval, cint64_one)) {
finalCount = nd29b;
} else {
if (divisor->rtype->size <= 4 && IS_TYPE_INT(divisor->rtype) && IRO_IsPow2(divisor, &powval)) {
finalCount = IRO_NewLinear(IROLinearOp2Arg);
finalCount->index = ++IRO_NumLinear;
finalCount->nodetype = ESHL;
finalCount->u.diadic.left = nd29b;
finalCount->u.diadic.right = divisor;
CInt64_SetLong(&divisor->u.node->data.intval, powval);
finalCount->rtype = type;
IRO_AddToList(divisor, list);
IRO_AddToList(finalCount, list);
} else {
finalCount = IRO_NewLinear(IROLinearOp2Arg);
finalCount->index = ++IRO_NumLinear;
finalCount->nodetype = EDIV;
finalCount->u.diadic.left = nd29b;
finalCount->u.diadic.right = divisor;
finalCount->rtype = type;
IRO_AddToList(divisor, list);
IRO_AddToList(finalCount, list);
}
}
tempobj = create_temp_object(type);
IRO_FindVar(tempobj, 1, 1);
ass = IRO_NewLinear(IROLinearOp2Arg);
ass->index = ++IRO_NumLinear;
ass->nodetype = EASS;
ass->u.diadic.left = IRO_TempReference(tempobj, list);
ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind;
ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind;
ass->u.diadic.right = finalCount;
ass->u.diadic.right->flags |= IROLF_Reffed;
ass->rtype = type;
IRO_AddToList(ass, list);
return ass->u.diadic.left;
}
static IROLinear *BuildOrigIterationCount_DoWhile(IROList *list, IROLoop *loop) {
IROLinear *finalCount;
IROLinear *count;
IROLinear *ass;
Type *type;
Object *tempobj;
ENode *expr;
type = loop->nd18->u.diadic.left->rtype;
count = IRO_NewLinear(IROLinearOperand);
count->index = ++IRO_NumLinear;
expr = IRO_NewENode(EINTCONST);
expr->rtype = type;
expr->data.intval = cint64_one;
count->u.node = expr;
count->rtype = type;
IRO_AddToList(count, list);
count->flags |= IROLF_Reffed;
finalCount = IRO_NewLinear(IROLinearOp2Arg);
finalCount->index = ++IRO_NumLinear;
finalCount->nodetype = EADD;
finalCount->rtype = type;
finalCount->u.diadic.left = IRO_DuplicateExpr(loop->nd18->u.diadic.left, list);
finalCount->u.diadic.left->flags |= IROLF_Reffed;
finalCount->u.diadic.left->flags &= ~IROLF_Assigned;
finalCount->u.diadic.left->u.monadic->flags &= ~IROLF_Assigned;
finalCount->u.diadic.right = count;
IRO_AddToList(finalCount, list);
tempobj = create_temp_object(type);
IRO_FindVar(tempobj, 1, 1);
ass = IRO_NewLinear(IROLinearOp2Arg);
ass->index = ++IRO_NumLinear;
ass->nodetype = EASS;
ass->u.diadic.left = IRO_TempReference(tempobj, list);
ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind;
ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind;
ass->u.diadic.right = finalCount;
ass->rtype = type;
IRO_AddToList(ass, list);
return ass->u.diadic.left;
}
IROLinear *BuildNewFinalvalue(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop) {
IROLinear *sub;
IROLinear *addvalue;
Type *type;
IROLinear *ass;
IROLinear *dupbound;
Object *tempobj;
ENode *expr;
type = iterCount->rtype;
addvalue = IRO_NewLinear(IROLinearOperand);
addvalue->index = ++IRO_NumLinear;
addvalue->rtype = type;
expr = IRO_NewENode(EINTCONST);
expr->rtype = type;
CInt64_SetLong(&expr->data.intval, loop->induction->addConst * unrollFactor);
addvalue->u.node = expr;
IRO_AddToList(addvalue, list);
if (loop->flags & LoopFlags_1)
dupbound = IRO_DuplicateExpr(loop->nd18->u.diadic.right, list);
else
dupbound = IRO_DuplicateExpr(loop->nd18->u.diadic.left, list);
sub = IRO_NewLinear(IROLinearOp2Arg);
sub->index = ++IRO_NumLinear;
sub->nodetype = ESUB;
sub->u.diadic.left = dupbound;
sub->u.diadic.right = addvalue;
sub->rtype = type;
IRO_AddToList(sub, list);
tempobj = create_temp_object(type);
IRO_FindVar(tempobj, 1, 1);
ass = IRO_NewLinear(IROLinearOp2Arg);
ass->index = ++IRO_NumLinear;
ass->nodetype = EASS;
ass->u.diadic.left = IRO_TempReference(tempobj, list);
ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind;
ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind;
ass->u.diadic.right = sub;
ass->u.diadic.right->flags |= IROLF_Reffed;
ass->rtype = type;
IRO_AddToList(ass, list);
return ass->u.diadic.left;
}
static IROLinear *BuildPreAlignTemp(IROLoopInd *ind, UInt32 unrollFactor, IROList *list) {
Type *type;
IROLinear *indnd;
IROLinear *factornd;
IROLinear *div;
IROLinear *constnd;
IROLinear *add;
IROLinear *mul;
IROLinear *ass;
Object *tempobj;
ENode *expr;
indnd = ind->nd;
type = indnd->rtype;
factornd = IRO_NewLinear(IROLinearOperand);
factornd->index = ++IRO_NumLinear;
factornd->rtype = type;
expr = IRO_NewENode(EINTCONST);
expr->rtype = type;
CInt64_SetLong(&expr->data.intval, unrollFactor);
factornd->u.node = expr;
IRO_AddToList(factornd, list);
if (indnd->type == IROLinearOp1Arg)
IRO_DuplicateExpr(indnd->u.monadic, list);
else
IRO_DuplicateExpr(indnd->u.diadic.left, list);
list->tail->flags &= ~IROLF_Assigned;
list->tail->u.monadic->flags &= ~IROLF_Assigned;
div = IRO_NewLinear(IROLinearOp2Arg);
div->index = ++IRO_NumLinear;
div->nodetype = EDIV;
div->u.diadic.left = list->tail;
div->u.diadic.right = factornd;
div->rtype = type;
IRO_AddToList(div, list);
div->flags |= IROLF_Reffed;
constnd = IRO_NewLinear(IROLinearOperand);
constnd->index = ++IRO_NumLinear;
expr = IRO_NewENode(EINTCONST);
expr->rtype = type;
expr->data.intval = cint64_one;
constnd->u.node = expr;
constnd->rtype = type;
IRO_AddToList(constnd, list);
constnd->flags |= IROLF_Reffed;
add = IRO_NewLinear(IROLinearOp2Arg);
add->index = ++IRO_NumLinear;
add->nodetype = EADD;
add->u.diadic.left = div;
add->u.diadic.right = constnd;
add->rtype = type;
IRO_AddToList(add, list);
add->flags |= IROLF_Reffed;
IRO_DuplicateExpr(factornd, list);
mul = IRO_NewLinear(IROLinearOp2Arg);
mul->index = ++IRO_NumLinear;
mul->nodetype = EMUL;
mul->u.diadic.left = add;
mul->u.diadic.right = list->tail;
mul->rtype = type;
IRO_AddToList(mul, list);
mul->flags |= IROLF_Reffed;
tempobj = create_temp_object(type);
IRO_FindVar(tempobj, 1, 1);
ass = IRO_NewLinear(IROLinearOp2Arg);
ass->index = ++IRO_NumLinear;
ass->nodetype = EASS;
ass->u.diadic.left = IRO_TempReference(tempobj, list);
ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind;
ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind;
ass->u.diadic.right = mul;
ass->u.diadic.right->flags |= IROLF_Reffed;
ass->rtype = type;
IRO_AddToList(ass, list);
return ass->u.diadic.left;
}
static IROLinear *BuildNewFinalvalue_DoWhile(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop) {
IROLinear *addvalue;
IROLinear *add;
IROLinear *mul;
IROLinear *ass;
Type *type;
Object *tempobj;
ENode *expr;
type = iterCount->rtype;
addvalue = IRO_NewLinear(IROLinearOperand);
addvalue->index = ++IRO_NumLinear;
addvalue->rtype = type;
expr = IRO_NewENode(EINTCONST);
expr->rtype = type;
CInt64_SetLong(&expr->data.intval, loop->induction->addConst);
addvalue->u.node = expr;
IRO_AddToList(addvalue, list);
addvalue->flags |= IROLF_Reffed;
mul = IRO_NewLinear(IROLinearOp2Arg);
mul->index = ++IRO_NumLinear;
mul->nodetype = EMUL;
mul->u.diadic.left = IRO_DuplicateExpr(iterCount, list);
mul->u.diadic.right = addvalue;
mul->rtype = type;
IRO_AddToList(mul, list);
mul->flags |= IROLF_Reffed;
mul->u.diadic.left->flags &= ~IROLF_Assigned;
mul->u.diadic.left->u.diadic.left->flags &= ~IROLF_Assigned;
if (loop->induction->nd->type == IROLinearOp1Arg)
IRO_DuplicateExpr(loop->induction->nd->u.monadic, list);
else
IRO_DuplicateExpr(loop->induction->nd->u.diadic.left, list);
list->tail->flags &= ~IROLF_Assigned;
list->tail->u.diadic.left->flags &= ~IROLF_Assigned;
add = IRO_NewLinear(IROLinearOp2Arg);
add->index = ++IRO_NumLinear;
add->nodetype = EADD;
add->u.diadic.left = mul;
add->u.diadic.right = list->tail;
add->rtype = type;
IRO_AddToList(add, list);
add->flags |= IROLF_Reffed;
tempobj = create_temp_object(type);
IRO_FindVar(tempobj, 1, 1);
ass = IRO_NewLinear(IROLinearOp2Arg);
ass->index = ++IRO_NumLinear;
ass->nodetype = EASS;
ass->u.diadic.left = IRO_TempReference(tempobj, list);
ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind;
ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind;
ass->u.diadic.right = add;
ass->u.diadic.right->flags |= IROLF_Reffed;
ass->rtype = type;
IRO_AddToList(ass, list);
return ass->u.diadic.left;
}
static IROLinear *BuildUnrolledFinalvalue_DoWhile(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop) {
IROLinear *addvalue_mult;
IROLinear *addvalue;
IROLinear *mul;
IROLinear *sub;
IROLinear *add;
IROLinear *ass;
Type *type;
Object *tempobj;
ENode *expr;
type = iterCount->rtype;
addvalue_mult = IRO_NewLinear(IROLinearOperand);
addvalue_mult->index = ++IRO_NumLinear;
addvalue_mult->rtype = type;
expr = IRO_NewENode(EINTCONST);
expr->rtype = type;
CInt64_SetLong(&expr->data.intval, loop->induction->addConst * unrollFactor);
addvalue_mult->u.node = expr;
IRO_AddToList(addvalue_mult, list);
addvalue_mult->flags |= IROLF_Reffed;
addvalue = IRO_NewLinear(IROLinearOperand);
addvalue->index = ++IRO_NumLinear;
addvalue->rtype = type;
expr = IRO_NewENode(EINTCONST);
expr->rtype = type;
CInt64_SetLong(&expr->data.intval, loop->induction->addConst);
addvalue->u.node = expr;
IRO_AddToList(addvalue, list);
addvalue->flags |= IROLF_Reffed;
mul = IRO_NewLinear(IROLinearOp2Arg);
mul->index = ++IRO_NumLinear;
mul->nodetype = EMUL;
mul->u.diadic.left = IRO_DuplicateExpr(iterCount, list);
mul->u.diadic.right = addvalue;
mul->rtype = type;
IRO_AddToList(mul, list);
mul->flags |= IROLF_Reffed;
mul->u.diadic.left->flags &= ~IROLF_Assigned;
mul->u.diadic.left->u.diadic.left->flags &= ~IROLF_Assigned;
sub = IRO_NewLinear(IROLinearOp2Arg);
sub->index = ++IRO_NumLinear;
sub->nodetype = ESUB;
sub->u.diadic.left = mul;
sub->u.diadic.right = addvalue_mult;
sub->rtype = type;
IRO_AddToList(sub, list);
sub->flags |= IROLF_Reffed;
if (loop->induction->nd->type == IROLinearOp1Arg)
IRO_DuplicateExpr(loop->induction->nd->u.monadic, list);
else
IRO_DuplicateExpr(loop->induction->nd->u.diadic.left, list);
list->tail->flags &= ~IROLF_Assigned;
list->tail->u.diadic.left->flags &= ~IROLF_Assigned;
add = IRO_NewLinear(IROLinearOp2Arg);
add->index = ++IRO_NumLinear;
add->nodetype = EADD;
add->u.diadic.left = sub;
add->u.diadic.right = list->tail;
add->rtype = type;
IRO_AddToList(add, list);
add->flags |= IROLF_Reffed;
tempobj = create_temp_object(type);
IRO_FindVar(tempobj, 1, 1);
ass = IRO_NewLinear(IROLinearOp2Arg);
ass->index = ++IRO_NumLinear;
ass->nodetype = EASS;
ass->u.diadic.left = IRO_TempReference(tempobj, list);
ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind;
ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind;
ass->u.diadic.right = add;
ass->u.diadic.right->flags |= IROLF_Reffed;
ass->rtype = type;
IRO_AddToList(ass, list);
return ass->u.diadic.left;
}
void BuildUnrolledBodyEntryTest(IROList *list, IROLinear *iterCount, UInt32 unrollFactor, CLabel *label) {
Type *type;
IROLinear *ifnot;
IROLinear *comp;
IROLinear *var;
IROLinear *value;
ENode *expr;
type = iterCount->rtype;
value = IRO_NewLinear(IROLinearOperand);
value->index = ++IRO_NumLinear;
value->rtype = type;
expr = IRO_NewENode(EINTCONST);
expr->rtype = type;
CInt64_SetLong(&expr->data.intval, unrollFactor);
value->u.node = expr;
IRO_AddToList(value, list);
var = IRO_DuplicateExpr(iterCount, list);
comp = IRO_NewLinear(IROLinearOp2Arg);
comp->index = ++IRO_NumLinear;
comp->nodetype = EGREATER;
comp->u.diadic.left = var;
comp->u.diadic.right = value;
comp->u.diadic.right->flags |= IROLF_Reffed;
comp->rtype = type;
IRO_AddToList(comp, list);
ifnot = IRO_NewLinear(IROLinearOp1Arg);
ifnot->index = ++IRO_NumLinear;
ifnot->type = IROLinearIfNot;
ifnot->u.label.x4 = comp;
ifnot->u.label.x4->flags |= IROLF_Reffed;
ifnot->rtype = type;
ifnot->u.label.label = label;
IRO_AddToList(ifnot, list);
}
void ChangeInductionReference(IROLinear *first, IROLinear *last, CInt64 val, IROLoop *loop) {
IROLinear *nd;
IROLinear *value;
IROLinear *add;
UInt32 isUnsigned;
IROLinear *father;
Boolean flag;
IROLinear *father2;
IROLinear *father3;
Type *tmp;
UInt32 flag2;
Object *varobj;
IROLinear *next;
ENode *expr;
Type *type;
CInt64 val2;
CInt64 val1;
IROList list;
type = loop->induction->nd->rtype;
isUnsigned = IRO_IsUnsignedType(type);
for (nd = first; nd; nd = next) {
next = nd->next;
varobj = IRO_IsVariable(nd);
if (varobj && loop->induction->var->object == varobj) {
value = IRO_NewLinear(IROLinearOperand);
value->index = ++IRO_NumLinear;
value->rtype = type;
expr = IRO_NewENode(EINTCONST);
expr->rtype = type;
expr->data.intval = val;
value->u.node = expr;
add = IRO_NewLinear(IROLinearOp2Arg);
add->index = ++IRO_NumLinear;
add->nodetype = EADD;
add->rtype = type;
father = IRO_LocateFather(nd);
flag = 1;
if (father && IS_LINEAR_MONADIC(father, ETYPCON)) {
tmp = father->rtype;
father = IRO_LocateFather(father);
if (tmp->type != nd->rtype->type || tmp->size < nd->rtype->size)
flag = 0;
}
flag2 = 0;
if (
flag &&
father &&
IS_LINEAR_DIADIC_2(father, ESHL, EMUL) &&
IRO_IsIntConstant(father->u.diadic.right) &&
(father2 = IRO_LocateFather(father)) &&
IS_LINEAR_DIADIC(father2, EADD) &&
father2->u.diadic.right == father &&
(father3 = IRO_LocateFather(father2))
)
{
IRO_InitList(&list);
val2 = father->u.diadic.right->u.node->data.intval;
if (father->nodetype == ESHL)
val2 = CInt64_Shl(cint64_one, val2);
val1 = value->u.node->data.intval;
if (isUnsigned)
val1 = CInt64_MulU(val2, val1);
else
val1 = CInt64_Mul(val2, val1);
value->u.node->data.intval = val1;
IRO_AddToList(value, &list);
IRO_AddToList(add, &list);
add->u.diadic.right = value;
IRO_Paste(list.head, list.tail, father3);
IRO_LocateFather_Cut_And_Paste_Without_Nopping(father2, add);
add->u.diadic.left = father2;
add->rtype = father2->rtype;
flag2 = 1;
}
if (!flag2) {
add->u.diadic.right = value;
add->u.diadic.right->flags |= IROLF_Reffed;
value->next = add;
add->u.diadic.left = nd;
IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, add);
add->flags |= IROLF_Reffed;
nd->next = value;
add->next = next;
}
}
if (nd == last)
break;
}
}
IROLinear *UpdateInductionIncrement(IROLoop *loop, SInt32 value, IROLinear *before) {
IROLinear *ind_nd;
IROLinear *addvalue;
IROLinear *ass;
Type *type;
ENode *expr;
IROList list;
IRO_InitList(&list);
ind_nd = loop->induction->nd;
type = ind_nd->rtype;
addvalue = IRO_NewLinear(IROLinearOperand);
addvalue->index = ++IRO_NumLinear;
addvalue->rtype = type;
expr = IRO_NewENode(EINTCONST);
expr->rtype = type;
CInt64_SetLong(&expr->data.intval, value * loop->induction->addConst);
addvalue->u.node = expr;
IRO_AddToList(addvalue, &list);
if (IS_LINEAR_MONADIC_2(ind_nd, EPREINC, EPOSTINC)) {
ind_nd = IRO_DuplicateExpr(ind_nd->u.monadic, &list);
ass = IRO_NewLinear(IROLinearOp2Arg);
ass->index = ++IRO_NumLinear;
ass->nodetype = EADDASS;
ass->u.diadic.left = ind_nd;
ass->u.diadic.right = addvalue;
ass->rtype = type;
IRO_AddToList(ass, &list);
} else if (IS_LINEAR_MONADIC_2(ind_nd, EPREDEC, EPOSTDEC)) {
ind_nd = IRO_DuplicateExpr(ind_nd->u.monadic, &list);
ass = IRO_NewLinear(IROLinearOp2Arg);
ass->index = ++IRO_NumLinear;
ass->nodetype = ESUBASS;
ass->u.diadic.left = ind_nd;
ass->u.diadic.right = addvalue;
ass->rtype = type;
IRO_AddToList(ass, &list);
} else if (IS_LINEAR_DIADIC(ind_nd, EADDASS)) {
ind_nd = IRO_DuplicateExpr(ind_nd->u.monadic, &list);
ass = IRO_NewLinear(IROLinearOp2Arg);
ass->index = ++IRO_NumLinear;
ass->nodetype = EADDASS;
ass->u.diadic.left = ind_nd;
ass->u.diadic.right = addvalue;
ass->rtype = type;
IRO_AddToList(ass, &list);
}
IRO_Paste(list.head, list.tail, before);
return list.tail;
}
void GenInitialAssignment(IROLoop *loop, Object *var, IROList *list) {
Type *type;
IROLinear *nd;
CError_ASSERT(3924, loop->nd14 && loop->nd14->type == IROLinearOp2Arg);
type = loop->induction->nd->rtype;
nd = IRO_NewLinear(IROLinearOp2Arg);
nd->index = ++IRO_NumLinear;
nd->nodetype = EASS;
nd->u.diadic.left = IRO_TempReference(var, list);
nd->u.diadic.right = IRO_DuplicateExpr(loop->nd14->u.diadic.right, list);
nd->rtype = type;
IRO_AddToList(nd, list);
}
void GenNewInduction(void) {
CError_FATAL(3941);
}