void FlowGraph::interposeBlock(BasicBlock* bb){
    ASSERT(bb->getNumberOfSources() == 1 && bb->getNumberOfTargets() == 1);
    BasicBlock* sourceBlock = bb->getSourceBlock(0);
    BasicBlock* targetBlock = bb->getTargetBlock(0);

    //sourceBlock->print();
    //targetBlock->print();

    bool linkFound = false;
    for (uint32_t i = 0; i < sourceBlock->getNumberOfTargets(); i++){
        if (sourceBlock->getTargetBlock(i)->getIndex() == targetBlock->getIndex()){
            linkFound = true;
            break;
        }
    }

    if (!linkFound){
        function->print();
        print();
        sourceBlock->print();
        targetBlock->print();        
    }

    ASSERT(linkFound && "There should be a source -> target block relationship between the blocks passed to this function");

    ASSERT(sourceBlock->getBaseAddress() + sourceBlock->getNumberOfBytes() != targetBlock->getBaseAddress() && "Source shouldn't fall through to target");

    bb->setBaseAddress(blocks.back()->getBaseAddress() + blocks.back()->getNumberOfBytes());
    bb->setIndex(basicBlocks.size());
    basicBlocks.append(bb);

    //PRINT_INFOR("now there are %d bbs in function %s", basicBlocks.size(), function->getName());
    //PRINT_INFOR("new block has base addres %#llx", bb->getBaseAddress());
    blocks.append(bb);

    sourceBlock->removeTargetBlock(targetBlock);
    sourceBlock->addTargetBlock(bb);
    targetBlock->removeSourceBlock(sourceBlock);
    targetBlock->addSourceBlock(bb);

    X86Instruction* jumpToTarget = bb->getLeader();
    jumpToTarget->setBaseAddress(blocks.back()->getBaseAddress() + blocks.back()->getSizeInBytes());
    jumpToTarget->setIndex(0);

    ASSERT(sourceBlock->getExitInstruction());
    ASSERT(sourceBlock->getExitInstruction()->getAddressAnchor());
    ASSERT(sourceBlock->getExitInstruction()->getTargetAddress() == targetBlock->getBaseAddress());
    sourceBlock->getExitInstruction()->getAddressAnchor()->updateLink(jumpToTarget);

    //bb->print();
    //bb->printInstructions();
}
void LengauerTarjan::immediateDominators(){

    uint32_t dfsNo = 0;
    depthFirstSearch(rootLoc,&dfsNo);

    size[0]  = 0;
    label[0] = 0;
    semi[0]  = 0;

    for(int32_t i=reachableCount;i>1;i--){
        uint32_t vertexW =  vertex[i];

        BasicBlock* bb = locToBasicBlock[vertexW];
        ASSERT(bb && "Basic Block should be initialized");
        uint32_t numberOfSources = bb->getNumberOfSources();

        for(uint32_t j=0;j<numberOfSources;j++){
            BasicBlock* source = bb->getSourceBlock(j);
            if(!source->isUnreachable()){
                uint32_t vertexV = basicBlockToLoc[source->getIndex()];
                uint32_t vertexU = EVAL(vertexV);
                if(semi[vertexU] < semi[vertexW]){
                    semi[vertexW] = semi[vertexU];
                }
            }
        }

        bucket[vertex[semi[vertexW]]].insert(vertexW);

        LINK(parent[vertexW],vertexW);

        LinkedList<uint32_t>* bs = &(bucket[parent[vertexW]]);
        while(!bs->empty()){
            uint32_t vertexV = bs->shift();
            uint32_t vertexU = EVAL(vertexV);
            dom[vertexV] = ( semi[vertexU] < semi[vertexV] ) ? vertexU : parent[vertexW];
        }
    }
    for(uint32_t i=2;i<=reachableCount;i++){
        uint32_t vertexW = vertex[i];
        if(dom[vertexW] != vertex[semi[vertexW]]){
            dom[vertexW] = dom[dom[vertexW]];
        }
    }

    dom[rootLoc] = 0;
    PRINT_DEBUG("ROOT is %d",rootLoc);

    for(uint32_t i=1;i<=reachableCount;i++){
        uint32_t vertexW = vertex[i];
        BasicBlock* bb = locToBasicBlock[vertexW];
        ASSERT(!bb->isUnreachable());
        BasicBlock* immDom = locToBasicBlock[dom[vertexW]];
        if(immDom){
            PRINT_DEBUG("Reachable : Immediate Dominator of %d is %d",bb->getIndex(),immDom->getIndex());
            bb->setImmDominator(immDom);
        } else {
            PRINT_DEBUG("Reachable : Immediate Dominator of %d is Entry",bb->getIndex());
        }
    }
    for(int32_t i=nodeCount;i>reachableCount;i--){
        BasicBlock* bb = locToBasicBlock[i];
        ASSERT(bb->isUnreachable());
        BasicBlock* immDom = locToBasicBlock[rootLoc];
        PRINT_DEBUG("Un-Reachable : Immediate Dominator of %d is %d",bb->getIndex(),immDom->getIndex());
        bb->setImmDominator(immDom);
    }
}
void LengauerTarjan::depthFirstSearch(uint32_t vertexV,uint32_t* dfsNo){

    semi[vertexV]     = ++(*dfsNo);
    vertex[*dfsNo]    = vertexV;

    label[vertexV]    = vertexV;
    ancestor[vertexV] = 0;
    child[vertexV]    = 0;
    size[vertexV]     = 1;

    BasicBlock* bb = locToBasicBlock[vertexV];

    PRINT_DEBUG_CFG("Mark %d with %d (vertex[%d] = %d)",bb->getIndex(),*dfsNo,*dfsNo,vertexV);

    uint32_t numberOfTargets = bb->getNumberOfTargets();
    for(uint32_t i=0;i<numberOfTargets;i++){
        BasicBlock* target = bb->getTargetBlock(i);
        uint32_t vertexW = basicBlockToLoc[target->getIndex()];
        if(semi[vertexW] == 0){
            parent[vertexW] = vertexV;
            depthFirstSearch(vertexW,dfsNo);
        }
    }
    ASSERT(!bb->isUnreachable());

#if 0
    LinkedList<uint32_t> searchStack; 
    searchStack.insert(vertexV);

    while(!searchStack.empty()){

        vertexV           = searchStack.shift();

        if(semi[vertexV] != 0){
            continue;
        }

        semi[vertexV]     = ++(*dfsNo);
        vertex[*dfsNo]    = vertexV;

        label[vertexV]    = vertexV;
        ancestor[vertexV] = 0;
        child[vertexV]    = 0;
        size[vertexV]     = 1;

        BasicBlock* bb = locToBasicBlock[vertexV];
        ASSERT(!bb->isUnreachable());
        uint32_t numberOfTargets = bb->getNumberOfTargets();
//        for(int32_t i=numberOfTargets-1;i>=0;i--){
        for(uint32_t i=0;i<numberOfTargets;i++){
            BasicBlock* target = bb->getTargetBlock(i);
            uint32_t vertexW = basicBlockToLoc[target->getIndex()];
            if(semi[vertexW] == 0){
                parent[vertexW] = vertexV;
                searchStack.insert(vertexW);
            }
        }
        PRINT_DEBUG("Mark %d with %d\n",bb->getIndex(),*dfsNo);
        ASSERT(!bb->isUnreachable());
    }
#endif
}
void TauFunctionTrace::instrument(){
    //InstrumentationTool::instrument();

    LineInfoFinder* lineInfoFinder = NULL;
    if (hasLineInformation()){
        lineInfoFinder = getLineInfoFinder();
    }

    InstrumentationPoint* p;

    uint64_t nameAddr = reserveDataOffset(sizeof(uint64_t));
    uint64_t fileAddr = reserveDataOffset(sizeof(uint64_t));
    uint64_t lineAddr = reserveDataOffset(sizeof(uint32_t));
    uint64_t siteIndexAddr = reserveDataOffset(sizeof(uint32_t));

    uint32_t site = functionEntry->addConstantArgument();
    ASSERT(site == functionExit->addConstantArgument());

    std::pebil_map_type<uint64_t, ControlInfo> functions;
    std::vector<uint64_t> orderedfuncs;

    uint32_t sequenceId = 0;
    if (doIntro){
        // go over all functions and intrument entries/exits
        for (uint32_t i = 0; i < getNumberOfExposedFunctions(); i++){
            Function* function = getExposedFunction(i);
            uint64_t addr = function->getBaseAddress();
            if (instrumentList && !instrumentList->functionMatches(function->getName())){
                continue;
            }
            if (!strcmp(function->getName(), "_fini")){
                continue;
            }

            BasicBlock* entryBlock = function->getFlowGraph()->getEntryBlock();
            Vector<BasicBlock*>* exitPoints = function->getFlowGraph()->getExitBlocks();

            std::string c;
            c.append(function->getName());
            if (c == "_start"){
                exitPoints->append(getProgramExitBlock());
                PRINT_INFOR("Special case: inserting exit for _start inside _fini since control generally doesn't reach its exit");
            }

            ASSERT(functions.count(addr) == 0 && "Multiple functions have the same base address?");

            PRINT_INFOR("[FUNCTION index=%d] internal instrumentation: %s", sequenceId, function->getName());

            ControlInfo f = ControlInfo();
            f.name = c;
            f.file = "";
            f.line = 0;
            f.index = sequenceId++;
            f.baseaddr = addr;
            f.type = ControlType_Function;

            LineInfo* li = NULL;
            if (lineInfoFinder){
                li = lineInfoFinder->lookupLineInfo(addr);
            }

            if (li){
                f.file.append(li->getFileName());
                f.line = li->GET(lr_line);
            }

            functions[addr] = f;
            orderedfuncs.push_back(addr);

            InstrumentationPoint* prior = addInstrumentationPoint(entryBlock->getLeader(), functionEntry, InstrumentationMode_tramp, InstLocation_prior);
            prior->setPriority(InstPriority_custom3);
            assignStoragePrior(prior, f.index, site);

            for (uint32_t j = 0; j < exitPoints->size(); j++){
                InstrumentationPoint* after = addInstrumentationPoint((*exitPoints)[j]->getExitInstruction(), functionExit, InstrumentationMode_tramp, InstLocation_prior);
                after->setPriority(InstPriority_custom5);

                if (c == "_start" && j == exitPoints->size() - 1){
                    after->setPriority(InstPriority_custom6);
                }
                assignStoragePrior(after, f.index, site);
            }

            delete exitPoints;
        }

    } else {
        // go over all instructions. when we find a call, instrument it
        for (uint32_t i = 0; i < getNumberOfExposedInstructions(); i++){
            X86Instruction* x = getExposedInstruction(i);
            ASSERT(x->getContainer()->isFunction());
            Function* function = (Function*)x->getContainer();

            if (x->isFunctionCall()){
                uint64_t addr = x->getTargetAddress();
                Symbol* functionSymbol = getElfFile()->lookupFunctionSymbol(addr);
            
                if (functionSymbol){

                    if (instrumentList && !instrumentList->functionMatches(functionSymbol->getSymbolName())){
                        continue;
                    }
                    ASSERT(x->getSizeInBytes() == Size__uncond_jump);
                
                    std::string c;
                    c.append(functionSymbol->getSymbolName());
                    if (functions.count(addr) == 0){
                        PRINT_INFOR("[FUNCTION index=%d] call site instrumentation: %#lx(%s) -> %s", sequenceId, addr, function->getName(), functionSymbol->getSymbolName());

                        ControlInfo f = ControlInfo();
                        f.name = c;
                        f.file = "";
                        f.line = 0;
                        f.index = sequenceId++;
                        f.baseaddr = addr;
                        f.type = ControlType_Function;

                        LineInfo* li = NULL;
                        if (lineInfoFinder){
                            li = lineInfoFinder->lookupLineInfo(addr);
                        }

                        if (li){
                            f.file.append(li->getFileName());
                            f.line = li->GET(lr_line);
                        }

                        functions[addr] = f;
                        orderedfuncs.push_back(addr);
                    }
                    uint32_t idx = functions[addr].index;

                    Base* exitpoint = (Base*)x;
                    if (c == "__libc_start_main"){
                        PRINT_INFOR("Special case: inserting exit for __libc_start_main inside _fini since this call generally doesn't return");
                        exitpoint = (Base*)getProgramExitBlock();
                    }

                    InstrumentationPoint* prior = addInstrumentationPoint(x, functionEntry, InstrumentationMode_tramp, InstLocation_prior);
                    InstrumentationPoint* after = addInstrumentationPoint(exitpoint, functionExit, InstrumentationMode_tramp, InstLocation_after);

                    assignStoragePrior(prior, idx, site);
                    assignStoragePrior(after, idx, site);
                }
            }
        }
    }


    // set up argument passing for function registration
    functionRegister->addArgument(nameAddr);
    functionRegister->addArgument(fileAddr);
    functionRegister->addArgument(lineAddr);
    uint32_t siteReg = functionRegister->addConstantArgument();


    // go over every function that was found, insert a registration call at program start
    for (std::vector<uint64_t>::iterator it = orderedfuncs.begin(); it != orderedfuncs.end(); it++){
        uint64_t addr = *it;
        ControlInfo f = functions[addr];
       
        ASSERT(f.baseaddr == addr);

        InstrumentationPoint* p = addInstrumentationPoint(getProgramEntryBlock(), functionRegister, InstrumentationMode_tramp);
        p->setPriority(InstPriority_custom1);

        const char* cstring = f.name.c_str();
        uint64_t storage = reserveDataOffset(strlen(cstring) + 1);
        initializeReservedData(getInstDataAddress() + storage, strlen(cstring), (void*)cstring);
        assignStoragePrior(p, getInstDataAddress() + storage, getInstDataAddress() + nameAddr, X86_REG_CX, getInstDataAddress() + getRegStorageOffset());

        const char* cstring2 = f.file.c_str();
        if (f.file == ""){
            assignStoragePrior(p, NULL, getInstDataAddress() + fileAddr, X86_REG_CX, getInstDataAddress() + getRegStorageOffset());            
        } else {
            storage = reserveDataOffset(strlen(cstring2) + 1);
            initializeReservedData(getInstDataAddress() + storage, strlen(cstring2), (void*)cstring2);
            assignStoragePrior(p, getInstDataAddress() + storage, getInstDataAddress() + fileAddr, X86_REG_CX, getInstDataAddress() + getRegStorageOffset());
        }

        assignStoragePrior(p, f.line, getInstDataAddress() + lineAddr, X86_REG_CX, getInstDataAddress() + getRegStorageOffset());
        assignStoragePrior(p, f.index, siteReg);
    }


    if (!instrumentList){
        return;
    }

    // instrument loops
    std::pebil_map_type<uint64_t, ControlInfo> loops;
    std::vector<uint64_t> orderedloops;

    loopRegister->addArgument(nameAddr);
    loopRegister->addArgument(fileAddr);
    loopRegister->addArgument(lineAddr);
    ASSERT(siteReg == loopRegister->addConstantArgument());

    for (uint32_t i = 0; i < getNumberOfExposedFunctions(); i++){
        Function* function = getExposedFunction(i);
        FlowGraph* flowgraph = function->getFlowGraph();

        if (!instrumentList->loopMatches(function->getName())){
            continue;
        }

        for (uint32_t j = 0; j < flowgraph->getNumberOfLoops(); j++){
            Loop* loop = flowgraph->getLoop(j);
            uint32_t depth = flowgraph->getLoopDepth(loop);
            BasicBlock* head = loop->getHead();
            uint64_t addr = head->getBaseAddress();

            // only want outer-most (depth == 1) loops
            if (depth != 1){
                continue;
            }

            BasicBlock** allLoopBlocks = new BasicBlock*[loop->getNumberOfBlocks()];
            loop->getAllBlocks(allLoopBlocks);

            // reject any loop that contains an indirect branch since it is difficult to guarantee that we will find all exits
            bool badLoop = false;
            for (uint32_t k = 0; k < loop->getNumberOfBlocks() && !badLoop; k++){
                BasicBlock* bb = allLoopBlocks[k];
                if (bb->getExitInstruction()->isIndirectBranch()){
                    badLoop = true;
                }
            }

            if (badLoop){
                PRINT_WARN(20, "Loop at %#lx in %s contains an indirect branch so we can't guarantee that all exits will be found. skipping!", addr, function->getName());
                delete[] allLoopBlocks;
                continue;
            }

            std::string c;
            c.append(function->getName());

            uint32_t entryc = 0;

            Vector<LoopPoint*>* points = NULL;

            // if addr already exists, it means that two loops share a head and we are going to merge them logically here
            if (loops.count(addr) == 0){

                ControlInfo f = ControlInfo();
                f.name = c;
                f.file = "";
                f.line = 0;
                f.index = sequenceId++;
                f.baseaddr = addr;
                f.type = ControlType_Loop;

                points = new Vector<LoopPoint*>();
                f.info = points;

                LineInfo* li = NULL;
                if (lineInfoFinder){
                    li = lineInfoFinder->lookupLineInfo(addr);
                }
                if (li){
                    f.file.append(li->getFileName());
                    f.line = li->GET(lr_line);
                }

                loops[addr] = f;
                orderedloops.push_back(addr);

                // find entries into this loop
                for (uint32_t k = 0; k < head->getNumberOfSources(); k++){
                    BasicBlock* source = head->getSourceBlock(k);

                    if (!loop->isBlockIn(source->getIndex())){
                        LoopPoint* lp = new LoopPoint();
                        points->append(lp);

                        lp->flowgraph = flowgraph;
                        lp->source = source;
                        lp->target = NULL;
                        lp->entry = true;
                        lp->interpose = false;

                        if (source->getBaseAddress() + source->getNumberOfBytes() != head->getBaseAddress()){
                            lp->interpose = true;
                            lp->target = head;
                        }
                        entryc++;
                    }
                }
            }

            ControlInfo f = loops[addr];
            points = f.info;

            // find exits from this loop
            uint32_t exitc = 0;
            for (uint32_t k = 0; k < loop->getNumberOfBlocks(); k++){
                BasicBlock* bb = allLoopBlocks[k];
                if (bb->endsWithReturn()){
                    LoopPoint* lp = new LoopPoint();
                    points->append(lp);

                    lp->flowgraph = flowgraph;
                    lp->source = bb;
                    lp->target = NULL;
                    lp->entry = false;
                    lp->interpose = false;
                    exitc++;
                }

                for (uint32_t m = 0; m < bb->getNumberOfTargets(); m++){
                    BasicBlock* target = bb->getTargetBlock(m);
                    if (!loop->isBlockIn(target->getIndex())){
                        LoopPoint* lp = new LoopPoint();
                        points->append(lp);

                        lp->flowgraph = flowgraph;
                        lp->source = bb;
                        lp->target = NULL;
                        lp->entry = false;
                        lp->interpose = false;

                        if (target->getBaseAddress() != bb->getBaseAddress() + bb->getNumberOfBytes()){
                            lp->interpose = true;
                            lp->target = target;
                        }
                        exitc++;
                    }
                }
            }

            PRINT_INFOR("[LOOP index=%d] loop instrumentation %#lx(%s) has %d entries and %d exits", sequenceId-1, addr, function->getName(), entryc, exitc);

            delete[] allLoopBlocks;
        }
    }

    // go over every loop that was found, insert a registration call at program start
    // [source_addr -> [target_addr -> interposed]]
    std::pebil_map_type<uint64_t, std::pebil_map_type<uint64_t, BasicBlock*> > idone;
    for (std::vector<uint64_t>::iterator it = orderedloops.begin(); it != orderedloops.end(); it++){
        uint64_t addr = *it;
        ControlInfo f = loops[addr];
       
        ASSERT(f.baseaddr == addr);

        InstrumentationPoint* p = addInstrumentationPoint(getProgramEntryBlock(), loopRegister, InstrumentationMode_tramp);
        p->setPriority(InstPriority_custom2);

        const char* cstring = f.name.c_str();
        uint64_t storage = reserveDataOffset(strlen(cstring) + 1);
        initializeReservedData(getInstDataAddress() + storage, strlen(cstring), (void*)cstring);
        assignStoragePrior(p, getInstDataAddress() + storage, getInstDataAddress() + nameAddr, X86_REG_CX, getInstDataAddress() + getRegStorageOffset());

        const char* cstring2 = f.file.c_str();
        if (f.file == ""){
            assignStoragePrior(p, NULL, getInstDataAddress() + fileAddr, X86_REG_CX, getInstDataAddress() + getRegStorageOffset());            
        } else {
            storage = reserveDataOffset(strlen(cstring2) + 1);
            initializeReservedData(getInstDataAddress() + storage, strlen(cstring2), (void*)cstring2);
            assignStoragePrior(p, getInstDataAddress() + storage, getInstDataAddress() + fileAddr, X86_REG_CX, getInstDataAddress() + getRegStorageOffset());
        }

        assignStoragePrior(p, f.line, getInstDataAddress() + lineAddr, X86_REG_CX, getInstDataAddress() + getRegStorageOffset());
        assignStoragePrior(p, f.index, siteReg);

        // now add instrumentation for each loop entry/exit
        Vector<LoopPoint*>* v = (Vector<LoopPoint*>*)f.info;
        for (uint32_t i = 0; i < v->size(); i++){
            LoopPoint* lp = (*v)[i];
            ASSERT(lp->flowgraph && lp->source);

            BasicBlock* bb = lp->source;
            if (lp->interpose){
                ASSERT(lp->target);
                if (idone.count(lp->source->getBaseAddress()) == 0){
                    idone[lp->source->getBaseAddress()] = std::pebil_map_type<uint64_t, BasicBlock*>();
                }
                if (idone[lp->source->getBaseAddress()].count(lp->target->getBaseAddress()) == 0){
                    idone[lp->source->getBaseAddress()][lp->target->getBaseAddress()] = initInterposeBlock(lp->flowgraph, lp->source->getIndex(), lp->target->getIndex());
                }

                bb = idone[lp->source->getBaseAddress()][lp->target->getBaseAddress()];

            } else {
                ASSERT(lp->target == NULL);
            }

            Base* pt = (Base*)bb;
            InstLocations loc = InstLocation_prior;

            // if exit block falls through, we must place the instrumentation point at the very end of the block
            if (!lp->entry && !lp->interpose){
                pt = (Base*)bb->getExitInstruction();
                if (!bb->getExitInstruction()->isReturn()){
                    loc = InstLocation_after;
                }
            }

            InstrumentationFunction* inf = functionExit;
            if (lp->entry){
                inf = functionEntry;
            }

            InstrumentationPoint* p = addInstrumentationPoint(pt, inf, InstrumentationMode_tramp, loc);
            p->setPriority(InstPriority_custom4);
            assignStoragePrior(p, f.index, site);

            delete lp;
        }
        delete v;
    }

}
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;
    }
}