// Currently the transfer function used by DFAGen is assumed to be:
// Y = gen[n] U (X - kill[n]).
OA_ptr<DataFlowSet>
ManagerReachingDefs::transfer(
    OA_ptr<DataFlowSet> xdfset,
    StmtHandle stmt)
{
    OA_ptr<ReachingDefsDFSet> xdfgenset;
    xdfgenset = xdfset.convert<ReachingDefsDFSet>();

    OA_ptr<ReachingDefsDFSet> x;
    x = new ReachingDefsDFSet(*xdfgenset);

    // if debug mode is on print information about transfer function
    if (debug) {
        cout << "In transfer: " << endl;
        cout << "\t Stmt  = " << mIR->toString(stmt) << endl;
        cout << "\t X     = ";
        dumpset(x);
    }

    OA_ptr<DataFlowSet> genBaseObj = genSet(stmt, x);
    OA_ptr<ReachingDefsDFSet> gen = genBaseObj.convert<ReachingDefsDFSet>();

    OA_ptr<DataFlowSet> killBaseObj = killSet(stmt, x);
    OA_ptr<ReachingDefsDFSet> kill = killBaseObj.convert<ReachingDefsDFSet>();


    // Add gen[n] to Y
    OA_ptr<DataFlow::DataFlowSetImplIterator<StmtHandle > > genIter;
    genIter = new DataFlow::DataFlowSetImplIterator<StmtHandle > (gen);
    for(; genIter->isValid(); ++(*genIter)) {
        StmtHandle  genVal;
        genVal = genIter->current();
        mReachingDefsMap->insert(stmt, genVal);
    }
    // Add X - kill[n] to Y
    x->minusEqu(*kill);
    OA_ptr<DataFlow::DataFlowSetImplIterator<StmtHandle > > xIter;
    xIter = new DataFlow::DataFlowSetImplIterator<StmtHandle > (x);
    for(; xIter->isValid(); ++(*xIter)) {
        StmtHandle  xVal;
        xVal = xIter->current();
        mReachingDefsMap->insert(stmt, xVal);
    }

    // if debug mode is on print information about transfer function
    if(debug) {
        cout << "\t gen  = ";
        dumpset(gen);
        cout << "\t kill = ";
        dumpset(kill);
        cout << "\t Y    = ";
        dumpset(mReachingDefsMap->getReachingDefsSet(stmt));
    }

    return mReachingDefsMap->getReachingDefsSet(stmt);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AggregateCopyPropagation::LocalCopyPropagation(Block* block, 
                                                    TOperandToIdDict& availableCopies) {
    BitVector killSet(infoList_.Count());
    BitVector copySet(infoList_.Count()); // Unused here.

    // Try to use the original operand instead of the copy.
    // We need to recompute the 'kill' set, because copies available
    // at the block entry might be invalidated by 'store' and 'call'.
    for(auto instr = block->FirstInstruction(); instr; 
        instr = instr->NextInstruction()) {
        if(auto callInstr = instr->As<CallInstr>()) {
            // This might be a call that kills copies.
            AddToKillSet(callInstr, killSet, copySet);
            ReplaceWithOriginal(callInstr, availableCopies, killSet);
        }
        else if(auto storeInstr = instr->As<StoreInstr>()) {
            AddToKillSet(storeInstr, killSet, copySet);
        }
        else if(auto loadInstr = instr->As<LoadInstr>()) {
            // Try to replace the operands with the original ones.
            ReplaceWithOriginal(loadInstr, availableCopies, killSet);
        }
    }
}