Commit 0ded6f5d authored by Ballabriga Clément's avatar Ballabriga Clément
Browse files

interprocedural: boucles a bornes parametriques

parent eb7d4dd6
......@@ -147,6 +147,7 @@ class PPLDomain {
BitVector trash; ///< Bitvector representing the set of variables scheduled to be destroyed
Vector<bound_t> bounds;
Vector<PPLDomain> *linbounds = NULL;
WorkSpace *_ws;
......@@ -269,6 +270,9 @@ class PPLDomain {
compare_op = src.compare_op;
trash = src.trash;
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);
......@@ -290,6 +294,17 @@ class PPLDomain {
trash = dom.trash;
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;
......@@ -458,6 +473,25 @@ class PPLDomain {
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;
......@@ -482,6 +516,7 @@ class PPLDomain {
* @return Composed state
*/
PPLDomain onCompose(const PPLDomain &summary) const;
PPLDomain onComposeBounds(const PPLDomain &summary) const;
/**
* Process an OTAWA semantic instruction
......@@ -534,6 +569,7 @@ class PPLDomain {
* @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 */
......
......@@ -72,13 +72,13 @@ class PolyAnalysis : public Processor {
private:
using state_t = PPLManager::t;
void processCFG(CFG & /* cfg */, state_t & /* s */, bool /* isEntryCFG */, bool /* summarize */);
void processBB(PPLManager *man, ai::CFGGraph &graph,
void processCFG(CFG & /* cfg */, state_t & /* s */, MyHTable<int,PPLDomain> &, bool /* isEntryCFG */, bool /* summarize */);
void processBB(PPLManager *man, ai::CFGGraph &graph, MyHTable<int,PPLDomain> &,
WorkListDriver<PPLManager, ai::CFGGraph, ai::EdgeStore<PPLManager, ai::CFGGraph>, PseudoTopoOrder> &ana,
ai::EdgeStore<PPLManager, ai::CFGGraph> &store,
MyHTable<int, state_t> &headerState);
const PropList *_props{};
state_t processHeader(ai::CFGGraph &graph, BasicBlock *header, PPLManager& man, ai::EdgeStore<PPLManager, ai::CFGGraph>& store, MyHTable<int, state_t> &headerState);
state_t processHeader(ai::CFGGraph &graph, MyHTable<int,PPLDomain> &, BasicBlock *header, PPLManager& man, ai::EdgeStore<PPLManager, ai::CFGGraph>& store, MyHTable<int, state_t> &headerState);
......
......@@ -24,6 +24,7 @@ extern Identifier<int> LOC_VAR_SIZE;
extern Identifier<int> MAX_AXIS;
extern Identifier<bool> SUMMARIZE;
extern Identifier<PPLDomain*> SUMMARY;
extern Identifier<MyHTable<int, PPLDomain>* > MAX_LINEAR;
extern p::feature POLY_ANALYSIS_FEATURE;
} // namespace poly
} // namespace otawa
......
......@@ -103,6 +103,7 @@ Output &operator<<(Output &o, const Variable pv) {
PPLDomain::~PPLDomain() {
delete _summary;
delete linbounds;
}
void PPLDomain::print(io::Output &out) const {
......@@ -324,6 +325,10 @@ void PPLDomain::displayLocVars(io::Output &out) const {
return;
}
Ident id_ssp(Ident::ID_START_SP, Ident::ID_SPECIAL);
if (!hasIdent(id_ssp)) {
cout << "Local variables: NOT APPLICABLE" << endl;
return;
}
Variable ssp = getVar(id_ssp);
out << "Local variables: " << endl;
for (int i = 0; i < NUM_LOC_VARS(_props) * LOC_VAR_SIZE(_props); i += LOC_VAR_SIZE(_props)) {
......@@ -486,7 +491,11 @@ void PPLDomain::displayIdentMap(io::Output &out) const {
out << endl;
}
//comme getLoopBound() mais renvoie une surapproximation de l'expression lineaire de la variable d'induction
PPLDomain PPLDomain::getLinearExpr(const Ident &id) {
if (isBottom()) {
return *this;
}
MyHTable<int, int> inputs;
int axis = 1;
PPLDomain dom(*this); /* make a working copy to do the projections */
......@@ -498,10 +507,11 @@ PPLDomain PPLDomain::getLinearExpr(const Ident &id) {
axis++;
}
}
dom.doMapPoly(MapWithHash(inputs));
dom.doMap(MapWithHash(inputs));
return dom;
}
// getLoopBound: a appeler a l'INTERIEUR de la boucle pour avoir une maximisation de la variable d'induction
bound_t PPLDomain::getLoopBound(int loopId) const {
if (isBottom()) {
return bound_t::UNREACHABLE;
......@@ -515,6 +525,57 @@ bound_t PPLDomain::getLoopBound(int loopId) const {
return bound_t::UNBOUNDED;
}
PPLDomain PPLDomain::onLoopExitLinear(int loop, const PPLDomain &bound) const {
PPLManager::t s_out = *this;
Ident id(loop, Ident::ID_LOOP);
ASSERT(s_out.hasIdent(id)); /* You are supposed to be already inside the loop when you call onLoopExit() */
Variable v = s_out.getVar(id);
MyHTable<int,int> map;
Vector<int> mapped;
for (MyHTable<Ident, int, HashIdent>::PairIterator it(bound.id2axis); it; it++) {
if (((*it).fst.getType() == Ident::ID_REG_INPUT) || ((*it).fst.getType() == Ident::ID_MEM_VAL_INPUT) || ((*it).fst == id)) {
if (hasIdent((*it).fst)) {
const Variable &v2 = getVar((*it).fst);
map[(*it).snd] = v2.id();
cout << (*it).snd << " to " << v2.id() << endl;
mapped.add(v2.id());
}
}
}
PPLDomain copy(bound);
cout << "avant remap: "; fflush(stdout);
copy.poly.minimized_constraints().print(); fflush(stdout); cout << endl;
copy.doMapPoly(MapWithHash(map));
for (PPL::dimension_type i = 0; i < copy.poly.space_dimension(); i++) {
if (!mapped.contains(i)) {
copy.poly.unconstrain(Variable(i));
}
}
cout << "apres remap: "; fflush(stdout);
copy.poly.minimized_constraints().print(); fflush(stdout); cout << endl;
if (copy.poly.space_dimension() < s_out.poly.space_dimension()) {
copy.poly.add_space_dimensions_and_embed(s_out.poly.space_dimension() - copy.poly.space_dimension());
}
s_out.poly.intersection_assign(copy.poly);
cout << "==" << endl;
fflush(stdout);
poly.minimized_constraints().print();
fflush(stdout);
cout << endl;
fflush(stdout);
copy.poly.minimized_constraints().print();
fflush(stdout);
cout << "==" << endl;
cout << "before onLoopExitLinear: " << *this << endl;
cout << " after onLoopExitLinear: " << s_out << endl;
s_out.varKill(v);
return s_out;
}
PPLDomain PPLDomain::onLoopExit(int loop, int bound) const {
PPLManager::t s_out = *this;
Ident id(loop, Ident::ID_LOOP);
......@@ -622,6 +683,47 @@ PPLDomain PPLDomain::onBranch(bool taken) const {
}
return res;
}
PPLDomain PPLDomain::onComposeBounds(const PPLDomain &bound) const {
PPLDomain out = bound;
// decaler
out.doMap(MapShift(bound.poly.space_dimension(), poly.space_dimension()));
PPL::dimension_type i;
for (i = 0; i < poly.space_dimension(); i++)
out.poly.unconstrain(Variable(i));
PPL::C_Polyhedron src(poly);
src.add_space_dimensions_and_embed(bound.poly.space_dimension());
out.poly.intersection_assign(src);
// registers
for (MyHTable<Ident, int, HashIdent>::PairIterator it(out.id2axis); it; it++) {
if ((*it).fst.getType() == Ident::ID_REG_INPUT) {
#ifdef POLY_DEBUG
cout << "Link input register: " << (*it).fst << endl;;
#endif
int nreg = (*it).fst.getId();
Ident idRegCaller(nreg, Ident::ID_REG);
if (hasIdent(idRegCaller))
out.doNewConstraint(out.getVar((*it).fst) == getVar(idRegCaller));
}
}
PPL::dimension_type max_axis = 0;
for (PPL::dimension_type i = 0; i < out.poly.space_dimension(); i++) {
if (out.axis2id[i].getType() == Ident::ID_INVALID) {
Variable v(i);
#ifdef POLY_DEBUG
cout << "Killing variable: " << v << endl;
#endif
out.trash.set(i);
}
if (max_axis < i)
max_axis = i;
}
out.num_axis = max_axis + 1;
out.doFinalizeUpdate();
return out;
}
PPLDomain PPLDomain::onCompose(const PPLDomain &summary) const {
PPLDomain out = summary;
// decaler
......@@ -735,9 +837,11 @@ PPLDomain PPLDomain::onCompose(const PPLDomain &summary) const {
Ident id_ssp(Ident::ID_START_SP, Ident::ID_SPECIAL);
Ident id_sfp(Ident::ID_START_FP, Ident::ID_SPECIAL);
Ident id_slr(Ident::ID_START_LR, Ident::ID_SPECIAL);
out.doNewConstraint(getVar(id_ssp) == out.getVar(id_ssp));
out.doNewConstraint(getVar(id_sfp) == out.getVar(id_sfp));
out.doNewConstraint(getVar(id_slr) == out.getVar(id_slr));
if (hasIdent(id_ssp) && out.hasIdent(id_ssp)) {
out.doNewConstraint(getVar(id_ssp) == out.getVar(id_ssp));
out.doNewConstraint(getVar(id_sfp) == out.getVar(id_sfp));
out.doNewConstraint(getVar(id_slr) == out.getVar(id_slr));
}
#ifdef POLY_DEBUG
cout << "Inject loop bounds" << endl;
......@@ -2248,6 +2352,7 @@ Identifier<int> LOC_VAR_SIZE("otawa::poly::LOC_VAR_SIZE", 4);
Identifier<int> NUM_LOC_VARS("otawa::poly::NUM_LOC_VARS", 8);
Identifier<int> MAX_AXIS("otawa::poly::MAX_AXIS", 512);
Identifier<PPLDomain*> SUMMARY("otawa::poly::SUMMARY", nullptr);
Identifier<MyHTable<int, PPLDomain> * > MAX_LINEAR("otawa::poly::MAX_LINEAR", nullptr);
Identifier<bool> SUMMARIZE("otawa::poly::SUMMARIZE", false);
} // namespace poly
......
......@@ -37,7 +37,8 @@ void PolyAnalysis::configure(const PropList &props) {
_props = &props;
}
PolyAnalysis::state_t PolyAnalysis::processHeader(ai::CFGGraph &graph, BasicBlock *header, PPLManager& man, ai::EdgeStore<PPLManager, ai::CFGGraph>& store, MyHTable<int, state_t> &headerState) {
PolyAnalysis::state_t PolyAnalysis::processHeader(ai::CFGGraph &graph, MyHTable<int,PPLDomain> &lb,
BasicBlock *header, PPLManager& man, ai::EdgeStore<PPLManager, ai::CFGGraph>& store, MyHTable<int, state_t> &headerState) {
state_t entryState = man.bot();
state_t backState = man.bot();
......@@ -67,13 +68,28 @@ PolyAnalysis::state_t PolyAnalysis::processHeader(ai::CFGGraph &graph, BasicBloc
bound_t bound = backState.getLoopBound(header->id());
backState.setBound(header->id(), bound);
PPLDomain linearBound = backState.getLinearExpr(Ident(header->id(), Ident::ID_LOOP));
// cout << "setBound: " << int(bound) << endl;
cout << "has state: " << backState << endl;
cout << "got linear bound: " << linearBound << endl;
backState.setLinBound(header->id(), linearBound);
#ifdef POLY_DEBUG
cout << "ITERATION: " << int(bound) << endl;
#endif
/*
if ((MAX_ITERATION(header) != bound_t::UNBOUNDED) &&
((MAX_ITERATION(header) < bound) || (bound == bound_t::UNBOUNDED)))
MAX_ITERATION(header) = bound;
*/
if (!lb.hasKey(header->id()))
lb[header->id()] = PPLDomain();
const PPLDomain &oldBound = lb[header->id()];
lb[header->id()] = oldBound.onMerge(linearBound, false);
headerState[header->id()] = man.widening(backState, headerState[header->id()]);
#ifdef POLY_DEBUG
......@@ -96,7 +112,7 @@ PolyAnalysis::state_t PolyAnalysis::processHeader(ai::CFGGraph &graph, BasicBloc
return headerState[header->id()];
}
void PolyAnalysis::processBB(PPLManager *man, ai::CFGGraph &graph,
void PolyAnalysis::processBB(PPLManager *man, ai::CFGGraph &graph, MyHTable<int,PPLDomain> &lb,
WorkListDriver<PPLManager, ai::CFGGraph, ai::EdgeStore<PPLManager, ai::CFGGraph>, PseudoTopoOrder> &ana,
ai::EdgeStore<PPLManager, ai::CFGGraph>& store,
MyHTable<int, state_t> &headerState) {
......@@ -119,10 +135,19 @@ void PolyAnalysis::processBB(PPLManager *man, ai::CFGGraph &graph,
state_t sum;
if (SUMMARY(subCFG) == nullptr) {
cout << "No summary exists for " << (*ana)->toSynth()->callee()->name() << ", creating one..." << endl;
processCFG(*subCFG, sum, true, true);
MyHTable<int, PPLDomain> *sublb = new MyHTable<int, PPLDomain>();
processCFG(*subCFG, sum, *sublb, true, true);
cout << "Finished creating summary of " << subCFG->name() << ", returning to " << (*ana)->toSynth()->caller()->name() << endl;
SUMMARY(subCFG) = new PPLDomain(sum);
MAX_LINEAR(subCFG) = sublb;
cout << "summary = " << endl;
cout << sum << endl;
cout << "parametric bounds = " << endl;
for (MyHTable<int, PPLDomain>::PairIterator it(*sublb); it; it++) {
cout << (*it).fst << " --> " << (*it).snd << endl;
}
cout << endl;
} else {
cout << "Reusing existing summary." << endl;
PPLDomain *p = SUMMARY(subCFG);
......@@ -135,6 +160,19 @@ void PolyAnalysis::processBB(PPLManager *man, ai::CFGGraph &graph,
cout << sum << endl;
#endif
s = s.onCompose(sum);
// TODO: compose lb with summary
MyHTable<int, PPLDomain> *sublb = MAX_LINEAR(subCFG);
for (MyHTable<int, PPLDomain>::PairIterator it(*sublb); it; it++) {
cout << "Compose loop bound: " << (*it).fst << " --> " << (*it).snd << endl;
PPLDomain composed((*it).snd);
composed = s.onCompose(composed);
composed = composed.getLinearExpr(Ident((*it).fst, Ident::ID_LOOP));
cout << "Compose loop bound: " << (*it).fst << " --> " << composed << endl;
if (!lb.hasKey((*it).fst))
lb[(*it).fst] = PPLDomain();
lb[(*it).fst] = lb.get((*it).fst).value().onMerge(composed, false);
}
#ifdef POLY_DEBUG
cout << "Composed state = " << endl;
......@@ -152,7 +190,7 @@ void PolyAnalysis::processBB(PPLManager *man, ai::CFGGraph &graph,
(*ana)->toSynth()->callee()->name() == "gsignal") {
cout << "[FIXME] Ignoring call to function: " << (*ana)->toSynth()->callee()->name() << endl;
} else {
processCFG(*subCFG, s, false, false);
processCFG(*subCFG, s, lb, false, false);
cout << "Return from " << subCFG->name() << " to " << (*ana)->toSynth()->caller()->name() << endl;
}
}
......@@ -172,7 +210,7 @@ void PolyAnalysis::processBB(PPLManager *man, ai::CFGGraph &graph,
#ifdef POLY_DEBUG
cout << "Basic block is loop header: " << bl->id() << endl;
#endif
s = processHeader(graph, bl, *man, store, headerState);
s = processHeader(graph, lb, bl, *man, store, headerState);
} else {
s = ana.input();
}
......@@ -266,8 +304,10 @@ void PolyAnalysis::processBB(PPLManager *man, ai::CFGGraph &graph,
if (Dominance::dominates(e->sink(), e->source())) {
/* Back-Edge: increment virtual loop counter */
edgeState = edgeState.onLoopIter(e->sink()->id());
cout << "loop iter! " << endl;
} else {
/* Entry-Edge: initialize virtal loop counter */
cout << "loop entry! " << endl;
edgeState = edgeState.onLoopEntry(e->sink()->id());
/* Avoid unnecessary widening before first loop iteration of inner loops */
......@@ -283,15 +323,24 @@ void PolyAnalysis::processBB(PPLManager *man, ai::CFGGraph &graph,
* FIXME: should be bound = s.getLoopBound(bb->id()) but we need to fix the widening to make it work
*/
int bound = edgeState.getBound(bb->id());
PPLDomain linBound = edgeState.getLinBound(bb->id());
#ifdef POLY_DEBUG
cout << "Bound on loop exit: " << bound << endl;
#endif
cout << "LinBound on loop exit: " << linBound << endl;
if (!linBound.isBottom()) {
edgeState = edgeState.onLoopExitLinear(bb->id(), linBound);
if (edgeState.isBottom())
continue;
}
/*
if (bound >= 0) {
edgeState = edgeState.onLoopExit(bb->id(), bound);
if (edgeState.isBottom()) {
continue;
}
}
*/
}
edgeState.doFinalizeUpdate();
ana.check(*e, edgeState);
......@@ -378,7 +427,7 @@ void PolyAnalysis::PseudoTopoOrder::_getPseudoTopo(const ai::CFGGraph &graph) {
_visited = nullptr;
}
void PolyAnalysis::processCFG(CFG &cfg, state_t &s, bool isEntryCFG, bool summarize) {
void PolyAnalysis::processCFG(CFG &cfg, state_t &s, MyHTable<int, PPLDomain> &lb, bool isEntryCFG, bool summarize){
PPLManager *man = isEntryCFG ? (new PPLManager(*_props, workspace())) : (new PPLManager(s, *_props, workspace()));
if (summarize) {
ASSERT(isEntryCFG);
......@@ -395,7 +444,7 @@ void PolyAnalysis::processCFG(CFG &cfg, state_t &s, bool isEntryCFG, bool summar
WorkListDriver<PPLManager, ai::CFGGraph, ai::EdgeStore<PPLManager, ai::CFGGraph>, PseudoTopoOrder> ana(*man, graph, store, _orders[cfg.index()]);
while (ana) {
processBB(man, graph, ana, store, headerState);
processBB(man, graph, lb, ana, store, headerState);
ana++;
}
......@@ -440,14 +489,31 @@ void PolyAnalysis::processWorkSpace(WorkSpace *ws) {
CFG *entry = coll->get(0);
state_t dummy;
ASSERT(dummy.getSummary() == nullptr);
SUMMARIZE(ws) = false;
processCFG(*entry, dummy, true /* is entry */, false /* summarize */);
SUMMARIZE(ws) = true;
MyHTable<int, PPLDomain> bounds;
MyHTable<int, int> static_bounds;
processCFG(*entry, dummy, bounds, true /* is entry */, false /* summarize */);
for (MyHTable<int, PPLDomain>::PairIterator it(bounds); it; it++) {
cout << "Parametric loop bound: " << (*it).fst << " --> " << (*it).snd << endl;
PPL::Coefficient binf_n, binf_d, bsup_n, bsup_d;
Ident id((*it).fst, Ident::ID_LOOP);
if (!(*it).snd.hasIdent(id)) {
static_bounds[(*it).fst] = bound_t::UNREACHABLE;
continue;
}
(*it).snd.getRange(id, binf_n, binf_d, bsup_n, bsup_d);
if (PPL::raw_value(bsup_d).get_ui() != 0) {
static_bounds[(*it).fst] =
static_cast<bound_t>(PPL::raw_value(bsup_n).get_ui() / PPL::raw_value(bsup_d).get_ui());
} else static_bounds[(*it).fst] = bound_t::UNBOUNDED;
}
cout << "LOOP BOUNDS: " << endl;
for (CFGCollection::Iter iter2(coll); iter2; iter2++) {
for (CFG::BlockIter iter((*iter2)->blocks()); iter; iter++) {
Block *bb = (*iter);
if (LOOP_HEADER(bb)) {
MAX_ITERATION(bb) = static_bounds[bb->id()];
cout << "[" << (*iter2)->name() << "]"
<< "MAX_ITERATION(" << bb->id() << ") = " << MAX_ITERATION(bb) << endl;
cout << "[" << (*iter2)->name() << "]"
......
......@@ -3,7 +3,7 @@ if [ "$1" = "" ]; then
echo "Usage: ./do.sh <C program without extension>"
fi
arm-unknown-linux-gnueabi-gcc -o "${1}" "${1}.c" -static -g
arm-unknown-linux-gnueabi-gcc -o "${1}" "${1}.c" -static -g -O0
if [ "$?" != "0" ]; then
echo "Compilation error"
exit 1
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment