OSROpndInfo OSRInductionDetector::processOpnd()

in vm/jitrino/src/optimizer/osr.cpp [68:199]


OSROpndInfo OSRInductionDetector::processOpnd(LoopTree* tree,
                                      LoopNode* loopHead,
                                      InstStack& defStack,
                                      const Opnd* opnd,
                                      iv_detection_flag flag){
    if (Log::isEnabled()) {
        Log::out() << "Processing opnd: ";
        opnd->print(Log::out());
        Log::out() << "\n";
    }

    OSROpndInfo result;
    Inst* defInst = opnd->getInst();

    if (std::find(defStack.begin(), defStack.end(), defInst) !=
        defStack.end()) {
        result.setType(OSROpndInfo::COUNTER);
        result.setIncrement(0);
        result.setOpnd((Opnd*) opnd);
        return result;
    }

    Opcode opcode = defInst->getOpcode();

    if (opcode == Op_LdConstant) {
        result.setType(OSROpndInfo::LD_CONST);
        result.setConst(defInst->asConstInst()->getValue().i4);
        result.setOpnd((Opnd*) opnd);
        result.setHeader((Opnd*) opnd);
        result.setHeaderFound();
        return result;
    }

    if (!inExactLoop(tree, (Opnd*) opnd, loopHead)) {
        result.setOpnd((Opnd*) opnd);
        result.setHeader((Opnd*) opnd);
        result.setHeaderFound();
        return result;
    }

    defStack.push_back(defInst);

    if (opcode == Op_Phi) {
        OSROpndInfo info1 =
            processOpnd(tree, loopHead, defStack, defInst->getSrc(0));

        if (defInst->getNumSrcOperands() > 1) {
            OSROpndInfo info2 =
                processOpnd(tree, loopHead, defStack, defInst->getSrc(1));
            if ( ((info1.isCounter() && !info1.isPhiSplit())
                   && (info2.isDOL() || info2.isLDConst()))
                 || ((info2.isCounter() && !info2.isPhiSplit())
                   && (info1.isDOL() || info1.isLDConst())) ) {

                result.setType(OSROpndInfo::COUNTER);
                result.setIncrement(info1.isCounter()? info1.
                                    getIncrement() : info2.getIncrement());
                result.markPhiSplit();
                result.setHeader((Opnd*) opnd);
                result.setHeaderFound();
            } else if ((flag == CHOOSE_MAX_IN_BRANCH) && info1.isCounter()
                       && info2.isCounter()
                       && signof(info1.getIncrement()) ==
                       signof(info2.getIncrement())) {

                result.setType(OSROpndInfo::COUNTER);
                result.setIncrement(std::abs(info1.getIncrement()) >
                                    std::abs(info2.getIncrement())? info1.
                                    getIncrement() : info2.getIncrement());
                result.markPhiSplit();
                result.setHeader((Opnd*) opnd);
                result.setHeaderFound();
            } else {
                result.setType(OSROpndInfo::UNDEF);
            }
        }
    } else if (opcode == Op_Add || opcode == Op_Sub) {
        Opnd* opnd1 = defInst->getSrc(0);
        Opnd* opnd2 = defInst->getSrc(1);
        OSROpndInfo info1 = processOpnd(tree, loopHead, defStack, opnd1);
        OSROpndInfo info2 = processOpnd(tree, loopHead, defStack, opnd2);

        if ((info1.isLDConst() || info1.isDOL())
            && (info2.isLDConst() || info2.isDOL())) {
            if (info1.isLDConst() && info2.isLDConst()
                && info1.getConst() == info2.getConst()) {
                result.setType(OSROpndInfo::LD_CONST);
                result.setConst(info1.getConst());
                writeHeaderToResult(result, tree, info1, info2);
            }
        } else if ((info1.isCounter() && info2.isLDConst())
                   || (info2.isCounter() && info1.isLDConst())) {
            U_32 increment = info1.isCounter() ?
                info1.getIncrement() : info2.getIncrement();
            U_32 diff = info1.isLDConst()? info1.getConst() : info2.getConst();
            bool monotonousFlag = increment == 0 || diff == 0
                || (opcode == Op_Add && signof(diff) == signof(increment))
                || (opcode == Op_Sub && signof(diff) != signof(increment));
            if (monotonousFlag) {
                result.setType(OSROpndInfo::COUNTER);
                if ((info1.isCounter() && info1.isPhiSplit()) ||
                    (info2.isCounter() && info2.isPhiSplit())) {
                    result.markPhiSplit();
                    writeHeaderToResult(result, tree, info1, info2);
                }
                if (opcode == Op_Add) {
                    result.setIncrement(increment + diff);
                    writeHeaderToResult(result, tree, info1, info2);
                } else {
                    result.setIncrement(increment - diff);
                    writeHeaderToResult(result, tree, info1, info2);
                }
            } else {
                result.setType(OSROpndInfo::UNDEF);
            }
        } else {
            result.setType(OSROpndInfo::UNDEF);
        }
    } else if (opcode == Op_StVar || opcode == Op_LdVar) {
        Opnd* newOpnd = defInst->getSrc(0);
        result = processOpnd(tree, loopHead, defStack, newOpnd);
    } else if (opcode == Op_TauArrayLen) {
        Opnd* arrayOpnd = defInst->getSrc(0);
        result = processOpnd(tree, loopHead, defStack, arrayOpnd);
    } else {
        result.setType(OSROpndInfo::UNDEF);
    }

    defStack.pop_back();
    result.setOpnd((Opnd*) opnd);
    return result;
}