示例#1
0
/*
 * Obtain some details of a given call site.
 */
void COptimiser::getCallSite(int required, POS &i, POS begin, std::deque<CALL_PARAM> &params) const
{
	do
	{
		if (i->udt & UDT_LINE)
		{
			++i;
			break;
		}
		else
		{
			POS j = i;
			if ((i->udt & UDT_FUNC) && i->params)
			{
				// Another function!
				std::deque<CALL_PARAM> reparams;
				getCallSite(i->params, --j, begin, reparams);
			}
			params.push_front(std::pair<POS, POS>(j, i));
			i = j;
			if (!--required) break;
		}

	} while (i-- != begin);
}
 /**
  * 
  * @brief returns all call sites that correspond with the given exit - return site pair
  *
  * @param - exitSite: the exit of the pair whose call sites to look for
  * @param = returnSite: the return site of the pair whose call sites to look for
  * @return the set of all call sites that correspond with the exit - return site pair
  *
  */
 const TransitionStorage::States TransitionStorage::getCallSites( State exitSite, State returnSite ) const
 {
   States calls;
   const Info::Returns & exit = T_info.exitTrans(exitSite);
   for( Info::ReturnIterator it = exit.begin(); it != exit.end(); it++ )
   {
     if( getReturnSite(*it) == returnSite )
       calls.insert(getCallSite(*it));  
   }
   return calls;
 }
    /**
     * Q: how can this be optimized?
     * @brief test if there exists a return transition with the given from state, 
     *        predecessor state, and symbol in this collection of transitions 
     *
     * @param - from: the desired from state for the return transition
     * @param - pred: the desired predecessor state for the return transition
     * @param - sym: the desired symbol for the return transition
     * @return true if there exists a return transition with the given from state and
     *          symbol in this collection of transitions
     *
     */
    bool TransitionStorage::returnExists( State from, State pred, Symbol sym ) const
    {
      Returns const & outgoing = T_info.exitTrans(from);

      for( ReturnIterator rit = outgoing.begin(); rit != outgoing.end(); rit++ )
      {
        if( (getCallSite(*rit) == pred) && (getReturnSym(*rit) == sym) )
          return true;      
      }     
      return false;
    }   
    /**
     *   
     * @brief creates transitions for 'dup' mirroring 'orig' outgoing transitions
     *
     * @param - orig: the state that is being duplicated
     * @param - dup: the state that is duplicating 'orig'
     *  
     */
    void TransitionStorage::dupTransOutgoing( State orig, State dup )
    { 
      // Duplicate outgoing internal transitions.
      const Info::Internals & from = T_info.fromTrans(orig);
      for( Info::InternalIterator it = from.begin(); it != from.end(); it++ )
      {
        Internal iTrans(dup,getInternalSym(*it),getTarget(*it));
        addInternal(iTrans);
      }

      // Duplicate call site call transitions.
      const Info::Calls & call = T_info.callTrans(orig);
      for( Info::CallIterator it = call.begin(); it != call.end(); it++ )
      {
        Call cTrans(dup,getCallSym(*it),getEntry(*it));
        addCall(cTrans);

      }

      // Duplicate exit point return transitions.
      const Info::Returns & exit = T_info.exitTrans(orig);
      for( Info::ReturnIterator it = exit.begin(); it != exit.end(); it++ )
      {
        Return rTrans(dup,getCallSite(*it),getReturnSym(*it),getReturnSite(*it));
        addReturn(rTrans);
      }

      // Q: Do we want to do these? Seems inconsistent. -Evan
      // A: Aditya says 'yes', and thinks we need it. So we definitely don't
      //    want to change it without looking at uses and compensating.
      // Duplicate call predecessor return transitions.
      const Info::Returns & pred = T_info.predTrans(orig);
      for( Info::ReturnIterator it = pred.begin(); it != pred.end(); it++ )
      {
        Return rTrans(getExit(*it),dup,getReturnSym(*it),getReturnSite(*it));
        addReturn(rTrans);
      }
    }
    /**
     *
     * @brief print the collection of transitions
     *
     * @param - o: the output stream to print to
     * @return the output stream that was printed to
     *
     */
    std::ostream & TransitionStorage::print( std::ostream & o ) const
    {    
      //Print call transitions.
      o << "Delta_c: {\n  ";
      bool first = true;
      for( CallIterator cit = callTrans.begin(); cit != callTrans.end(); cit++, first=false )
      {
        if( !first )
          o << ", \n  ";
        o << "(";
        printKey(o,getCallSite(*cit));
        o << " (=" << getCallSite(*cit) << ") ";
        o << ", ";
        printKey(o,getCallSym(*cit));
        o << ", "; 
        printKey(o,getEntry(*cit));
        o << " (=" << getEntry(*cit) << ") ";
        o << ")";
      }
      o << "\n}\n";

      //Print internal transitions.
      o << "Delta_i:  {\n  ";
      first = true;
      for(InternalIterator iit = internalTrans.begin();
          iit != internalTrans.end(); iit++, first=false )
      {
        if( !first )
          o << ",\n  ";
        o << "(";
        printKey(o,getSource(*iit));
        o << " (=" << getSource(*iit) << ") ";
        o << ", ";
        printKey(o,getInternalSym(*iit));
        o << ", ";
        printKey(o,getTarget(*iit));
        o << " (=" << getTarget(*iit) << ") ";
        o << ")";
      }
      o << "\n}\n";

      //Print return transitions.
      o << "Delta_r: {\n  ";
      first = true;
      for(ReturnIterator rit = returnTrans.begin();
          rit != returnTrans.end(); rit++, first = false )
      {
        if( !first )
          o << ",\n  ";
        o << "(";
        printKey(o,getExit(*rit));
        o << " (=" << getExit(*rit) << ") ";
        o << ", ";
        printKey(o,getCallSite(*rit));
        o << " (=" << getCallSite(*rit) << ") ";
        o << ", "; 
        printKey(o,getReturnSym(*rit));
        o << ", ";
        printKey(o,getReturnSite(*rit));
        o << " (=" << getReturnSite(*rit) << ") ";
        o << ")";
      }
      o << "\n}\n";
      
      return o;
    }
    /**
     *  
     * @brief creates transitions for 'dup' mirroring 'orig' transitions
     *
     * @param - orig: the state that is being duplicated
     * @param - dup: the state that is duplicating 'orig'
     *  
     */
    void TransitionStorage::dupTrans( State orig, State dup )
    { 
      //Duplicate outgoing internal transitions.
      const Info::Internals & from = T_info.fromTrans(orig);
      for( Info::InternalIterator it = from.begin(); it != from.end(); it++ )
      {
        Internal iTrans(dup,getInternalSym(*it),getTarget(*it));
        addInternal(iTrans);

        // Q: This is also inconsistent with dupTransOutgoing, which didn't do
        //    anything special with self loops. -Evan
        // A: Aditya says yes, but this is again what McVeto(?) needs.
        //    dupTrans is used in 'duplicateState', but dupTransOutgoing is
        //    different.
        if( orig == getTarget(*it) )   //Handle self-loops.
        {
          Internal loop(dup,getInternalSym(*it),dup);
          addInternal(loop);
        }
      }

      //Duplicate incoming internal transitions.
      const Info::Internals & to = T_info.toTrans(orig);
      for( Info::InternalIterator it = to.begin(); it != to.end(); it++ )
      {
        Internal iTrans(getSource(*it),getInternalSym(*it),dup);
        addInternal(iTrans);
      }

      //Duplicate call site call transitions.
      const Info::Calls & call = T_info.callTrans(orig);
      for( Info::CallIterator it = call.begin(); it != call.end(); it++ )
      {
        Call cTrans(dup,getCallSym(*it),getEntry(*it));
        addCall(cTrans);
        if( orig == getEntry(*it) )   //Handle self-loops.
        {
          Call loop(dup,getCallSym(*it),dup);
          addCall(loop);
        }
      }

      //Duplicate entry point call transitions.
      const Info::Calls & entry = T_info.entryTrans(orig);
      for( Info::CallIterator it = entry.begin(); it != entry.end(); it++ )
      {
        Call cTrans(getCallSite(*it),getCallSym(*it),dup);
        addCall(cTrans);
      }

      //Duplicate exit point return transitions.
      const Info::Returns & exit = T_info.exitTrans(orig);
      for( Info::ReturnIterator it = exit.begin(); it != exit.end(); it++ )
      {
        Return rTrans(dup,getCallSite(*it),getReturnSym(*it),getReturnSite(*it));
        addReturn(rTrans);
        if( orig == getCallSite(*it) )   //Handle self-loops.
        {
          Return loop(dup,dup,getReturnSym(*it),getReturnSite(*it));
          addReturn(loop);
        }
        if( orig == getReturnSite(*it) )   //Handle self-loops.
        {
          Return loop(dup,getCallSite(*it),getReturnSym(*it),dup);
          addReturn(loop);
        }
        if( orig == getCallSite(*it) && orig == getReturnSite(*it) )   //Handle self-loops.
        {
          Return loop(dup,dup,getReturnSym(*it),dup);
          addReturn(loop);
        }
      }

      //Duplicate call predecessor return transitions.
      const Info::Returns & pred = T_info.predTrans(orig);
      for( Info::ReturnIterator it = pred.begin(); it != pred.end(); it++ )
      {
        Return rTrans(getExit(*it),dup,getReturnSym(*it),getReturnSite(*it));
        addReturn(rTrans);
        if( orig == getReturnSite(*it) )   //Handle self-loops.
        {
          Return loop(getExit(*it),dup,getReturnSym(*it),dup);
          addReturn(loop);
        }
      }

      //Duplicate return site return transitions.
      const Info::Returns & ret = T_info.retTrans(orig);
      for( Info::ReturnIterator it = ret.begin(); it != ret.end(); it++ )
      {
        Return rTrans(getExit(*it),getCallSite(*it),getReturnSym(*it),dup);
        addReturn(rTrans);
      }
    }
