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