void LoopReductor::processWorkSpace(otawa::WorkSpace *fw) { int idx = 0; const CFGCollection *orig_coll = INVOLVED_CFGS(fw); if (reduce_loops) { for (CFGCollection::Iterator cfg(*orig_coll); cfg; cfg++) { VirtualCFG *vcfg = new VirtualCFG(false); if (ENTRY_CFG(fw) == *cfg) ENTRY_CFG(fw) = vcfg; vcfgvec.add(vcfg); INDEX(vcfg) = INDEX(cfg); LABEL(vcfg) = LABEL(cfg); ENTRY(vcfg->entry()) = vcfg; } int i = 0; for (CFGCollection::Iterator cfg(*orig_coll); cfg; cfg++, i++) { VirtualCFG *vcfg = vcfgvec.get(i); idx = 0; INDEX(vcfg->entry()) = idx; vcfg->addBB(vcfg->entry()); idx++; reduce(vcfg, cfg); INDEX(vcfg->exit()) = idx; vcfg->addBB(vcfg->exit()); /* Renum basic blocks */ idx = 0; for (CFG::BBIterator bb(vcfg); bb; bb++) { INDEX(bb) = idx; idx++; } } INVOLVED_CFGS(fw) = NULL; } else { for (CFGCollection::Iterator cfg(*orig_coll); cfg; cfg++) { Vector<BasicBlock*> *ancestors = new Vector<BasicBlock*>(); for (CFG::BBIterator bb(cfg); bb; bb++) { IN_LOOPS(bb) = new dfa::BitSet(cfg->countBB()); } /* Do the Depth-First Search, compute the ancestors sets, and mark loop headers */ depthFirstSearch(cfg->entry(), ancestors); delete ancestors; } } }
CacheListener(WorkSpace *ws, Problem& prob, int set, Identifier<typename P::Domain *>& id) : _prob(prob), _set(set), _id(id) { const CFGCollection *col = INVOLVED_CFGS(ws); for(int i = 0; i < col->count(); i++) for (CFG::BBIterator bb(col->get(i)); bb; bb++) prob.init(_id(bb)[_set], prob.bottom()); }
void CATBuilder::cleanup(WorkSpace *ws) { static cstring cat_names[] = { "INV", "AH", "FH", "FM", "AM", "NC" }; if(!logFor(LOG_BB)) return; const CFGCollection *cfgs = INVOLVED_CFGS(ws); ASSERT(cfgs); for(int i = 0; i < cfgs->count(); i++) for(CFG::BBIterator bb(cfgs->get(i)); bb; bb++) { cerr << "\tBB " << bb->number() << " (" << bb->address() << ")\n"; Pair<int, BlockAccess *> ab = DATA_BLOCKS(bb); for(int j = 0; j < ab.fst; j++) { BlockAccess& b = ab.snd[j]; cerr << "\t\t" << b << " -> " << cat_names[dcache::CATEGORY(b)] << io::endl; } } }
void BBCleaner::clean(void) { const CFGCollection *coll = INVOLVED_CFGS(ws); ASSERT(coll); for(CFGCollection::Iterator cfg(coll); cfg; cfg++) for(CFG::BBIterator bb(cfg); bb; bb++) clean(ws, cfg, bb); }
void CFGProcessor::processWorkSpace(WorkSpace *fw) { // Get the CFG collection const CFGCollection *cfgs = INVOLVED_CFGS(fw); ASSERT(cfgs); // Visit CFG int count = 0; for(CFGCollection::Iterator cfg(cfgs); cfg; cfg++) { if(logFor(LOG_CFG)) log << "\tprocess CFG " << cfg->label() << io::endl; _cfg = cfg; processCFG(fw, cfg); count++; } // Record stats if(recordsStats()) PROCESSED_CFG(stats) = count; }
void BBSize::processWorkSpace(WorkSpace* ws) { const CFGCollection* cfgs = INVOLVED_CFGS(ws); ASSERT(cfgs); int totalSize = 0; int totalNum = 0; int totalMax = 0; for(CFGCollection::Iterator cfg(cfgs); cfg; cfg++) { int cfgSize = 0; int cfgNum = 0; int cfgMax = 0; for(CFG::BBIterator bb(cfg); bb; bb++) { if(bb->size() > 0) { cfgSize += bb->size(); cfgNum++; totalSize += bb->size(); totalNum++; if(bb->size() > cfgMax) cfgMax = bb->size(); if(bb->size() > totalMax) totalMax = bb->size(); } } elm::cout << "CFG " << cfg->label() << " avg " << ((float)cfgSize/(float)cfgNum) << " max " << cfgMax << elm::io::endl; } elm::cout << "PROG avg " << ((float)totalSize/(float)totalNum) << " max " << totalMax << elm::io::endl; }
void CATBuilder::cleanup(WorkSpace *ws) { static cstring cat_names[] = { "INV", "AH", "FH", "PE", "AM", "NC" }; if(!logFor(LOG_BB)) return; int stats[cache::NOT_CLASSIFIED + 1], total = 0; array::set(stats, NOT_CLASSIFIED + 1, 0); const CFGCollection *cfgs = INVOLVED_CFGS(ws); ASSERT(cfgs); for(int i = 0; i < cfgs->count(); i++) for(CFG::BBIterator bb(cfgs->get(i)); bb; bb++) { cerr << "\tBB " << bb->number() << " (" << bb->address() << ")\n"; Pair<int, BlockAccess *> ab = DATA_BLOCKS(bb); for(int j = 0; j < ab.fst; j++) { BlockAccess& b = ab.snd[j]; cerr << "\t\t" << b << " -> " << cat_names[dcache::CATEGORY(b)] << io::endl; stats[dcache::CATEGORY(b)]++; total++; } } if(logFor(LOG_FUN)) { for(int i = cache::ALWAYS_HIT; i <= cache::NOT_CLASSIFIED; i++) cerr << cat_names[i] << " : " << io::fmt(stats[i]).width(5).right() << " (" << io::fmt(double(stats[i] * 100) / total).width(5, 2).right() << "%)\n"; cerr << "total: " << total << io::endl; } }
void LoopUnroller::processWorkSpace(otawa::WorkSpace *fw) { int cfgidx = 0; const CFGCollection *orig_coll = INVOLVED_CFGS(fw); // Create the new VCFG collection first, so that it will be available when we do the loop unrolling for (CFGCollection::Iterator cfg(*orig_coll); cfg; cfg++, cfgidx++) { VirtualCFG *vcfg = new VirtualCFG(false); coll->add(vcfg); INDEX(vcfg) = cfgidx; vcfg->addBB(vcfg->entry()); } cfgidx = 0; for (CFGCollection::Iterator vcfg(*coll), cfg(*orig_coll); vcfg; vcfg++, cfg++) { ASSERT(INDEX(vcfg) == INDEX(cfg)); LABEL(vcfg) = cfg->label(); INDEX(vcfg->entry()) = 0; idx = 1; // if (isVerbose()) { cout << "Processing CFG: " << cfg->label() << "\n"; //} /* !!GRUIK!! Ca serait bien d'avoir une classe VCFGCollection */ VirtualCFG *casted_vcfg = static_cast<otawa::VirtualCFG*>((otawa::CFG*)vcfg); unroll((otawa::CFG*) cfg, 0, casted_vcfg); if (ENTRY_CFG(fw) == cfg) ENTRY_CFG(fw) = vcfg; casted_vcfg->addBB(vcfg->exit()); INDEX(vcfg->exit()) = idx; } }
void CATBuilder::processLBlockSet(WorkSpace *ws, const BlockCollection& coll, const hard::Cache *cache) { if(coll.count() == 0) return; // prepare problem int line = coll.cacheSet(); MUSTPERS prob(&coll, ws, cache); MUSTPERS::Domain dom = prob.bottom(); acs_stack_t empty_stack; if(logFor(LOG_FUN)) log << "\tSET " << line << io::endl; const CFGCollection *cfgs = INVOLVED_CFGS(ws); ASSERT(cfgs); for(int i = 0; i < cfgs->count(); i++) { if(logFor(LOG_BB)) log << "\t\tCFG " << cfgs->get(i) << io::endl; for(CFG::BBIterator bb(cfgs->get(i)); bb; bb++) { if(logFor(LOG_BB)) log << "\t\t\t" << *bb << io::endl; // get the input domain acs_table_t *ins = MUST_ACS(bb); prob.setMust(dom, *ins->get(line)); acs_table_t *pers = PERS_ACS(bb); bool has_pers = pers; if(!has_pers) prob.emptyPers(dom); else { acs_stack_t *stack; acs_stack_table_t *stack_table = LEVEL_PERS_ACS(bb); if(stack_table) stack = &stack_table->item(line); else stack = &empty_stack; prob.setPers(dom, *pers->get(line), *stack); } // explore the adresses Pair<int, BlockAccess *> ab = DATA_BLOCKS(bb); for(int j = 0; j < ab.fst; j++) { BlockAccess& b = ab.snd[j]; if(b.kind() != BlockAccess::BLOCK) { CATEGORY(b) = cache::NOT_CLASSIFIED; prob.ageAll(dom); } else if(b.block().set() == line) { // initialization bool done = false; CATEGORY(b) = cache::NOT_CLASSIFIED; ACS *may = 0; if(MAY_ACS(bb) != 0) may = MAY_ACS(bb)->get(line); // in MUST ? if(dom.getMust().contains(b.block().index())) CATEGORY(b) = cache::ALWAYS_HIT; // persistent ? else if(has_pers) { // find the initial header BasicBlock *header; if (LOOP_HEADER(bb)) header = bb; else header = ENCLOSING_LOOP_HEADER(bb); // look in the different levels for(int k = dom.getPers().length() - 1; k >= 0 && header; k--) { if(dom.getPers().isPersistent(b.block().index(), k)) { CATEGORY(b) = cache::FIRST_MISS; CATEGORY_HEADER(b) = header; done = true; break; } header = ENCLOSING_LOOP_HEADER(header); } } // out of MAY ? if(!done && may && !may->contains(b.block().index())) CATEGORY(b) = cache::ALWAYS_MISS; // update state prob.inject(dom, b.block().index()); } } } } }
/** * Trigger associated with CFG. For each CFG, perform a call to * @ref cleanupCFG() that may be customized by a subclass. */ void CFGProcessor::doCleanUp(void) { const CFGCollection *coll = INVOLVED_CFGS(workspace()); for(int i = 0; i < coll->count(); i++) cleanupCFG(workspace(), coll->get(i)); }
void Builder::processLBlockSet(WorkSpace *fw, otawa::ccg::LBlockSet *lbset) { ASSERT(fw); ASSERT(lbset); const hard::Cache *cache = hard::CACHE_CONFIGURATION(fw)->instCache(); // Create the CCG Collection *ccgs = Graph::GRAPHS(fw); if(!ccgs) { ccgs = new Collection(cache->rowCount()); fw->addProp(new DeletableProperty<Collection *>(Graph::GRAPHS, ccgs)); } Graph *ccg = new Graph; ccgs->ccgs[lbset->line()] = ccg; // Initialization for(LBlockSet::Iterator lblock(*lbset); lblock; lblock++) { Node *node = new Node(lblock); ccg->add(node); Graph::NODE(lblock) = node; } // Run the DFA Problem prob(lbset, lbset->count(), cache, fw); const CFGCollection *coll = INVOLVED_CFGS(fw); dfa::XCFGVisitor<Problem> visitor(*coll, prob); dfa::XIterativeDFA<dfa::XCFGVisitor<Problem> > engine(visitor); engine.process(); // Add the annotations from the DFA result for (CFGCollection::Iterator cfg(coll); cfg; cfg++) { for (CFG::BBIterator block(*cfg); block; block++) { dfa::XCFGVisitor<Problem>::key_t pair(*cfg, *block); dfa::BitSet *bitset = engine.in(pair); block->addProp(new DeletableProperty<dfa::BitSet *>(IN, new dfa::BitSet(*bitset))); } } // Detecting the non conflict state of each lblock BasicBlock *BB; LBlock *line; int length = lbset->count(); for(LBlockSet::Iterator lbloc(*lbset); lbloc; lbloc++) if(lbloc->id() != 0 && lbloc->id() != length - 1) { BB = lbloc->bb(); dfa::BitSet *inid = IN(BB); for(dfa::BitSet::Iterator bit(*inid); bit; bit++) line = lbset->lblock(*bit); if(cache->block(line->address()) == cache->block(lbloc->address()) && BB != line->bb()) NON_CONFLICT(lbloc) = true; } // Building the ccg edges using DFA length = lbset->count(); address_t adinst; LBlock *aux; for (CFGCollection::Iterator cfg(coll); cfg; cfg++) { for (CFG::BBIterator bb(*cfg); bb; bb++) { if ((cfg != ENTRY_CFG(fw)) || (!bb->isEntry() && !bb->isExit())) { dfa::BitSet *info = IN(bb); ASSERT(info); bool test = false; bool visit; for(BasicBlock::InstIter inst(bb); inst; inst++) { visit = false; adinst = inst->address(); for (LBlockSet::Iterator lbloc(*lbset); lbloc; lbloc++){ address_t address = lbloc->address(); // the first lblock in the BB it's a conflict if(adinst == address && !test && bb == lbloc->bb()) { for (int i = 0; i< length; i++) if (info->contains(i)) { LBlock *lblock = lbset->lblock(i); Node *node = Graph::NODE(lblock); new Edge (node, Graph::NODE(lbloc)); } aux = lbloc; test = true; visit = true; break; } if(adinst == address && !visit && bb == lbloc->bb()) { new Edge(Graph::NODE(aux), Graph::NODE(lbloc)); aux = lbloc; break; } } } } } } // build edge to LBlock end BasicBlock *exit = ENTRY_CFG(fw)->exit(); LBlock *end = lbset->lblock(length-1); dfa::BitSet *info = IN(exit); for (int i = 0; i< length; i++) if (info->contains(i)) { LBlock *ccgnode1 = lbset->lblock(i); new Edge(Graph::NODE(ccgnode1), Graph::NODE(end)); } // Build edge from 'S' till 'end' LBlock *s = lbset->lblock(0); new Edge(Graph::NODE(s), Graph::NODE(end)); // Cleanup the DFA annotations for (CFGCollection::Iterator cfg(coll); cfg; cfg++) for (CFG::BBIterator block(cfg); block; block++) block->removeProp(&IN); }
void LoopUnroller::cleanup(WorkSpace *ws) { INVOLVED_CFGS(ws) = coll; ENTRY_CFG(ws) = coll->get(0); }