示例#7
0
/*
 * Inline expand a program's functions.
 * This also performs some rudimentary constant propagation
 * but a better constant propagator should be written at some
 * latter date!
 */
bool COptimiser::inlineExpand()
{
	std::map<LPNAMED_METHOD, MACHINE_UNITS> methods;

	// Make copies of all the program's methods.
	{
		std::vector<tagNamedMethod>::iterator i = m_prg.m_methods.begin();
		for (; i != m_prg.m_methods.end(); ++i)
		{
			if (!i->bInline) continue;

			MACHINE_UNITS &method = methods[&*i];
			POS j = m_prg.m_units.begin() + i->i;
			int depth = 0;
			do
			{
				method.push_back(*j);

				if (j->udt & UDT_OPEN) ++depth;
				else if ((j->udt & UDT_CLOSE) && !--depth) break;
			} while (++j != m_prg.m_units.end());

			method.pop_front();
			method.pop_back();

			// m_prg.m_units.erase(m_prg.m_units.begin() + i->i - 1, j + 1);
		}
	}

	if (!methods.size()) return false;

	// Locate method calls.
	TCHAR chr = 0;
	POS i = m_prg.m_units.begin();
	for (; i != m_prg.m_units.end(); ++i)
	{
		if (!((i->udt & UDT_FUNC) && (i->func == CProgram::methodCall))) continue;
		POS unit = i - 1;
		if (unit->udt & UDT_OBJ) continue;
		LPNAMED_METHOD p = NAMED_METHOD::locate(unit->lit, i->params - 1, false, m_prg);
		if (!(p && p->bInline)) continue;

		LPMACHINE_UNITS pUnits = &methods.find(p)->second;

		// Back peddle to find where this call site begins.

		MACHINE_UNITS paramUnits;

		POS j = i;

		std::map<STRING, MACHINE_UNIT> subst;

		{
			std::deque<CALL_PARAM> params;
			getCallSite(i->params, --j, m_prg.m_units.begin(), params);

			MACHINE_UNIT assign;
			assign.udt = UNIT_DATA_TYPE(UDT_FUNC | UDT_LINE);
			assign.params = 2;
			assign.func = operators::assign;

			std::deque<CALL_PARAM>::iterator k = params.begin();
			for (; k != (params.end() - 1); ++k)
			{
				TCHAR pos = p->params - (k - params.begin());
				STRING var = STRING(_T(" ")) + pos;

				if ((k->first != k->second) || (~(k->first->udt) & UDT_ID))
				{
					MACHINE_UNIT lhs;
					lhs.udt = UDT_ID;
					lhs.lit = var;

					paramUnits.push_back(lhs);
					paramUnits.insert(paramUnits.end(), k->first, k->second + 1);

					paramUnits.push_back(assign);
				}
				else
				{
					// The parameter is just a simple constant value so
					// we can plug it to the function directly later.
					subst.insert(std::pair<STRING, MACHINE_UNIT>(
						var, *k->first
					));
				}
			}
		}

		paramUnits.insert(paramUnits.end(), pUnits->begin(), pUnits->end());

		MACHINE_UNIT mu;
		mu.udt = UDT_ID;
		mu.lit = STRING(_T(" ret")) + ++chr;

		MACHINE_UNITS retVal;

		// Fix up return values.
		POS k;
		for (k = paramUnits.begin(); k != paramUnits.end(); ++k)
		{
			if (k->udt & UDT_ID)
			{
				std::map<STRING, MACHINE_UNIT>::iterator i = subst.find(k->lit);
				if (i != subst.end())
				{
					*k = i->second;
				}
				else if (k->lit[0] == ' ')
				{
					// This is a parameter, but we can't leave it named this since we
					// are not in a local scope.
					k->lit[0] = '-';
				}
				continue;
			}
			if (!((k->udt & UDT_FUNC) && (k->func == CProgram::returnVal))) continue;

			if (k == (paramUnits.end() - 1))
			{
				// This return statement is the last statement in the function
				// so we can just replace the function call by its argument
				// rather than setting up the return properly.
				std::deque<CALL_PARAM> params;
				POS j = k - 1;
				getCallSite(1, j, paramUnits.begin(), params);
				retVal.insert(retVal.begin(), j, k);
				paramUnits.erase(j, k + 1);
				break;
			}
			else
			{
				k->func = operators::assign;
				k->params = 2;

				std::deque<CALL_PARAM> rparams;
				getCallSite(1, --k, paramUnits.begin(), rparams);
				k = paramUnits.insert(k, mu) + 1;
			}
		}

		k = m_prg.m_units.erase(j, i + 1);

		if (retVal.size())
		{
			const int kpos = k - m_prg.m_units.begin();
			m_prg.m_units.insert(k, retVal.begin(), retVal.end());
			k = m_prg.m_units.begin() + kpos;
		}
		else
		{
			k = m_prg.m_units.insert(k, mu);
		}

		while (--k != m_prg.m_units.begin())
		{
			if (k->udt & UDT_LINE) break;
		}

		// Now we insert the function's body!
		m_prg.m_units.insert(k + 1, paramUnits.begin(), paramUnits.end());
		i = m_prg.m_units.begin(); // (Heh...)
	}

	/**{
		POS i = m_prg.m_units.begin();
		for (; i != m_prg.m_units.end(); ++i)
		{
			i->show();
		}
	}**/

	return true;
}
示例#8
0
/*
 * Propagate constant values by replacing variable references
 * with their values where those values are constants or other
 * variables.
 */
