/**
 * Build a new context tree for the given CFG.
 * @param cfg		CFG to build the context tree for.
 * @param parent	Parent context tree.
 * @param _inline	If true, inline the call BB.
 */
ContextTree::ContextTree(CFG *cfg, ContextTree *parent, bool _inline):
	_kind(ROOT),
	_bb(cfg->entry()),
	_cfg(cfg),
	_parent(parent)
{
	ASSERT(cfg);
	TRACE("Computing " << cfg->label());
	
	/*
	 * First, create a ContextTree for each loop.
	 */
	for (CFG::BBIterator bb(cfg); bb; bb++)
		if (LOOP_HEADER(bb)) {
			OWNER_CONTEXT_TREE(bb) = new ContextTree(bb, cfg, this);
			OWNER_CONTEXT_TREE(bb)->addBB(bb, _inline);
		}
	
	/*
	 * Then, link each ContextTree to its parents.
	 */
	for (CFG::BBIterator bb(cfg); bb; bb++) {
		if (LOOP_HEADER(bb)) {
			/* Loop header: add the ContextTree to its parent ContextTree */
			if (!ENCLOSING_LOOP_HEADER(bb)) {
				/* The loop is not in another loop: add to the root context tree. */
				addChild(OWNER_CONTEXT_TREE(bb));
			} else {
				/* The loop is in another loop, add to the outer loop's context tree. */
				OWNER_CONTEXT_TREE(ENCLOSING_LOOP_HEADER(bb))->addChild(OWNER_CONTEXT_TREE(bb));
			}
		} else {
			/* Not loop header: add the BasicBlock to its ContextTree */		
			if (!ENCLOSING_LOOP_HEADER(bb)) {
				/* bb is not in a loop: add bb to the root ContextTree */
				addBB(bb, _inline);
				OWNER_CONTEXT_TREE(bb)=this;			
			} else {
				/* The bb is in a loop: add the bb to the loop's ContextTree. */
				ContextTree *parent = OWNER_CONTEXT_TREE(ENCLOSING_LOOP_HEADER(bb));
				parent->addBB(bb, _inline);
				OWNER_CONTEXT_TREE(bb) = parent;
			}
		}
	}	
}
Exemple #2
0
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());
				}
			}
		}
	}
}
Exemple #3
0
  void ISPCATBuilder::processCFG(WorkSpace *ws, CFG *cfg) {
    ISPProblem problem(_isp_size);
    DefaultListener<ISPProblem> listener(ws, problem,true);
    DefaultFixPoint<DefaultListener<ISPProblem> > fixpoint(listener);
    HalfAbsInt<DefaultFixPoint<DefaultListener<ISPProblem> > > halfabsint(fixpoint, *ws);
    halfabsint.solve();
	
    for(CFG::BBIterator bb(cfg); bb; bb++) {
      if (bb->isEntry() || bb->isExit())
	continue;
      FunctionBlock *fb = FUNCTION_BLOCK(bb);
      if (fb) {
	ISPProblem::Domain dom(*listener.results[cfg->number()][bb->number()]); 
	bool may, must;
	dom.contains(fb, &may, &must);
	
	if (must) {
	  ISP_CATEGORY(bb) = ISP_ALWAYS_HIT;
	} 
	else {
	  if (!may) {
	    ISP_CATEGORY(bb) = ISP_ALWAYS_MISS;
	  } 
	  else {
	    BasicBlock *pers_header = NULL;
	    BasicBlock *loop_header = ENCLOSING_LOOP_HEADER(bb);
 	    while (loop_header){
	      bool pers_entering, pers_back = true;
 	      for (BasicBlock::InIterator edge(loop_header) ; edge && pers_back; edge++){
		BasicBlock * source = edge->source();
		ISPProblem::Domain source_out(*listener.results_out[cfg->number()][source->number()]); 
		bool pers_may, pers_must;
		source_out.contains(fb, &pers_may, &pers_must);
 		if (!Dominance::isBackEdge(edge)){  // edge thats enters the loop
		  pers_entering = pers_must;
		}
		else { // backedge
		  if (!pers_must)
		    pers_back = false;
		}
	      }
	      if (pers_back){
		pers_header = loop_header;
		if (pers_entering)
		  loop_header = ENCLOSING_LOOP_HEADER(loop_header);
		else
		  loop_header = NULL;
	      }
	      else
		loop_header = NULL;
	    }
		  
	    if (pers_header){
	      ISP_CATEGORY(bb) = ISP_PERSISTENT; 
	      ISP_HEADER(bb) = pers_header;
	    }
	    else
	      ISP_CATEGORY(bb) = ISP_NOT_CLASSIFIED; 
	  }
	}
      }
    }
  }
