Otawa  0.10
FastState.h
Go to the documentation of this file.
1 /*
2  * FastState class
3  *
4  * This file is part of OTAWA
5  * Copyright (c) 2011-12, IRIT UPS.
6  *
7  * OTAWA is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * OTAWA is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with OTAWA; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 #ifndef OTAWA_DFA_FASTSTATE_H_
22 #define OTAWA_DFA_FASTSTATE_H_
23 
24 #include <elm/types.h>
25 #include <elm/util/array.h>
26 #include <elm/alloc/StackAllocator.h>
27 #include <otawa/hard/Platform.h>
28 #include "State.h"
29 
30 namespace otawa { namespace dfa {
31 
32 using namespace elm;
33 
34 template <class D>
35 class FastState {
36 public:
39  typedef typename D::t value_t;
40 private:
41 
42  typedef struct node_t {
43  inline node_t(address_t _a, value_t _v, node_t *_n = 0): a(_a), v(_v), n(_n) { }
44  inline node_t(node_t *node): a(node->a), v(node->v), n(0) { }
48  inline void *operator new(size_t size, StackAllocator& alloc) { return alloc.allocate(size); }
49  } node_t;
50 
51  typedef struct state_t {
52  inline state_t(value_t **r, node_t *m): regs(r), mem(m) { }
55  inline void *operator new(size_t size, StackAllocator& alloc) { return alloc.allocate(size); }
56  } stat_t;
57 
58  static const elm::t::size
59  rblock_shift = 3,
60  rblock_mask = (1 << rblock_shift) - 1,
61  rblock_size = 1 << rblock_shift;
62 
63 public:
64  typedef state_t *t;
65 
72  inline FastState(D *d, dfa::State *state, StackAllocator& alloc)
73  : dom(d),
74  nrblock((state->process().platform()->regCount() + rblock_mask) >> rblock_shift),
75  allocator(alloc),
76  bot(make(true)), top(make(false)),
77  multi_max(8),
78  istate(state){ }
79 
84  inline int getMultiMax(void) const { return multi_max; }
85 
90  inline void setMultiMax(int new_multi_max) { multi_max = new_multi_max; }
91 
98  value_t get(t s, register_t r) {
99  ASSERTP(r < nrblock * rblock_size, "register index out of bound");
100  return s->regs[r >> rblock_shift][r & rblock_mask];
101  }
102 
110  t set(t s, register_t r, value_t v) {
111  ASSERTP(r < nrblock * rblock_size, "register index out of bound");
112  //cerr << "DEBUG: set(" << r << ", "; dom->dump(cerr, v); cerr << ")\n";
113  typename D::t *rblock = allocator.allocate<typename D::t>(rblock_size);
114  elm::array::copy(rblock, s->regs[r >> rblock_shift], rblock_size);
115  rblock[r & rblock_mask] = v;
116  typename D::t **regs = allocator.allocate<value_t *>(nrblock);
117  elm::array::copy(regs, s->regs, nrblock);
118  regs[r >> rblock_shift] = rblock;
119  t res = new(allocator) state_t(regs, s->mem);
120  //cerr << "RESULT="; print(cerr, res);
121  return res;
122  }
123 
131  t store(t s, address_t a, value_t v) {
132  node_t *mem, *cur;
133  node_t **pn = &mem;
134 
135  // look for position
136  for(cur = s->mem; cur && cur->a < a; cur = cur->n) {
137  *pn = new(allocator) node_t(cur);
138  pn = &((*pn)->n);
139  }
140 
141  // determine the next node
142  node_t *next;
143  if(!cur)
144  next = 0;
145  else if(cur->a == a)
146  next = cur->n;
147  else
148  next = cur;
149 
150  // create the new node
151  if(v == dom->top)
152  *pn = next;
153  else
154  *pn = new(allocator) node_t(a, v, next);
155 
156  // build the new state
157  return new(allocator) state_t(s->regs, mem);
158  }
159 
167  if(s == bot)
168  return dom->bot;
169  for(node_t *cur = s->mem; cur; cur = cur->n)
170  if(cur->a == a)
171  return cur->v;
172  return dom->top;
173  }
174 
185  ASSERT(a < b);
186  ASSERT(off > 0);
187 
188  // special cases
189  if(s == bot)
190  return s;
191  node_t *mem = 0, *cur = 0;
192  node_t **pn = &mem;
193 
194  // set all nodes of the area to top
195  if((b - a) / off > multi_max || v == D::top) {
196  for(cur = s->mem; cur && cur->a < b; cur = cur->n)
197  if(cur->a != a) {
198  if(a < cur->a)
199  a += (cur->a - a + off - 1) / off * off;
200  *pn = new(allocator) node_t(cur);
201  pn = &((*pn)->n);
202  }
203  }
204 
205  // traverse the memory
206  else {
207  for(cur = s->mem; cur && cur->a < b; cur = cur->n)
208  if(cur->a == a) {
209  value_t v = dom->join(cur->v, v);
210  a += off;
211  if(v != dom->top) {
212  *pn = new(allocator) node_t(cur->a, v);
213  pn = &((*pn)->n);
214  }
215  }
216  else if(a < cur->a)
217  a += (cur->a - a + off - 1) / off * off;
218  else {
219  *pn = new(allocator) node_t(cur);
220  pn = &((*pn)->n);
221  }
222  }
223 
224  // finalize the new state
225  *pn = cur;
226  s = new(allocator) state_t(s->regs, mem);
227  return s;
228  }
229 
236  return new(allocator) state_t(s->regs, 0);
237  }
238 
248  ASSERT(a < b);
249  ASSERT(off > 0);
250 
251  // special cases
252  if((b - a) / off > multi_max)
253  return dom->top;
254 
255  // load the data
256  value_t r = dom->bot;
257  for(node_t *cur = s->mem; cur && cur->a < b; cur = cur->n)
258  if(cur->a == a) {
259  r = dom->join(r, cur->v);
260  a += off;
261  }
262  else if(a < cur->a)
263  a += (cur->a - a + off - 1) / off * off;
264  return r;
265  }
266 
270  t join(t s1, t s2) {
271 
272  // special cases
273  if(s1 == s2)
274  return s1;
275  else if(s1 == top || s2 == top)
276  return top;
277  else if(s1 == bot)
278  return s2;
279  else if(s2 == bot)
280  return s1;
281 
282  // join registers
283  value_t **regs;
284  if(s1->regs == s2->regs)
285  regs = s1->regs;
286  else {
287  regs = allocator.allocate<value_t *>(nrblock);
288  for(int i = 0; i < nrblock; i++) {
289  if(s1->regs[i] == s2->regs[i])
290  regs[i] = s1->regs[i];
291  else {
292  regs[i] = allocator.allocate<value_t>(rblock_size);
293  for(int j = 0; j < rblock_size; j++)
294  regs[i][j] = dom->join(s1->regs[i][j], s2->regs[i][j]);
295  }
296  }
297  }
298 
299  // join memory
300  node_t *mem = 0, *cur1 = s1->mem, *cur2 = s2->mem;
301  node_t **pn = &mem;
302  while(cur1 != cur2 && cur1 && cur2) {
303  if(cur1->a == cur2->a) {
304  *pn = new(allocator) node_t(cur1->a, dom->join(cur1->v, cur2->v));
305  pn = &(*pn)->n;
306  cur1 = cur1->n;
307  cur2 = cur2->n;
308  }
309  // TODO We should take into account initialized memory!
310  else if(cur1->a < cur2->a)
311  cur1 = cur1->n;
312  else
313  cur2 = cur2->n;
314  }
315  if(cur1 == cur2)
316  *pn = cur1;
317  else
318  *pn = 0;
319 
320  // return join state
321  return new(allocator) state_t(regs, mem);
322  }
323 
340  template <class W> t map(t s, W& w) {
341 
342  // register filtering
343  value_t **regs = 0;
344  value_t rblock[rblock_size];
345  for(int i = 0; i < nrblock; i++) {
346 
347  // filter the block
348  bool changed = false;
349  for(int j = 0; j < rblock_size; j++) {
350  rblock[j] = w.process(s->regs[i][j]);
351  changed |= !dom->equals(rblock[j], s->regs[i][j]);
352  }
353 
354  // need duplication?
355  if(changed) {
356  if(!regs) {
357  regs = allocator.allocate<value_t *>(nrblock);
358  if(i > 0)
359  array::copy(regs, s->regs, i);
360  }
361  regs[i] = allocator.allocate<value_t>(rblock_size);
362  array::copy(regs[i], rblock, rblock_size);
363  }
364  else if(regs)
365  regs[i] = s->regs[i];
366  }
367  if(!regs)
368  regs = s->regs;
369 
370  // memory filtering
371  node_t *mem = s->mem;
372  node_t *cur = s->mem, **pn = &mem, *last;
373  for(cur = s->mem, last = s->mem; cur; cur = cur->n) {
374  value_t v = w.process(cur->v);
375  if(!dom->equals(cur->v, v)) {
376 
377  // copy the intermediate nods
378  for(node_t *p = last; p != cur; p = p ->n) {
379  *pn = new(allocator) node_t(p);
380  pn = &((*pn)->n);
381  }
382 
383  // add the changed node
384  *pn = new(allocator) node_t(cur->a, v);
385  last = cur->n;
386  }
387  }
388  *pn = last;
389 
390  // return new state if required
391  if(mem == s->mem && regs == s->regs)
392  return s;
393  else
394  return new(allocator) state_t(regs, mem);
395  }
396 
403  bool equals(t s1, t s2) {
404  if(s1 == s2)
405  return true;
406 
407  // check registers
408  if(s1->regs != s2->regs) {
409  for(int i = 0; i < nrblock; i++)
410  if(s1->regs[i] != s2->regs[i])
411  for(int j = 0; j < rblock_size; j++)
412  if(!dom->equals(s1->regs[i][j], s2->regs[i][j]))
413  return false;
414  }
415 
416  // check memory
417  if(s1->mem != s2->mem) {
418  node_t *c1, *c2;
419  for(c1 = s1->mem, c2 = s2->mem; c1 && c2; c1 = c1->n, c2 = c2->n) {
420  if(c1 == c2)
421  break;
422  if(c1->a != c2->a || !dom->equals(c1->v, c2->v))
423  return false;
424  }
425  if(c1 != c2)
426  return false;
427  }
428 
429  // all is fine
430  return true;
431  }
432 
433  void print(io::Output& out, t s) {
434 
435  // display registers
436  out << '\t';
437  bool fst = true;
438  for(int i = 0; i < nrblock; i++)
439  for(int j = 0; j < rblock_size; j++)
440  if(!dom->equals(s->regs[i][j], dom->bot)) {
441  if(!fst)
442  out << ", ";
443  else
444  fst = false;
445  out << "r" << ((i * rblock_size) + j) << " = ";
446  dom->dump(out, s->regs[i][j]);
447  }
448  if(fst)
449  out << "no register set";
450  out << io::endl;
451 
452  // display memory
453  out << '\t';
454  fst = true;
455  for(node_t *n = s->mem; n; n = n->n) {
456  if(fst)
457  fst = false;
458  else
459  out << ", ";
460  out << Address(n->a) << " = ";
461  dom->dump(out, n->v);
462  }
463  if(fst)
464  out << "no memory set";
465  out << io::endl;
466  }
467 
487  template <class W> t combine(t s1, t s2, W& w) {
488 
489  // special cases
490  if(s1 == s2)
491  return s1;
492  else if(s1 == top || s2 == top)
493  return top;
494  else if(s1 == bot)
495  return s2;
496  else if(s2 == bot)
497  return s1;
498 
499  // join registers
500  value_t **regs;
501  if(s1->regs == s2->regs)
502  regs = s1->regs;
503  else {
504  regs = allocator.allocate<value_t *>(nrblock);
505  for(int i = 0; i < nrblock; i++) {
506  if(s1->regs[i] == s2->regs[i])
507  regs[i] = s1->regs[i];
508  else {
509  regs[i] = allocator.allocate<value_t>(rblock_size);
510  for(int j = 0; j < rblock_size; j++)
511  regs[i][j] = w.process(s1->regs[i][j], s2->regs[i][j]);
512  }
513  }
514  }
515 
516  // join memory
517  node_t *mem = 0, *cur1 = s1->mem, *cur2 = s2->mem;
518  node_t **pn = &mem;
519  while(cur1 != cur2 && cur1 && cur2) {
520 
521  // join the common address
522  if(cur1->a == cur2->a) {
523  *pn = new(allocator) node_t(cur1->a, w.process(cur1->v, cur2->v));
524  pn = &((*pn)->n);
525  cur1 = cur1->n;
526  cur2 = cur2->n;
527  }
528 
529  // else join with T -> T
530  // TODO We should take into account initialized memory!
531  else if(cur1->a < cur2->a)
532  cur1 = cur1->n;
533  else
534  cur2 = cur2->n;
535 
536  }
537  if(cur1 == cur2)
538  *pn = cur1;
539  else
540  *pn = 0;
541 
542  // return join state
543  return new(allocator) state_t(regs, mem);
544  }
545 
546 private:
547 
553  t make(bool bot) {
554  value_t **regs = allocator.allocate<value_t *>(nrblock);
555  for(int i = 0; i < nrblock; i++) {
556  regs[i] = allocator.allocate<value_t>(rblock_size);
557  for(int j = 0; j < rblock_size; j++)
558  regs[i][j] = dom->bot;
559  }
560  return new(allocator) state_t(regs, 0);
561  }
562 
563  D *dom;
568 public:
569  t top, bot;
570 
571 };
572 
573 } } // otawa::dfa
574 
575 #endif /* OTAWA_DFA_FASTSTATE_H_ */
void copy(T *target, const T *source, int size)
t set(t s, register_t r, value_t v)
Set a register value.
Definition: FastState.h:110
elm::t::size nrblock
Definition: FastState.h:564
void print(io::Output &out, t s)
Display the state.
Definition: FastState.h:433
value_t v
Definition: FastState.h:46
t::uint32 address_t
Definition: FastState.h:37
FastState(D *d, dfa::State *state, StackAllocator &alloc)
Build a state.
Definition: FastState.h:72
Fast implementation of abstract domain on the functional state of a microprocessor including the regi...
Definition: FastState.h:35
Definition: FastState.h:42
bool equals(t s1, t s2)
Test if both states are equal.
Definition: FastState.h:403
t::uint32 register_t
Definition: FastState.h:38
state_t * t
Definition: FastState.h:64
value_t ** regs
Definition: FastState.h:53
t combine(t s1, t s2, W &w)
Apply a function to combine two states.
Definition: FastState.h:487
D * dom
Definition: FastState.h:563
node_t(address_t _a, value_t _v, node_t *_n=0)
Definition: FastState.h:43
uint32 size
t store(t s, address_t a, value_t v)
Perform a store to memory.
Definition: FastState.h:131
node_t * mem
Definition: FastState.h:54
int getMultiMax(void) const
Get the max number of multiple load/store before jumping to top.
Definition: FastState.h:84
node_t(node_t *node)
Definition: FastState.h:44
t make(bool bot)
Make a basic state.
Definition: FastState.h:553
t join(t s1, t s2)
Perform join of both states.
Definition: FastState.h:270
D::t value_t
Definition: FastState.h:39
t::uint32 size
Definition: base.h:46
node_t * n
Definition: FastState.h:47
value_t load(t s, address_t a, address_t b, ot::size off)
Load multiple values from a memory area.
Definition: FastState.h:247
The representation of an address in OTAWA.
Definition: base.h:54
address_t a
Definition: FastState.h:45
Represents a value of the data state.
Definition: State.h:86
Property * make(const Identifier< T > &id, const T &v)
Definition: info.h:31
sys::SystemOutStream & out
t storeAtTop(t s)
Store to T address (set all memory to T).
Definition: FastState.h:235
dfa::State * istate
Definition: FastState.h:567
void setMultiMax(int new_multi_max)
Set the maximum number of multiple load/store before approximating to top.
Definition: FastState.h:90
Definition: FastState.h:51
t store(t s, address_t a, address_t b, ot::size off, value_t v)
Perform a multiple-store (joining on all memories that are modified).
Definition: FastState.h:184
StackAllocator & allocator
Definition: FastState.h:565
int multi_max
Definition: FastState.h:566
state_t(value_t **r, node_t *m)
Definition: FastState.h:52
t top
Definition: FastState.h:569
value_t load(t s, address_t a)
Perform a load at the given address.
Definition: FastState.h:166
t map(t s, W &w)
Apply a function to transform a state.
Definition: FastState.h:340
uint32_t uint32