Skip to content
Snippets Groups Projects
Select Git revision
  • master
1 result

DoxygenLayout.xml

Blame
  • PPLDomain.h 25.45 KiB
    #ifndef PPLDOMAIN_H
    #define PPLDOMAIN_H 1
    
    #include <elm/util/BitVector.h>
    #include <otawa/cfg.h>
    #include <otawa/cfg/features.h>
    #include <otawa/ipet.h>
    #include <otawa/otawa.h>
    #include <otawa/prog/sem.h>
    #include <otawa/dfa/ai.h>
    #include <otawa/dfa/State.h>
    #include <ppl.hh>
    
    #include "PolyCommon.h"
    #include "PolyWrap.h"
    
    namespace otawa {
    namespace poly {
    
    using namespace otawa;
    //using namespace otawa::util;
    
    namespace PPL = Parma_Polyhedra_Library;
    using Variable = PPL::Variable;
    
    enum bound_t : signed long {
    	UNREACHABLE = -1,
    	UNBOUNDED = -2,
    };
    
    /* TODO(clement): detect stack conf. from OTAWA */ 
    enum stackconf_t : int32_t {
    	STACK_TOP = -0x60000000,
    	STACK_SIZE = 0x10000000,
    };
    
    /**
     * @class Ident
     *
     * Identifiers can represent registers, memory address/values, loop bounds, or special values (such as starting stack
     * frame address).
     * They are associated to polyhedron variables in abstract states.
     *
     * Identifiers are uniquely identified by a type, and an id number.
     *
     */
    class Ident {
      public:
    	enum IdentType {
    		ID_REG = 0,
    		ID_REG_INPUT,
    		ID_MEM_ADDR,
    		ID_MEM_VAL,
    		ID_MEM_VAL_INPUT,
    		ID_SPECIAL,
    		ID_LOOP,
    		ID_INVALID,
    		ID_MAX_TYPE,
    	};
    	enum IdentSpecial {
    		ID_START_SP = 0,
    		ID_START_FP = 1,
    		ID_START_LR = 2,
    	};
    	inline Ident() : _type(ID_INVALID) {}
    	inline Ident(int id, IdentType typ) : _id(id), _type(typ) {}
    	inline ~Ident() = default;
    	inline int getId() const { return _id; }
    	inline IdentType getType() const { return _type; }
    	inline bool equals(const Ident &b) const { return (_id == b._id) && (_type == b._type); }
    
    	void print(io::Output &out) const;
    
    	inline bool operator==(const Ident &i) const { return (_id == i._id) && (_type == i._type); }
    	inline bool operator!=(const Ident &i) const { return (_id != i._id) || (_type != i._type); }
    
      private:
    	int _id{};
    	IdentType _type;
    };
    inline Output &operator<<(Output &o, const Ident &i) {
    	i.print(o);
    	return o;
    }
    
    class HashIdent {
      public:
    	static inline t::hash hash(const Ident &key) { return key.getId(); };
    	static inline bool equals(const Ident &key1, const Ident &key2) { return key1.equals(key2); }
    };
    
    class VectCoefIdent {
    	public:
    		static inline t::hash hash(const Vector<PPL::Coefficient> &v) { 
    			int prime = 31;
    			t::hash result = 1;
    			for (int i = 0; i < v.length(); i++) {
    				result = prime * result + PPL::raw_value(v[i]).get_ui();
    			}
    			return 0; 
    		}
    		static inline bool equals(const Vector<PPL::Coefficient> &v1, const Vector<PPL::Coefficient> &v2) {
    			return v1 == v2;
    		}
    };
    
    class HashCons {
      public:
    	static t::hash hash(const PPL::Constraint &key);
    	static inline bool equals(const PPL::Constraint &key1, const PPL::Constraint &key2) {
    		return key1.is_equivalent_to(key2);
    	}
    };
    
    
    /**
     * @class PPLInput
     *
     * Represents an input (register, or memory location) to a summarized function
     *
     */
    /*
    class PPLInput {
    	public:
    		Ident _input;
    		Ident _where;
    	bool operator==(const PPLInput &a) const {
    		return false;
    	}
    };
    */
    
    /**
     * @class PPLSummary
     *
     * Represents a partial result (summary) computed for a function.
     */
    class PPLSummary {
    	public:
    		elm::Vector<Ident> _damaged; ///< The list of output (or side-effects) variables (registers or pointers)
    //		genstruct::Vector<Ident> _inputs; ///< The list of inputs for the function
    		inline bool equals(const PPLSummary &b) const {
    			return true;
    		}
    };
    
    // TODO make this a template and put in elm/whatever
    class Mapping {
    	public:
    		bool includes(const Mapping &src) const {
    			for (MyHTable<Ident, guid_t, HashIdent>::PairIterator it(id2guid); it(); it++) {
    				if (!src.id2guid.hasKey((*it).fst))
    				   return false;	
    				if (src.id2guid[(*it).fst] != (*it).snd)
    					return false;
    			}
    			for (MyHTable<guid_t, Ident>::PairIterator it(guid2id); it(); it++) {
    				if (!src.guid2id.hasKey((*it).fst))
    				   return false;	
    
    				const Ident &id1 = (*it).snd;
    				const Ident &id2 = src.guid2id[(*it).fst];
    				if (id1 != id2) 
    					return false;
    			}
    			return true;
    		}
    
    		bool operator==(const Mapping &src) const {
    			return this->includes(src) && src.includes(*this);
    		}
    
    		inline void add(const Ident &id, guid_t guid) {
    			if (id2guid.hasKey(id))
    				guid2id.remove(id2guid[id]);
    
    			if (guid2id.hasKey(guid))
    				id2guid.remove(guid2id[guid]);
    
    			id2guid[id] = guid;
    			guid2id[guid] = id;
    		}
    
    		inline guid_t find1(const Ident &id) const {
    			return id2guid[id];
    		}
    
    		inline const Ident& find2(guid_t guid) const {
    			return guid2id[guid];
    		}
    
    		inline void del1(const Ident &id) {
    			guid2id.remove(id2guid[id]);
    			id2guid.remove(id);
    
    		}
    
    		inline void del2(guid_t guid) {
    			id2guid.remove(guid2id[guid]);
    			guid2id.remove(guid);
    		}
    
    		inline bool has1(const Ident &id) const {
    			return id2guid.hasKey(id);
    		}
    
    		inline bool has2(guid_t guid) const {
    			return guid2id.hasKey(guid);
    		}
    
    		inline MyHTable<Ident, guid_t, HashIdent>::PairIterator getPairIter() const {
    			return MyHTable<Ident, guid_t, HashIdent>::PairIterator(id2guid);
    		}
    
    		inline MyHTable<Ident, guid_t, HashIdent>::MutableIter getMutableIter() {
    			return MyHTable<Ident, guid_t, HashIdent>::MutableIter(id2guid);
    		}
    		
    		inline int count() const {
    			ASSERT(id2guid.count() == guid2id.count());
    			return id2guid.count();
    		}
    
    	private:
    		MyHTable<Ident, guid_t, HashIdent> id2guid;
    		MyHTable<guid_t, Ident> guid2id;
    
    };
    
    class PPLDomain {
    
    private:
    	/* Abstract state */
    	WPoly poly;
    
    	Mapping idmap; ///< Mapping from identifiers (registers/pointers) to polyhedron variables
    	Vector<guid_t> victims; ///< Set of variables scheduled to be destroyed
    
    	Ident compare_reg;      ///< Register holding the last comparison result
    	sem::cond_t compare_op; ///< Last comparison semantics
    
    	int mem_ref{}; ///< Highest pointer ID + 1
    	int num_axis;  ///<Highest poly variable ID + 1
    
    	Vector<bound_t> bounds;
    	Vector<PPLDomain> *linbounds = NULL;
    
    	WorkSpace *_ws;
    
    	PPLSummary *_summary; ///< Summarize currently analyzed function
    
    	/* Nested classes */
    
    	/**
    	 * @class MapHelper
    	 *
    	 * Wrapper for the PPL poly mapping partial functions, that computes automatically
    	 * max_in_codomain/has_empty_codomain.
    	 * See PPL documentation for details.
    	 */
    	template <class F> class MapHelper {
    	  public:
    		MapHelper(F &pfunc, int max_in_domain);
    		inline bool maps(guid_t i, guid_t &j) const { return _pfunc.maps(i, j); }
    
    	  private:
    		F &_pfunc;
    	};
    
    	/**
    	 * @class RemoveMarked
    	 *
    	 * Partial mapping function that removes variables in set (bitvector)
    	 * Needs to be wrapped with MapHelper before usage with PPL.
    	 */
    	class RemoveMarked {
    	  public:
    		inline ~RemoveMarked() = default;
    		inline RemoveMarked(BitVector &bv, int size) : _bv(bv), _size(size) {}
    		bool maps(guid_t i, guid_t &j) const;
    
    	  private:
    		BitVector &_bv;
    		int _size;
    	};
    
    
    	/**
    	 * @class MapWithHash
    	 *
    	 * Partial mapping function accoring to passed hashtable.
    	 * Needs to be wrapped with MapHelper before usage with PPL.
    	 */
    	class MapGuid {
    	  public:
    		inline explicit MapGuid(MyHTable<guid_t, guid_t> &map) : _map(map) {}
    		inline bool maps(guid_t i, guid_t &j) const {
    			if (_map.hasKey(i)) {
    				j = _map[i];
    				return true;
    			}
    			{ return false; }
    		}
    
    	  private:
    		MyHTable<guid_t, guid_t> &_map;
    	};
    	class MapWithHash {
    	  public:
    		inline explicit MapWithHash(MyHTable<int, int> &map) : _map(map) {}
    		inline bool maps(guid_t i, guid_t &j) const {
    			if (_map.hasKey(i)) {
    				j = _map[i];
    				return true;
    			}
    			{ return false; }
    		}
    
    	  private:
    		MyHTable<int, int> &_map;
    	};
    
    	class MapShift {
    	  public:
    		inline explicit MapShift(guid_t domsize, guid_t shift) : _domsize(domsize), _shift(shift) {}
    		inline bool maps(guid_t i, guid_t &j) const {
    			if (i < _domsize) {
    				j = i + _shift;
    				return true;
    			} else return false;
    		}
    
    	  private:
    		guid_t _domsize;
    		guid_t _shift;
    	};
    
      public:
    	/* Basic operations (constructor, destructor, copy, comparison) */
    
    	/**
    	 * Builds a bottom state
    	 */
    	inline PPLDomain() : poly(true) {
    		num_axis = -1;
    		compare_reg = Ident();
    		compare_op = sem::EQ;
    		_ws = nullptr;
    		_summary = nullptr;
    	}
    
    	/**
    	 * Builds a top state
    	 * @param maxAxis Maximum number of variables this state can hold
    	 */
    	inline explicit PPLDomain(int maxAxis, WorkSpace *ws, PPLSummary *summary = nullptr) : poly(false) {
    		num_axis = 0;
    		mem_ref = 0;
    		_ws = ws;
    		compare_reg = Ident();
    		compare_op = sem::EQ;
    		_summary = summary;
    	}
    
    	inline PPLDomain(const PPLDomain &src) : poly(src.poly){
    		num_axis = src.num_axis;
    		idmap = src.idmap;
    		ASSERT(idmap == src.idmap);
    		mem_ref = src.mem_ref;
    		compare_reg = src.compare_reg;
    		compare_op = src.compare_op;
    		victims = src.victims;
    		bounds = src.bounds;
    		if (src.linbounds != nullptr) {
    			linbounds = new Vector<PPLDomain>(*src.linbounds);
    		}
    		_ws = src._ws;
    		if (src._summary != nullptr) {
    			_summary = new PPLSummary(*src._summary);
    		} else {
    			_summary = nullptr;
    		}
    	}
    
    	~PPLDomain();
    
    	inline PPLDomain &operator=(const PPLDomain &dom) {
    		poly = dom.poly;
    		num_axis = dom.num_axis;
    		idmap = dom.idmap;
    		ASSERT(idmap == dom.idmap);
    		compare_reg = dom.compare_reg;
    		compare_op = dom.compare_op;
    		mem_ref = dom.mem_ref;
    		victims = dom.victims;
    		bounds = dom.bounds;
    		_ws = dom._ws;
    		if (linbounds != nullptr) {
    			if (dom.linbounds != nullptr) {
    				*linbounds = *dom.linbounds;
    			} else {
    				delete linbounds;
    				linbounds = nullptr;
    			}
    		} else {
    			if (dom.linbounds != nullptr)
    				linbounds = new Vector<PPLDomain>(*dom.linbounds);
    		}
    		if (_summary != nullptr) {
    			if (dom._summary != nullptr) {
    				*_summary = *dom._summary;
    			} else {
    				delete _summary;
    				_summary = nullptr;
    			}
    		} else {
    			if (dom._summary != nullptr)
    				_summary = new PPLSummary(*dom._summary);
    		}
    		return *this;
    	}
    
    	bool equals(const PPLDomain & /*b*/) const;
    
    	/* Operations that reads the state and returns information about it */
    
    	/**
    	 * Gets summary information 
    	 */
    	PPLSummary *getSummary() {
    		return _summary;
    	}
    
    	/**
    	 * Prints this state (constraints, mappings, and local variables)
    	 */
    	void print(io::Output &out) const;
    
    	/**
    	 * Display local variables in this state
    	 */
    	void displayLocVars(io::Output &out) const;
    
    	/**
    	 * Display global variables in this state
    	 */
    	void displayGlobVars(io::Output &out) const;
    
    	/**
    	 * Display mappings in this state
    	 */
    	void displayIdentMap(io::Output &out) const;
    
    	/**
    	 * Attempts to get the range of possible values for a variable associated with an identifier.
    	 *
    	 * @param id The target identifier
    	 * @param binf_n Reference for storing the numerator for the lower bound
    	 * @param binf_d Reference for storing the denominator for the lower bound
    	 * @param bsup_n Reference for storing the numerator for the upper bound
    	 * @param bsup_d eference for storing the denominator for the upper bound
    	 */
    	void getRange(const Ident &id, PPL::Coefficient &binf_n, PPL::Coefficient &binf_d, PPL::Coefficient &bsup_n,
    	              PPL::Coefficient &bsup_d) const;
    	/**
    	 * Attempts to get the range of possible values for a variable.
    	 *
    	 * @param var The target variable
    	 * @param binf_n Reference for storing the numerator for the lower bound
    	 * @param binf_d Reference for storing the denominator for the lower bound
    	 * @param bsup_n Reference for storing the numerator for the upper bound
    	 * @param bsup_d eference for storing the denominator for the upper bound
    	 */
    	void getRange(const WVar &var, PPL::Coefficient &binf_n, PPL::Coefficient &binf_d, PPL::Coefficient &bsup_n,
    	              PPL::Coefficient &bsup_d) const;
    
    	/**
    	 * Display a fraction on output stream.
    	 *
    	 * @param out The output stream
    	 * @param num Numerator
    	 * @param den Denominator
    	 * @param hex display in hex if true
    	 */
    	void displayFrac(io::Output &out, const PPL::Coefficient &num, const PPL::Coefficient &den, bool hex = false) const;
    
    	/**
    	 * Gets the space dimension of the polyhedron in the current state
    	 *
    	 * @return The space dimension count.
    	 */
    	inline int getVarIDCount() const { return poly.variable_count(); }
    
    	/**
    	 * Gets the number of constraints in the current state
    	 *
    	 * @return The constraint count.
    	 */
    	 int getConsCount() const;
    
    	/**
    	 * Tests if the current state is equivalent to Bottom.
    	 *
    	 * @return true if bottom, false otherwise.
    	 */
    	inline bool isBottom() const { return (num_axis == -1) || poly.is_empty(); }
    
    	/**
    	 * Sets the current state to bottom.
    	 */
    	inline void setBottom() { *this = PPLDomain(); }
    
    	/**
    	 * Tests if the current state has a pending filtering operation, resulting from a condition branch
    	 *
    	 * @return true if pending filtering operation, false otherwise.
    	 */
    	inline bool hasFilter() const { return (compare_reg.getType() != Ident::ID_INVALID); }
    
    	/**
    	 * Tests if two variables may be equal (i.e. exists at least one concrete state in this abstract state where they
    	 * are equal)
    	 *
    	 * @param v1 First variable
    	 * @param v2 Second variable
    	 * @return true if may be equal, false otherwise
    	 */
    	bool mayAlias(const WVar &v1, const WVar &v2) const;
    
    	/**
    	 * Tests if two variables must be equal (i.e. they are equal for all concrete states in this abstract state)
    	 *
    	 * @param v1 First variable
    	 * @param v2 Second variable
    	 * @return true if must be equal, false otherwise
    	 */
    	bool mustAlias(const WVar &v1, const WVar &v2, int offset = 0) const;
    
    	/**
    	 * Attempts to get the value of a a variable mapped to an identifier, if this value can be statically determined,
    	 * and is unique.
    	 *
    	 * @param id The target identifier
    	 * @param cst_n Reference for storing the numerator
    	 * @param cst_d Reference for storing the denominator
    	 * @return true if successful, false if the value cannot be determined.
    	 */
    	bool getConstant(const Ident &id, PPL::Coefficient &cst_n, PPL::Coefficient &cst_d) const;
    
    	/**
    	 * Attempts to get the value of a variable, if this value can be statically determined, and is unique.
    	 *
    	 * @param var The target variable
    	 * @param cst_n Reference for storing the numerator
    	 * @param cst_d Reference for storing the denominator
    	 * @return true if successful, false if the value cannot be determined.
    	 */
    	bool getConstant(const WVar &var, PPL::Coefficient &cst_n, PPL::Coefficient &cst_d) const;
    
    	/* TODO documenter */
    	PPLDomain getLinearExpr(const Ident &id);
    
    	/**
    	 * Attempts to get the current loop bound estimation, in the current state.
    	 *
    	 * @param loopId The ID of the loop header.
    	 * @return loop bound, or bound_t::UNREACHABLE if this state is bottom, or bound_t::UNBOUNDED if loop cannot be
    	 * bounded.
    	 */
    	bound_t getLoopBound(int loopId) const;
    
    	inline bound_t getBound(int loopId) const { 
    		if (bounds.length() <= loopId)
    			return bound_t(0);
    		return bounds[loopId]; 
    	}
    	inline PPLDomain getLinBound(int loopId) const { 
    		if ((linbounds == nullptr) || (linbounds->length() <= loopId))
    			return PPLDomain();
    		return (*linbounds)[loopId];
    	}
    
    	inline void setLinBound(int loopId, PPLDomain bound) {
    		if (bound.isBottom()) 
    			return;
    		if (linbounds == nullptr)
    			linbounds = new Vector<PPLDomain>();
    		if (linbounds->length() <= loopId) {
    			linbounds->setLength(loopId + 1);
    		}
    		delete bound.linbounds;
    		bound.linbounds = nullptr;
    		(*linbounds)[loopId] = (*linbounds)[loopId].onMerge(bound, false);
    	}
    
    	inline void setBound(int loopId, bound_t b) { 
    		if (b == bound_t(0))
    			return;
    		if (bounds.length() <= loopId) {
    			bounds.setLength(loopId + 1);
    			bounds[loopId] = b;
    		} else {
    			if ((bounds[loopId] != bound_t::UNBOUNDED) &&
    			    ((bounds[loopId] < b) || (b == bound_t::UNBOUNDED))) {
    				bounds[loopId] = b;
    			}
    		}
    	}
    
    	/* High-level update operations. They return the modified state. */
    
    	/**
    	 * Compose current state with function summary
    	 *
    	 * @param summary Callee function summary
    	 * 
    	 * @return Composed state
    	 */
    	PPLDomain onCompose(const PPLDomain &summary) const;
    	PPLDomain onComposeBounds(const PPLDomain &summary) const;
    
    	/**
    	 * Process an OTAWA semantic instruction
    	 *
    	 * @param si The semantic instruction
    	 * @param instaddr Instruction address
    	 *
    	 * @return The updated state.
    	 */
    	PPLDomain onSemInst(const sem::inst &si, int instaddr) const;
    
    	/**
    	 * Process a conditional branch instruction, and apply the filtering.
    	 *
    	 * @param taken true if we are processing the TAKEN edge, false otherwise
    	 *
    	 * @return The updated state.
    	 */
    
    	PPLDomain onBranch(bool taken) const;
    
    	/**
    	 * Process join and widening
    	 *
    	 * @param r Other state to merge with
    	 * @param widen true if we perform a widening, false for normal join
    	 * @return The updated state.
    	 */
    	PPLDomain onMerge(const PPLDomain &r, bool widen = false) const;
    	/**
    	 * Process loop entry
    	 *
    	 * @param loop The ID of the loop header.
    	 * @return The updated state.
    	 */
    	PPLDomain onLoopEntry(int loop) const;
    	/**
    	 * Process loop back-edge
    	 *
    	 * @param loop The ID of the loop header.
    	 * @return The updated state.
    	 */
    	PPLDomain onLoopIter(int loop) const;
    	/**
    	 * Process loop exit-edge
    	 *
    	 * @param loop The ID of the loop header.
    	 * @param bound The current estimated bound of the loop (or bound_t::UNREACHABLE/bound_t::UNBOUNDED if loop
    	 * unreachable/unbounded)
    	 * @return The updated state.
    	 */
    	PPLDomain onLoopExit(int loop, int bound) const;
    	PPLDomain onLoopExitLinear(int loop, const PPLDomain &bound) const;
    
    	/* Operations that modify the state in-place */
    
    	/**
    	 * Enable summarization of to-be-analyzed function (must be called before the start of the analysis of this function)
    	 */
    	void enableSummary();
    
    
    	/**
    	 * Map only the polyhedron (without the identifier mappings). This is probably not what you want.
    	 *
    	 * @param pfunc The partial mapping function (see PPL docs)
    	 * @param noproj Prevent PPL from optimizing the projection by classifying it as a permutation
    	 */
    	template <class F> void doMapPoly(F pfunc, bool noproj = false);
    
    	/**
    	 * Map only the identifiers mappings (without the polyhedron). This is probably not what you want.
    	 *
    	 * @param pfunc The partial mapping function (see PPL docs)
    	 */
    	template <class F> void doMapIdents(F pfunc);
    
    	/**
    	 * Map the state according to partial function. This is equivalent to calling doMapPoly + doMapIdents
    	 *
    	 * @param pfunc The partial mapping function (see PPL docs)
    	 * @param noproj Prevent PPL from optimizing the projection by classifying it as a permutation
    	 */
    	template <class F> void doMap(F pfunc, bool noproj = false);
    
    	/**
    	 * Handle integer wrap-around (currently not implemented)
    	 */
    	void doIntegerWrap();
    
    	/**
    	 * Unconstrain (scratch) a variable associated with an identifier.
    	 *
    	 * @param id Target identifier.
    	 */
    	void doScratch(Ident &id);
    
    	/**
    	 * Add a new constraints to the polyhedron
    	 *
    	 * @param c The new constraint to add.
    	 */
    	void doNewConstraint(const WCons &c) { poly.add_constraint(c); }
    
    	/* Variable/Idents handling operations */
    
    	/**
    	 * create a new variable to represent an identifier.
    	 *
    	 * @param id The identifier to associate the variable with.
    	 * @param allow_replace true if we allow replacing an existing variable that was mapped to id, false otherwise
    	 * @return The new variable.
    	 */
    	WVar varNew(const Ident &id, bool allow_replace = false, bool create_damaged = false);
    
    	/**
    	 * Schedule a variable (associated with an identifier) to be destroyed.
    	 * The actual variable removal will be done at the next _doFinalizeUpdate()
    	 *
    	 * @param id Target identifier
    	 */
    	inline void varKill(const Ident &id) { 
    		varKill(WVar(idmap.find1(id)));
    	}
    
    	/**
    	 * Schedule a variable to be destroyed.
    	 * The actual variable removal will be done at the next _doFinalizeUpdate()
    	 *
    	 * @param v Target variable
    	 */
    	inline void varKill(const WVar &v) { 
    		idmap.del2(v.guid());
    		victims.add(v.guid()); 
    	}
    
    	/**
    	 * Gets the variable associated with an identifier, creating a new variable if it doesn't exists (i.e. lookup).
    	 *
    	 * @param id The target identifier
    	 * @param create_input if true, and the identifier is unknown, and we are summarizing, create an input
    	 * @return The variable.
    	 */
    	WVar getVarOrNew(const Ident &id, bool create_input = false);
    
    	/**
    	 * Gets the variable associated with an identifier, aborting if the variables doesn't exists (i.e. lookup).
    	 *
    	 * @param id The target identifier
    	 * @return The variable.
    	 */
    	WVar getVar(const Ident &id) const;
    
    	/**
    	 * Tests if a variable is associated with an identifier.
    	 *
    	 * @param v Variable to test
    	 * @return true if the variable is mapped to an identifier, false otherwise
    	 */
    	inline bool isVarMapped(const WVar &v) const {
    		return idmap.has2(v.guid());
    	}
    
    	/**
    	 * Returns the identifier associated with a variable
    	 *
    	 * @param v The variable
    	 * @return The identifier
    	 */
    	inline const Ident &getIdent(const WVar &v) const { return idmap.find2(v.guid()); }
    
    	/**
    	 * Tests if an identifier exists
    	 *
    	 * @param id The identifier
    	 * @return true if the identifier exists, false otherwise
    	 */
    	bool hasIdent(const Ident & id) const;
    
    	/**
    	 * Schedule all OTAWA semantic-instruction temporary registers to be destroyed.
    	 */
    	void doKillTemporaries();
    
    	/**
    	 * Schedule all hardware registers in bitset to be destroyed (Ri is destroyed if bit i is NOT set in bv)
    	 *
    	 * @param bv Bitset indicating which registers to destroy
    	 */
    	void doKillRegisters(BitVector bv);
    
    	/**
    	 * Schedule the local variables to be destroyed, when leaving a function.
    	 */
    	void doLeaveFunction();
    
    	/**
    	 * Performs garbage-collection of variables scheduled to be destroyed.
    	 */
    	void doFinalizeUpdate();
    
    	/* Pointers/Memory-related operations */
    
    	/**
    	 * Create new memory address/value variable and identifiers.
    	 */
    	void varCreatePtr(Ident & /*addr*/, Ident & /*val*/);
    
    	/**
    	 * Associate a new value to the address variable, replacing existing value.
    	 *
    	 * The variable representing the address is scheduled to be destroyed. It is replaced by another variable
    	 * representing
    	 * the same address, but associated with another value.
    	 *
    	 * The variable representing the old value is scheduled to be destroyed.
    	 *
    	 * @param address A variable representing a memory address.
    	 * @param newValue A variable representing the new memory value.
    	 * @return new address variable
    	 */
    	WVar memReplace(const WVar & address, const WVar & newValue);
    
    	/**
    	 * Create a new abstract memory location at specified address, with the specified value.
    	 *
    	 * @param address A variable representing the memory address.
    	 * @param newValue A variable representing the memory value.
    	 * @param dmg If summarizing, mark address as damaged
    	 * @return new address variable
    	 */
    	WVar memCreate(const WLinExpr & address , const WLinExpr &newValue, bool dmg = true);
    
    	/**
    	 * Associate a new value to the address variable, merging with existing value.
    	 *
    	 * The variable representing the address is scheduled to be destroyed. It is replaced by another variable
    	 * representing
    	 * the same address, but associated with another value.
    	 *
    	 * @param address A variable representing a memory address.
    	 * @param newValue A variable representing the new memory value.
    	 * @return new address variable
    	 */
    	WVar memMerge(const WVar &address, const WVar &newValue);
    
    	/**
    	 * Attempts to use process initial state to discover value associated with a constant address-variable
    	 *
    	 * @param id The identifier associated with the constant address-varialbe
    	 * @param address The constant address (detected from polyhedron)
    	 * @param value The value at the address (recovered from process initial state)
    	 * @return true if success, false otherwise
    	 */
    	bool memGetInitial(const Ident &id, uint32_t &address, uint32_t &value, bool force = false);
    
      private:
    	/* Private helper functions. Subject to changes, and should not be used directly. */
    
    
    	std::set<guid_t> _collectPolyVars(const WPoly &poly) const;
    
    	void _identifyPolyVars(const PPLDomain &d, const std::set<guid_t> &vars, const std::set<guid_t> &indep, MyHTable<guid_t, Vector<PPL::Coefficient> > &vmap) const;
    
    //	int _doAllocAxis(const Ident & /*ident*/, bool allow_replace = false);
    //	void _doFreeAxis(int axis);
    #ifdef POLY_DEBUG
    	void _sanityChecks(bool allow_holes = false);
    #else
    	inline void _sanityChecks(bool allow_holes = false) {}
    #endif
    
    	const WCons *_getConstraintFor(int axis) const;
    	/**
    	 * Indexes the pointer in dom, by their expression in terms of registers referenced in map_regs.
    	 * Stores the result in map_ptr.
    	 */
    	void _indexPointersByExpr(MyHTable<WCons, int, HashCons> &map_ptr,
    	                          MyHTable<int, int> &commonRegs) const;
    
    	void _identifyAncestorVars(PPLDomain &l, MyHTable<int, int> &commonVarsL, PPLDomain &r,
    	                           MyHTable<int, int> &commonVarsR) const;
    
    	/**
    	 * Computes the join or widening of two abstract states
    	 * @param this The first abstract state (will not be modified)
    	 * @param r The second abstract state (will not be modified)
    	 * @return Join or widening result
    	 */
    	void _doBinaryOp(int op, WVar *v, WVar *vs1, WVar *vs2);
    
    	/**
    	 * Unify the two states so that variables refering to the same object (register, memory location, ...) have the same
    	 * number.
    	 *
    	 * @param l First state to unify
    	 * @param r Second state to unify
    	 */
    	void _doUnify(PPLDomain &l1, PPLDomain &r1, bool noPtre=false) const;
    
    	/**
    	 * To be documented
    	 */
    	void _doMatchGlobals(PPLDomain &l1, PPLDomain &r1, 
    		MyHTable<guid_t, Vector<PPL::Coefficient> > &leftVMap, 
    		MyHTable<Vector<PPL::Coefficient> , guid_t, VectCoefIdent> &invRightVMap) const;
    	/**
    	 * To be documented
    	 */
    	void _doMatchSummaries(PPLDomain &l1, PPLDomain &r1, unsigned int &axis, 
    			MyHTable <int,int> &mappingL, MyHTable<int,int> &mappingR,
    			MyHTable<WCons, int, HashCons>&,
    			MyHTable<WCons, int, HashCons>&) const;
    
    };
    
    inline Output &operator<<(Output &o, const PPLDomain &dom) {
    	dom.print(o);
    	return o;
    }
    inline bool operator==(const PPLDomain &a, const PPLDomain &b) { return a.equals(b); }
    inline bool operator!=(const PPLDomain &a, const PPLDomain &b) { return !(a == b); }
    
    } // namespace poly
    } // namespace otawa
    #endif