void FlowGraph::computeDefUseDist(){
    uint32_t fcnt = function->getNumberOfInstructions();
    std::pebil_map_type<uint64_t, X86Instruction*> imap;
    std::pebil_map_type<uint64_t, BasicBlock*> bmap;
    std::pebil_map_type<uint64_t, LinkedList<X86Instruction::ReachingDefinition*>*> alliuses;
    std::pebil_map_type<uint64_t, LinkedList<X86Instruction::ReachingDefinition*>*> allidefs;

    for (uint32_t i = 0; i < basicBlocks.size(); i++){
        BasicBlock* bb = basicBlocks[i];
        for (uint32_t j = 0; j < bb->getNumberOfInstructions(); j++){
            X86Instruction* x = bb->getInstruction(j);
            for (uint32_t k = 0; k < x->getSizeInBytes(); k++){
                ASSERT(imap.count(x->getBaseAddress() + k) == 0);
                ASSERT(bmap.count(x->getBaseAddress() + k) == 0);
                imap[x->getBaseAddress() + k] = x;
                bmap[x->getBaseAddress() + k] = bb;
            }

            ASSERT(alliuses.count(x->getBaseAddress()) == 0);
            ASSERT(allidefs.count(x->getBaseAddress()) == 0);
            alliuses[x->getBaseAddress()] = x->getUses();
            allidefs[x->getBaseAddress()] = x->getDefs();
        }
    }

    // For each loop
    for (uint32_t i = 0; i < loops.size(); ++i) {
        BasicBlock** allLoopBlocks = new BasicBlock*[loops[i]->getNumberOfBlocks()];
        loops[i]->getAllBlocks(allLoopBlocks);
        uint64_t loopLeader = loops[i]->getHead()->getBaseAddress();
        // For each block
        for (uint32_t j = 0; j < loops[i]->getNumberOfBlocks(); ++j){
            BasicBlock* bb = allLoopBlocks[j];

            // For each instruction
            for (uint32_t k = 0; k < bb->getNumberOfInstructions(); ++k){
                X86Instruction* ins = bb->getInstruction(k);

                // Skip the instruction if it can't define anything
                if (!ins->isIntegerOperation() && !ins->isFloatPOperation() && !ins->isMoveOperation()) {
                    continue;
                }
                ASSERT(!ins->usesControlTarget());

                singleDefUse(this, ins, bb, loops[i], imap, bmap, alliuses, allidefs, k, loopLeader, fcnt);
            }
        }
        delete[] allLoopBlocks;
    }

    // handle all non-loop blocks
    for (uint32_t i = 0; i < getNumberOfBasicBlocks(); i++){
        BasicBlock* bb = basicBlocks[i];
        if (!isBlockInLoop(bb->getIndex())){
            for (uint32_t k = 0; k < bb->getNumberOfInstructions(); ++k){
                X86Instruction* ins = bb->getInstruction(k);
                
                if (!ins->isIntegerOperation() && !ins->isFloatPOperation() && !ins->isMoveOperation()) {
                    continue;
                }
                ASSERT(!ins->usesControlTarget());
                
                singleDefUse(this, ins, bb, NULL, imap, bmap, alliuses, allidefs, k, 0, fcnt);
            }
        }
    }

    for (uint32_t i = 0; i < basicBlocks.size(); i++){

        BasicBlock* bb = basicBlocks[i];
        for (uint32_t j = 0; j < bb->getNumberOfInstructions(); j++){

            X86Instruction* x = bb->getInstruction(j);
            uint64_t addr = x->getBaseAddress();

            ASSERT(alliuses.count(addr) == 1);
            LinkedList<X86Instruction::ReachingDefinition*>* l = alliuses[addr];
            alliuses.erase(addr);
            while (!l->empty()){
                delete l->shift();
            }
            delete l;

            ASSERT(allidefs.count(addr) == 1);
            l = allidefs[addr];
            allidefs.erase(addr);
            while (!l->empty()){
                delete l->shift();
            }
            delete l;
        }
    }

    ASSERT(alliuses.size() == 0);
    ASSERT(allidefs.size() == 0);
}
inline void singleDefUse(FlowGraph* fg, X86Instruction* ins, BasicBlock* bb, Loop* loop,
                         std::pebil_map_type<uint64_t, X86Instruction*>& ipebil_map_type,
                         std::pebil_map_type<uint64_t, BasicBlock*>& bpebil_map_type,
                         std::pebil_map_type<uint64_t, LinkedList<X86Instruction::ReachingDefinition*>*>& alliuses,
                         std::pebil_map_type<uint64_t, LinkedList<X86Instruction::ReachingDefinition*>*>& allidefs,
                         int k, uint64_t loopLeader, uint32_t fcnt){

    // Get defintions for this instruction: ins
    LinkedList<X86Instruction::ReachingDefinition*>* idefs = ins->getDefs();
    LinkedList<X86Instruction::ReachingDefinition*>* allDefs = idefs;

    // Skip instruction if it doesn't define anything
    if (idefs == NULL) {
        return;
    }

    if (idefs->empty()) {
        delete idefs;
        return;
    }

    set<LinkedList<X86Instruction::ReachingDefinition*>*> allDefLists;
    allDefLists.insert(idefs);

    PriorityQueue<struct path*, uint32_t> paths = PriorityQueue<struct path*, uint32_t>();
    bool blockTouched[fg->getFunction()->getNumberOfBasicBlocks()];
    bzero(&blockTouched, sizeof(bool) * fg->getFunction()->getNumberOfBasicBlocks());

    // Initialize worklist with the path from this instruction
    // Only take paths inside the loop. Since the definitions are in a loop, uses in the loop will be most relevant.
    if (k == bb->getNumberOfInstructions() - 1){
        ASSERT(ins->controlFallsThrough());
        if (bb->getNumberOfTargets() > 0){
            ASSERT(bb->getNumberOfTargets() == 1);
            if (flowsInDefUseScope(bb->getTargetBlock(0), loop)){
                // Path flows to the first instruction of the next block
                paths.insert(new path(bb->getTargetBlock(0)->getLeader(), idefs), 1);
            } 
        }
    } else {
        // path flows to the next instruction in this block
        paths.insert(new path(bb->getInstruction(k+1), idefs), 1);
    }

    // while there are paths in worklist
    while (!paths.isEmpty()) {

        // take the shortest path in list
        uint32_t currDist;
        struct path* p = paths.deleteMin(&currDist);
        X86Instruction* cand = p->ins;
        idefs = p->defs;
        delete p;

        LinkedList<X86Instruction::ReachingDefinition*>* i2uses, *i2defs, *newdefs;
        i2uses = alliuses[cand->getBaseAddress()];

        // Check if any of idefs is used
        if(i2uses != NULL && anyDefsAreUsed(idefs, i2uses)){

            // Check if use is shortest
            uint32_t duDist;
            duDist = trueDefUseDist(currDist, fcnt);
            if (!ins->getDefUseDist() || ins->getDefUseDist() > duDist) {
                ins->setDefUseDist(duDist);
            }

            // If dist has increased beyond size of function, we must be looping?
            if (currDist > fcnt) {
                ins->setDefXIter();
                break;
            }

            // Stop searching along this path
            continue;
        }

        // Check if any defines are overwritten
        i2defs = allidefs[cand->getBaseAddress()];
        newdefs = removeInvalidated(idefs, i2defs);

        // If all definitions killed, stop searching along this path
        if (newdefs == NULL)
            continue;

        allDefLists.insert(newdefs);

        // end of block that is a branch
        if (cand->usesControlTarget() && !cand->isCall()){
            BasicBlock* tgtBlock = bpebil_map_type[cand->getTargetAddress()];
            if (tgtBlock && !blockTouched[tgtBlock->getIndex()] && flowsInDefUseScope(tgtBlock, loop)){
                blockTouched[tgtBlock->getIndex()] = true;
                if (tgtBlock->getBaseAddress() == loopLeader){
                    paths.insert(new path(tgtBlock->getLeader(), newdefs), loopXDefUseDist(currDist + 1, fcnt));
                } else {
                    paths.insert(new path(tgtBlock->getLeader(), newdefs), currDist + 1);
                }
            }
        }

        // non-branching control
        if (cand->controlFallsThrough()){
            BasicBlock* tgtBlock = bpebil_map_type[cand->getBaseAddress() + cand->getSizeInBytes()];
            if (tgtBlock && flowsInDefUseScope(tgtBlock, loop)){
                X86Instruction* ftTarget = ipebil_map_type[cand->getBaseAddress() + cand->getSizeInBytes()];
                if (ftTarget){
                    if (ftTarget->isLeader()){
                        if (!blockTouched[tgtBlock->getIndex()]){
                            blockTouched[tgtBlock->getIndex()] = true;
                            if (ftTarget->getBaseAddress() == loopLeader){
                                paths.insert(new path(ftTarget, newdefs), loopXDefUseDist(currDist + 1, fcnt));
                            } else {
                                paths.insert(new path(ftTarget, newdefs), currDist + 1);
                            }
                        }
                    } else {
                        paths.insert(new path(ftTarget, newdefs), currDist + 1);
                    }
                }
            }
        }
        
    }
    if (!paths.isEmpty()){
        ins->setDefUseDist(0);
    }
    while (!paths.isEmpty()){
        delete paths.deleteMin(NULL);
    }

    while (!allDefs->empty()){
        delete allDefs->shift();
    }
    for(set<LinkedList<X86Instruction::ReachingDefinition*>*>::iterator it = allDefLists.begin(); it != allDefLists.end(); ++it){
        delete *it;
    }
}