void COptimiser::propagateConstants()
{
	// Beware: terrible algorithm here!
	//
	// When if/while/for/branch are encountered, and when if/while/for
	// end, the constant pool is reset even if conditional code does
	// does affect certain constants! This is to avoid trick situations
	// but it is far over-reaching. In general it is safe to maintain
	// the pool of constants for an if...else construct (using the same
	// pool that existed before the construct for both parts of it) but
	// this is too much work for now. (Branch will proabably break this
	// algorithm!)
	//
	// The technique here is to look for assignment instructions with
	// constant right hand sides and maintain a map (the "pool") of
	// {var : constant} that is updated with each new assignment. Then
	// when a reference to a var is found, it is replaced by the constant
	// in the pool. This is good enough to mitigate the ineffectuality of
	// the redundant assignment instructions generated by inlineExpand(),
	// but not good enough to do anything else!
	//
	// This algorithm also makes the assumption that all function calls
	// have no side effects. It is not safe (!) for general use because
	// of this!

	std::map<STRING, MACHINE_UNIT> pool;

	POS i = m_prg.m_units.begin();
	for (; i != m_prg.m_units.end(); ++i)
	{
		if (i->udt & UDT_FUNC)
		{
			if (i->func == operators::assign)
			{
				POS j = i - 1;
				std::deque<CALL_PARAM> params;
				getCallSite(2, j, m_prg.m_units.begin(), params);

				CALL_PARAM lhs = params.front();
				CALL_PARAM rhs = params.back();

				// Don't store values if the left hand side is something
				// esoteric like a function or another assignment.
				if (lhs.first != lhs.second) continue;

				if ((rhs.first != rhs.second) || (rhs.first->udt & UDT_FUNC))
				{
					// If this value is already in the constant pool, we need
					// to purge it.
					pool.erase(lhs.first->lit);
					continue;
				}

				// Add an entry to the pool.
				pool.insert(std::pair<STRING, MACHINE_UNIT>(
					lhs.first->lit, *rhs.first
				));
			}
			else if ((i->func == CProgram::conditional)
					| (i->func == CProgram::elseIf)
					| (i->func == CProgram::whileLoop)
					| (i->func == CProgram::untilLoop)
					| (i->func == CProgram::forLoop)
					| (i->func == CProgram::skipMethod))
			{
				// Clear the pool (!)
				pool.clear();
			}
		}
		else if (i->udt & UDT_ID)
		{
			// Look ahead to make sure this isn't the left-hand-side
			// of an assignment.

			bool bFailed = false;
			for (POS j = i; j != m_prg.m_units.end(); ++j)
			{
				if ((j->udt & UDT_FUNC) && (j->func == operators::assign))
				{
					POS k = j - 1;
					std::deque<CALL_PARAM> params;
					getCallSite(2, k, m_prg.m_units.begin(), params);

					if (params[0].first == i)
					{
						bFailed = true;
						break;
					}
				}
				else if (j->udt & UDT_LINE) break;
			}

			if (bFailed) continue;

			// This is a referece to a constant - but is this constant in the pool?
			std::map<STRING, MACHINE_UNIT>::iterator k = pool.find(i->lit);
			if (k != pool.end())
			{
				*i = k->second;
			}
		}
	}
}