blob: f60f926b88d0327ca5510b527907602f930335b8 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Intel
*
*/
#include "LoopUtils.h"
#include "Inst.h"
namespace Jitrino {
InvariantOpndLoopInfo* InductiveOpndLoopInfo::getStartValue() {
return startValue;
}
InvariantOpndLoopInfo* InductiveOpndLoopInfo::getEndValue() {
if (boundType != UNKNOWN_BOUND) {
return endValue;
}
findBoundInfo();
return endValue;
}
void InductiveOpndLoopInfo::setStartValue(InvariantOpndLoopInfo* start) {
startValue = start;
}
void InductiveOpndLoopInfo::setEndValue(InvariantOpndLoopInfo* end) {
endValue = end;
}
BoundType InductiveOpndLoopInfo::getBoundType() {
if (boundType != UNKNOWN_BOUND) {
return boundType;
}
findBoundInfo();
return boundType;
}
void InductiveOpndLoopInfo::findBoundInfo() {
BranchInst* branchInst = NULL;
OpndLoopInfo* opndInfo = NULL;
const Nodes& loopNodes = inductionDetector->loopNode->getNodesInLoop();
for (Nodes::const_iterator it = loopNodes.begin(), end = loopNodes.end(); it != end; it++) {
Node* node = *it;
branchInst = ((Inst*)node->getLastInst())->asBranchInst();
if (branchInst == NULL) continue;
SsaOpnd* leftOpnd = branchInst->getSrc(0)->asSsaOpnd();
SsaOpnd* rightOpnd = (branchInst->getNumSrcOperands() == 2)
? branchInst->getSrc(1)->asSsaOpnd() : NULL;
Edge* trueEdge = node->getTrueEdge();
Edge* falseEdge = node->getFalseEdge();
bool isTrueExit = inductionDetector->loopNode->isLoopExit(trueEdge);
bool isFalseExit = inductionDetector->loopNode->isLoopExit(falseEdge);
// Check if branch matches.
if ((isTrueExit || isFalseExit) && (leftOpnd == mainOpnd || rightOpnd == mainOpnd)) {
ComparisonModifier compMod = branchInst->getComparisonModifier();
switch (compMod) {
case Cmp_Zero:
boundType = isTrueExit ? NE_BOUND : EQ_BOUND;
endValue = inductionDetector->zero;
break;
case Cmp_NonZero:
boundType = isTrueExit ? EQ_BOUND : NE_BOUND;
endValue = inductionDetector->zero;
break;
case Cmp_EQ: {
boundType = isTrueExit ? NE_BOUND : EQ_BOUND;
opndInfo = (leftOpnd == mainOpnd)
? inductionDetector->getOpndInfo(rightOpnd)
: inductionDetector->getOpndInfo(leftOpnd);
endValue = (opndInfo != NULL) ? opndInfo->asInvarinat() : NULL;
break;
}
case Cmp_NE_Un:
boundType = isTrueExit ? EQ_BOUND : NE_BOUND;
opndInfo = (leftOpnd == mainOpnd)
? inductionDetector->getOpndInfo(rightOpnd)
: inductionDetector->getOpndInfo(leftOpnd);
endValue = (opndInfo != NULL) ? opndInfo->asInvarinat() : NULL;
break;
case Cmp_GT:
case Cmp_GT_Un:
if (leftOpnd == mainOpnd) {
// indVar >= invVar
boundType = isTrueExit ? UPPER_EQ_BOUND : LOW_BOUND;
opndInfo = inductionDetector->getOpndInfo(rightOpnd);
} else {
// invVar >= indVar
boundType = isTrueExit ? LOW_EQ_BOUND : UPPER_BOUND;
opndInfo = inductionDetector->getOpndInfo(leftOpnd);
}
endValue = (opndInfo != NULL) ? opndInfo->asInvarinat() : NULL;
break;
case Cmp_GTE:
case Cmp_GTE_Un:
if (leftOpnd == mainOpnd) {
// indVar >= invVar
boundType = isTrueExit ? UPPER_BOUND : LOW_EQ_BOUND;
opndInfo = inductionDetector->getOpndInfo(rightOpnd);
} else {
// invVar >= indVar
boundType = isTrueExit ? LOW_BOUND : UPPER_EQ_BOUND;
opndInfo = inductionDetector->getOpndInfo(leftOpnd);
}
endValue = (opndInfo != NULL) ? opndInfo->asInvarinat() : NULL;
break;
default:;
};
return;
}
}
}
InductionDetector::InductionDetector(MemoryManager& mm, LoopNode* loop):
memoryManager(mm), loopNode(loop), defStack(mm) {
zero = createConstOpnd(NULL, 0);
one = createConstOpnd(NULL, 1);
};
OpndLoopInfo* InductionDetector::processOpnd(SsaOpnd * opnd) {
OpndLoopInfo* resultOpnd = NULL;
Inst* defInst = opnd->getInst();
if (std::find(defStack.begin(), defStack.end(), defInst) != defStack.end()) {
return createInductiveOpnd(opnd, one, NULL, zero);
}
Node* defNode = defInst->getNode();
Opcode opcode = defInst->getOpcode();
if (opcode == Op_LdConstant) {
return createConstOpnd(opnd, defInst->asConstInst()->getValue().i4);
}
if (!loopNode->inLoop(defNode)) {
return createInvariantOpnd(opnd);
}
defStack.push_back(defInst);
switch (opcode) {
case Op_Phi: {
OpndLoopInfo* info1 = processOpnd(defInst->getSrc(0)->asSsaOpnd());
OpndLoopInfo* info2 = (info1 != NULL && defInst->getNumSrcOperands() == 2)
? processOpnd(defInst->getSrc(1)->asSsaOpnd()) : NULL;
if (info2 != NULL) {
InductiveOpndLoopInfo* indOpnd = (info1->isInductive() && !info1->asInductive()->isPhiSplit) ?
info1->asInductive() : ((info2->isInductive() && !info2->asInductive()->isPhiSplit) ?
info2->asInductive() : NULL);
InvariantOpndLoopInfo* invOpnd = info1->isInvariant() ? info1->asInvarinat() :
(info2->isInvariant() ? info2->asInvarinat() : NULL);
if (indOpnd != NULL && invOpnd != NULL) {
InductiveOpndLoopInfo* resOpnd = createInductiveOpnd(opnd, one,
NULL, indOpnd->getStride());
resOpnd->startValue = invOpnd;
resOpnd->header = opnd;
resOpnd->isPhiSplit = true;
resultOpnd = resOpnd;
}
}
break;
}
case Op_Add:
case Op_Sub:
case Op_Mul: {
SsaOpnd *op1 = defInst->getSrc(0)->asSsaOpnd();
SsaOpnd *op2 = defInst->getSrc(1)->asSsaOpnd();
OpndLoopInfo* info1 = processOpnd(op1);
OpndLoopInfo* info2 = (info1 != NULL) ? processOpnd(op2) : NULL;
if (info2 != NULL) {
if (info1->isInvariant() && info2->isInvariant()) {
InvariantOpndLoopInfo* invOpnd1 = info1->asInvarinat();
InvariantOpndLoopInfo* invOpnd2 = info2->asInvarinat();
if (invOpnd1->isConstant() && invOpnd2->isConstant()) {
int val1 = invOpnd1->asConstant()->getValue();
int val2 = invOpnd2->asConstant()->getValue();
if (opcode == Op_Add) {
resultOpnd = createConstOpnd(opnd, val1 + val2);
} else if (opcode == Op_Sub) {
resultOpnd = createConstOpnd(opnd, val1 - val2);
} else {
assert(opcode == Op_Mul);
resultOpnd = createConstOpnd(opnd, val1 * val2);
}
} else {
resultOpnd = createInvariantOpnd(opnd);
}
} else {
InductiveOpndLoopInfo* indOpnd = (info1->isInductive() && !info1->asInductive()->isPhiSplit) ?
info1->asInductive() : ((info2->isInductive() && !info2->asInductive()->isPhiSplit) ?
info2->asInductive() : NULL);
InvariantOpndLoopInfo* invOpnd = info1->isInvariant() ? info1->asInvarinat() :
(info2->isInvariant() ? info2->asInvarinat() : NULL);
if (indOpnd != NULL && invOpnd != NULL) {
InductiveOpndLoopInfo* resOpnd = NULL;
if (opcode == Op_Add || opcode == Op_Sub) {
resOpnd = createInductiveOpnd(opnd, one, indOpnd, invOpnd);
} else {
assert(opcode == Op_Mul);
resOpnd = createInductiveOpnd(opnd, invOpnd, indOpnd, zero);
}
resOpnd->isPhiSplit = indOpnd->isPhiSplit;
resOpnd->header = indOpnd->header;
resultOpnd = resOpnd;
}
}
}
break;
}
case Op_StVar:
case Op_LdVar: {
resultOpnd = processOpnd(defInst->getSrc(0)->asSsaOpnd());
if (resultOpnd != NULL) {
resultOpnd->mainOpnd = opnd;
}
break;
}
case Op_TauArrayLen: {
resultOpnd = processOpnd(defInst->getSrc(0)->asSsaOpnd());
if (resultOpnd != NULL) {
resultOpnd->mainOpnd = opnd;
}
break;
}
default:;
};
defStack.pop_back();
return resultOpnd;
}
OpndLoopInfo* InductionDetector::getOpndInfo(SsaOpnd * opnd,
IVDetectionMode mode) {
// TODO: Current implementation doesn't support other modes.
assert(mode == IGNORE_BRANCH);
defStack.clear();
ivMode = mode;
return processOpnd(opnd);
}
} // namespace Jitrino