void LoopUnroller::unroll(otawa::CFG *cfg, BasicBlock *header, VirtualCFG *vcfg) {
	VectorQueue<BasicBlock*> workList;
	VectorQueue<BasicBlock*> loopList;
	VectorQueue<BasicBlock*> virtualCallList;
	genstruct::Vector<BasicBlock*> doneList;
	typedef genstruct::Vector<Pair<VirtualBasicBlock*, Edge::kind_t> > BackEdgePairVector;
	BackEdgePairVector backEdges;
	bool dont_unroll = false;
	BasicBlock *unrolled_from;
	int start;

	/* Avoid unrolling loops with LOOP_COUNT of 0, since it would create a LOOP_COUNT of -1 for the non-unrolled part of the loop*/

	/*

	if (header && (ipet::LOOP_COUNT(header) == 0)) {
		dont_unroll = true;
	}

	*/
	//if (header) dont_unroll = true;
	start = dont_unroll ? 1 : 0;


	for (int i = start; ((i < 2) && header) || (i < 1); i++) {
		doneList.clear();
		ASSERT(workList.isEmpty());
		ASSERT(loopList.isEmpty());
		ASSERT(doneList.isEmpty());

		workList.put(header ? header : cfg->entry());
		doneList.add(header ? header : cfg->entry());

		genstruct::Vector<BasicBlock*> bbs;

		while (!workList.isEmpty()) {

			BasicBlock *current = workList.get();

			if (LOOP_HEADER(current) && (current != header)) {
				/* we enter another loop */

				loopList.put(current);

				/* add exit edges destinations to the worklist */

				for (genstruct::Vector<Edge*>::Iterator exitedge(**EXIT_LIST(current)); exitedge; exitedge++) {
					if (!doneList.contains(exitedge->target())) {
						workList.put(exitedge->target());
						doneList.add(exitedge->target());
					}
				}
			} else {
				VirtualBasicBlock *new_bb = 0;
				if ((!current->isEntry()) && (!current->isExit())) {
					/* Duplicate the current basic block */

					new_bb = new VirtualBasicBlock(current);
					new_bb->removeAllProp(&ENCLOSING_LOOP_HEADER);
					new_bb->removeAllProp(&EXIT_LIST);
					new_bb->removeAllProp(&REVERSE_DOM);
					new_bb->removeAllProp(&LOOP_EXIT_EDGE);
					new_bb->removeAllProp(&LOOP_HEADER);
					new_bb->removeAllProp(&ENTRY);

					/* Remember the call block so we can correct its destination when we have processed it */
					if (VIRTUAL_RETURN_BLOCK(new_bb))
						virtualCallList.put(new_bb);

					if ((current == header) && (!dont_unroll)) {
						if (i == 0) {
							unrolled_from = new_bb;
						} else {
							UNROLLED_FROM(new_bb) = unrolled_from;
						}
					}
					/*
					if (ipet::LOOP_COUNT(new_bb) != -1) {
						if (i == 0) {
							new_bb->removeAllProp(&ipet::LOOP_COUNT);
						}
						else {
							int old_count = ipet::LOOP_COUNT(new_bb);
							new_bb->removeAllProp(&ipet::LOOP_COUNT);
							ipet::LOOP_COUNT(new_bb) = old_count - (1 - start);
							ASSERT(ipet::LOOP_COUNT(new_bb) >= 0);

						}

					}
					*/
					INDEX(new_bb) = idx;
					idx++;
					vcfg->addBB(new_bb);


					bbs.add(current);

					map.put(current, new_bb);
				}


				/* add successors which are in loop (including possible sub-loop headers) */
				for (BasicBlock::OutIterator outedge(current); outedge; outedge++) {

					if (outedge->target() == cfg->exit())
						continue;
					if (outedge->kind() == Edge::CALL)
						continue;

					if (ENCLOSING_LOOP_HEADER(outedge->target()) == header) {
					//	cout << "Test for add: " << outedge->target()->number() << "\n";
						if (!doneList.contains(outedge->target())) {
							workList.put(outedge->target());
							doneList.add(outedge->target());
						}
					}
					if (LOOP_EXIT_EDGE(outedge)) {
						ASSERT(new_bb);
						/* Connect exit edge */
						VirtualBasicBlock *vdst = map.get(outedge->target());
						new Edge(new_bb, vdst, outedge->kind());
					}
				}

			}
		}

		while (!virtualCallList.isEmpty()) {
			BasicBlock *vcall = virtualCallList.get();
			BasicBlock *vreturn = map.get(VIRTUAL_RETURN_BLOCK(vcall), 0);

			ASSERT(vreturn != 0);
			VIRTUAL_RETURN_BLOCK(vcall) = vreturn;

		}


		while (!loopList.isEmpty()) {
			BasicBlock *loop = loopList.get();
			unroll(cfg, loop, vcfg);
		}



		/* Connect the internal edges for the current loop */
		for (genstruct::Vector<BasicBlock*>::Iterator bb(bbs); bb; bb++) {
			for (BasicBlock::OutIterator outedge(bb); outedge; outedge++) {
				if (LOOP_EXIT_EDGE(outedge))
					continue;
				if (LOOP_HEADER(outedge->target()) && (outedge->target() != header))
					continue;
				if (outedge->target() == cfg->exit())
					continue;

				VirtualBasicBlock *vsrc = map.get(*bb, 0);
				VirtualBasicBlock *vdst = map.get(outedge->target(), 0);

				if (outedge->kind() == Edge::CALL) {
					CFG *called_cfg = outedge->calledCFG();
					int called_idx = INDEX(called_cfg);
					CFG *called_vcfg = coll->get(called_idx);
					Edge *vedge = new Edge(vsrc, called_vcfg->entry(), Edge::CALL);
					CALLED_BY(called_vcfg).add(vedge);
					ENTRY(called_vcfg->entry()) = called_vcfg;
					CALLED_CFG(outedge) = called_vcfg; /* XXX:  ??!? */


				} else if ((outedge->target() != header) || ((i == 1) /* XXX && !dont_unroll XXX*/ )) {
					new Edge(vsrc, vdst, outedge->kind());
				} else {
					backEdges.add(pair(vsrc, outedge->kind()));
				}
			}
		}

		if (i == start) {
			/* Connect virtual entry edges */
			if (header) {
				for (BasicBlock::InIterator inedge(header); inedge; inedge++) {
					if (Dominance::dominates(header, inedge->source()))
						continue; /* skip back edges */
					if (inedge->source() == cfg->entry())
						continue;
					VirtualBasicBlock *vsrc = map.get(inedge->source());
					VirtualBasicBlock *vdst = map.get(header);
					new Edge(vsrc, vdst, inedge->kind());
				}
			}

		} else {
			/* Connect virtual backedges from the first to the other iterations */
			for (BackEdgePairVector::Iterator iter(backEdges); iter; iter++) {
				VirtualBasicBlock *vdst = map.get(header);
				new Edge((*iter).fst, vdst, (*iter).snd);
			}
		}
	}
	if (!header) {
		/* add main entry edges */
		for (BasicBlock::OutIterator outedge(cfg->entry()); outedge; outedge++) {
			VirtualBasicBlock *vdst = map.get(outedge->target());
			new Edge(vcfg->entry(), vdst, Edge::VIRTUAL_CALL);
		}
		/* add main exit edges */
		for (BasicBlock::InIterator inedge(cfg->exit()); inedge; inedge++) {
			VirtualBasicBlock *vsrc = map.get(inedge->source());
			new Edge(vsrc, vcfg->exit(), Edge::VIRTUAL_RETURN);
		}
	}

}
void EdgeCAT2Builder::processLBlockSet(otawa::CFG *cfg, LBlockSet *lbset, const hard::Cache *cache) {
	unsigned int line = lbset->line();
	/*static double moypr = 0;
	static double moy = 0;*/
	
	/* Use the results to set the categorization */
	for (LBlockSet::Iterator lblock(*lbset); lblock; lblock++) {
		if ((lblock->id() == 0) || (lblock->id() == lbset->count() - 1))
			continue;
			
	
		Vector<MUSTProblem::Domain*> &mustVec = *CACHE_EDGE_ACS_MUST(lblock);
		Vector<PERSProblem::Domain*> &persVec = *CACHE_EDGE_ACS_PERS(lblock);
		
		CATEGORY_EDGE(lblock) = new Vector<category_t>();
		CATEGORY_EDGE_HEADER(lblock) = new Vector<BasicBlock*>();

		BasicBlock::InIterator inedge(lblock->bb());
		for (int i = 0; i < mustVec.length(); i++) {
			
			MUSTProblem::Domain *must = mustVec[i];
			
			PERSProblem::Domain *pers = NULL;
			if (firstmiss_level != FML_NONE) {
				pers = persVec[i];
				/* enter/leave context if in-edge enters or exits loops */
				if (LOOP_EXIT_EDGE(inedge)) {
					/* find loop header of inner-most exited loop */
					BasicBlock *header = inedge->source();
					if (!LOOP_HEADER(header))
						header = ENCLOSING_LOOP_HEADER(header);
					ASSERT(header && LOOP_HEADER(header));
	
					/* now leave contexts for each loop between header and LOOP_EXIT_EDGE(inedge) (included) */
					pers->leaveContext();
					while (header != LOOP_EXIT_EDGE(inedge)) {	
						pers->leaveContext();
						header = ENCLOSING_LOOP_HEADER(header);
						ASSERT(header);
					} 
				}
				if (LOOP_HEADER(lblock->bb()) && !BACK_EDGE(inedge)) {
					/* an entry edge may not enter more than one loop */
					pers->enterContext();
				}
			}
			
			
			BasicBlock *header = NULL;	
			category_t cat = NOT_CLASSIFIED;	
			BasicBlock *cat_header = NULL;		
				
			if (must->contains(lblock->cacheblock())) {
				cat = ALWAYS_HIT;
			} else if (firstmiss_level != FML_NONE) {
				if (Dominance::isLoopHeader(lblock->bb()))
					header = lblock->bb();
			  	else header = ENCLOSING_LOOP_HEADER(lblock->bb());
			  	
			  	int bound;
			  	bool perfect_firstmiss = true;										
				
				bound = 0;
				
				if ((pers->length() > 1) && (firstmiss_level == FML_INNER))
					bound = pers->length() - 1;
				cat_header = NULL;		
			  	for (int k = pers->length() - 1 ; (k >= bound) && (header != NULL); k--) {
					if (pers->isPersistent(lblock->cacheblock(), k)) {
						cat = FIRST_MISS;
						cat_header = header;
					} else perfect_firstmiss = false;
					header = ENCLOSING_LOOP_HEADER(header);
				}
			
				if ((firstmiss_level == FML_OUTER) && (perfect_firstmiss == false))
					cat = ALWAYS_MISS;																				
			} /* of category condition test */			
			CATEGORY_EDGE(lblock)->add(cat);
			CATEGORY_EDGE_HEADER(lblock)->add(cat_header);
			inedge++;
		}
	}
	

}