in vm/jitrino/src/optimizer/loop_unroll.cpp [333:447]
static OpndLoopInfo processOpnd(LoopNode* loopHead, LoopTree* lt, InstStack& defStack, Opnd* opnd) {
OpndLoopInfo result;
Inst* defInst = opnd->getInst();
if (Log::isEnabled()) {
log_ident(defStack.size()); defInst->print(Log::out()); Log::out()<<"]"<<std::endl;
}
if (std::find(defStack.begin(), defStack.end(), defInst)!=defStack.end()) {
result.setType(OpndLoopInfo::COUNTER);
result.setIncrement(0);
if (Log::isEnabled()) {
log_ident(defStack.size());
Log::out()<<"Found duplicate in def stack -> stopping recursion. ";result.print(Log::out()); Log::out()<<std::endl;
}
return result;
}
Node* defNode = defInst->getNode();
Opcode opcode = defInst->getOpcode();
if (opcode == Op_LdConstant) {
result.setType(OpndLoopInfo::LD_CONST);
result.setConst(defInst->asConstInst()->getValue().i4);
if (Log::isEnabled()) {
log_ident(defStack.size());
Log::out()<<"assigning to const -> stopping recursion. ";result.print(Log::out());Log::out()<<std::endl;
}
return result;
}
if (!loopHead->inLoop(defNode)) {
if (Log::isEnabled()) {
log_ident(defStack.size());
Log::out()<<"Inst out of the loop -> stopping recursion. ";result.print(Log::out()); Log::out()<<std::endl;
}
return result;
}
defStack.push_back(defInst);
if (opcode == Op_Phi) {
OpndLoopInfo info1 = processOpnd(loopHead, lt, defStack, defInst->getSrc(0));
OpndLoopInfo info2 = processOpnd(loopHead, lt, defStack, defInst->getSrc(1));
if (Log::isEnabled()) {
log_ident(defStack.size());
Log::out()<<"PHI(";info1.print(Log::out());Log::out()<<",";info2.print(Log::out());Log::out()<<")"<<std::endl;
}
if ( ((info1.isCounter() && !info1.isPhiSplit()) && (info2.isDOL() || info2.isLDConst()))
|| ((info2.isCounter() && !info2.isPhiSplit()) && (info1.isDOL() || info1.isLDConst())) )
{
result.setType(OpndLoopInfo::COUNTER);
result.setIncrement(info1.isCounter() ? info1.getIncrement() : info2.getIncrement());
result.markPhiSplit();
} else {
result.setType(OpndLoopInfo::UNDEF);
}
} else if (opcode == Op_Add || opcode == Op_Sub) { //todo: LADD
Opnd *op1 = defInst->getSrc(0);
Opnd *op2 = defInst->getSrc(1);
OpndLoopInfo info1 = processOpnd(loopHead, lt, defStack, op1);
OpndLoopInfo info2 = processOpnd(loopHead, lt, defStack, op2);
if ((info1.isLDConst() || info1.isDOL()) && (info2.isLDConst() || info2.isDOL())) {
if (info1.isLDConst() && info2.isLDConst() && info1.getConst() == info2.getConst()) {
result.setType(OpndLoopInfo::LD_CONST);
result.setConst(info1.getConst());
} else {
//result is DOL (default type)
}
} else if ((info1.isCounter() && info2.isLDConst()) || (info2.isCounter() && info1.isLDConst())) {
int increment = info1.isCounter()? info1.getIncrement(): info2.getIncrement();
int diff = info1.isLDConst()? info1.getConst(): info2.getConst();
//we use SSA form to analyze how opnd changes in loop and we do not analyze actual control flow,
// so we can unroll loops with monotonically changing 'counters' only.
//Example: when 'counter' changes not monotonically and we can't unroll:
//idx=0; loop {idx+=100; if(idx>=100) break; idx-=99;} ->'increment'=1 but not monotonicaly.
bool monotonousFlag = increment == 0 || diff == 0
|| (opcode == Op_Add && signof(diff) == signof(increment))
|| (opcode == Op_Sub && signof(diff) != signof(increment));
if (monotonousFlag) {
result.setType(OpndLoopInfo::COUNTER);
if ((info1.isCounter() && info1.isPhiSplit()) || (info2.isCounter() && info2.isPhiSplit())) {
result.markPhiSplit();
}
//TO IMPROVE: for loops like: for (; length-1>=0;length--){...}
//we have 2 SUBs by -1 => "-2", but real counter is changed by "-1".
//Loop unroll will use "-2". It's ok, because this value is used in a guard inst
//and ABS(increment_in_unroll) >= ABS(real_increment). This work only for monotonous loops.
//To make increment_in_unroll == real_increment we must track modifications (SUB,ADD) that affects vars only.
if (opcode == Op_Add) {
result.setIncrement(increment + diff);
} else {
result.setIncrement(increment - diff);
}
} else {
result.setType(OpndLoopInfo::UNDEF);
}
} else {
result.setType(OpndLoopInfo::UNDEF);
}
} else if (opcode == Op_StVar || opcode == Op_LdVar) {
Opnd* newOpnd = defInst->getSrc(0);
result = processOpnd(loopHead, lt, defStack, newOpnd);
} else if (opcode == Op_TauArrayLen) {
Opnd* arrayOpnd = defInst->getSrc(0);
result = processOpnd(loopHead, lt, defStack, arrayOpnd);
} else { //unsupported op
result.setType(OpndLoopInfo::UNDEF);
if (Log::isEnabled()) {
log_ident(defStack.size()); Log::out()<<"unknown op -> stopping recursion. ";
}
}
defStack.pop_back();
if (Log::isEnabled()) {
log_ident(defStack.size());
result.print(Log::out());Log::out()<<std::endl;
}
return result;
}