HPCToolkit
VMAInterval.cpp
Go to the documentation of this file.
1 // -*-Mode: C++;-*-
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // $HeadURL$
6 // $Id$
7 //
8 // --------------------------------------------------------------------------
9 // Part of HPCToolkit (hpctoolkit.org)
10 //
11 // Information about sources of support for research and development of
12 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
13 // --------------------------------------------------------------------------
14 //
15 // Copyright ((c)) 2002-2019, Rice University
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are
20 // met:
21 //
22 // * Redistributions of source code must retain the above copyright
23 // notice, this list of conditions and the following disclaimer.
24 //
25 // * Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // * Neither the name of Rice University (RICE) nor the names of its
30 // contributors may be used to endorse or promote products derived from
31 // this software without specific prior written permission.
32 //
33 // This software is provided by RICE and contributors "as is" and any
34 // express or implied warranties, including, but not limited to, the
35 // implied warranties of merchantability and fitness for a particular
36 // purpose are disclaimed. In no event shall RICE or contributors be
37 // liable for any direct, indirect, incidental, special, exemplary, or
38 // consequential damages (including, but not limited to, procurement of
39 // substitute goods or services; loss of use, data, or profits; or
40 // business interruption) however caused and on any theory of liability,
41 // whether in contract, strict liability, or tort (including negligence
42 // or otherwise) arising in any way out of the use of this software, even
43 // if advised of the possibility of such damage.
44 //
45 // ******************************************************* EndRiceCopyright *
46 
47 //***************************************************************************
48 //
49 // File:
50 // $HeadURL$
51 //
52 // Purpose:
53 // [The purpose of this file]
54 //
55 // Description:
56 // [The set of functions, macros, etc. defined in the file]
57 //
58 //***************************************************************************
59 
60 //************************* System Include Files ****************************
61 
62 #include <iostream>
63 using std::cerr;
64 using std::endl;
65 using std::hex;
66 using std::dec;
67 
68 #include <typeinfo>
69 
70 #include <string>
71 using std::string;
72 
73 #include <cstring>
74 
75 //*************************** User Include Files ****************************
76 
77 #include "VMAInterval.hpp"
78 
80 #include <lib/support/StrUtil.hpp>
81 
82 //*************************** Forward Declarations **************************
83 
84 #define DBG 0
85 
86 //***************************************************************************
87 
88 //***************************************************************************
89 // VMAInterval
90 //***************************************************************************
91 
92 string
94 {
95  string self = "["
96  + StrUtil::toStr(m_beg, 16) + "-"
97  + StrUtil::toStr(m_end, 16) + ")";
98  return self;
99 }
100 
101 
102 void
103 VMAInterval::fromString(const char* formattedstr)
104 {
105  const char* s = formattedstr;
106  const char* p = formattedstr;
107  if (!p) { return; }
108 
109  // -----------------------------------------------------
110  // 1. ignore leading whitespace
111  // -----------------------------------------------------
112  while (*p != '\0' && isspace(*p)) { p++; }
113  if (*p == '\0') { return; }
114 
115  // -----------------------------------------------------
116  // 2. parse
117  // -----------------------------------------------------
118  // skip '['
119  DIAG_Assert(*p == '[', DIAG_UnexpectedInput << "'" << s << "'");
120  p++;
121 
122  // read 'm_beg'
123  unsigned endidx;
124  m_beg = StrUtil::toUInt64(p, &endidx);
125  p += endidx;
126 
127  // skip '-'
128  DIAG_Assert(*p == '-', DIAG_UnexpectedInput << "'" << s << "'");
129  p++;
130 
131  // read 'm_end'
132  m_end = StrUtil::toUInt64(p, &endidx);
133  p += endidx;
134 
135  // skip ')'
136  DIAG_Assert(*p == ')', DIAG_UnexpectedInput << "'" << s << "'");
137 }
138 
139 
140 std::ostream&
141 VMAInterval::dump(std::ostream& os) const
142 {
143  os << std::showbase;
144  os << std::hex << "[" << m_beg << "-" << m_end << ")" << std::dec;
145  return os;
146 }
147 
148 
149 void
151 {
152  dump(std::cout);
153  std::cout.flush();
154 }
155 
156 
157 //***************************************************************************
158 // VMAIntervalSet
159 //***************************************************************************
160 
161 // Given an interval x to insert or delete from the interval set, the
162 // following cases are possible where x is represented by <> and
163 // existing interval set by {}.
164 //
165 // We first find lb and ub such that: (lb <= x < ub) and lb != x.
166 //
167 // 0) lb interval already contains x
168 // {lb <> }
169 // {lb <> } ...
170 // ... {lb <> }
171 // ... {lb <> } ...
172 // 1) x is a mutually exclusive interval:
173 // a. <>
174 // b. <> {ub} ...
175 // c. ... {lb} <>
176 // d. ... {lb} <> {ub} ...
177 // 2) x overlaps only the lb interval
178 // a. ... {lb < } ... {} >
179 // b. ... {lb < } ... {} > {ub} ...
180 // 3) x overlaps only the ub interval:
181 // a. < {} ... { > ub} ...
182 // b. ... {lb} < {} ... { > ub} ...
183 // 4) x overlaps both lb and ub interval
184 // ... {lb < } ... { > ub} ...
185 // 5) x subsumes all intervals
186 // < {} ... {} >
187 
188 typedef std::pair <VMAIntervalSet::iterator, bool> iteratorPair;
189 
190 // insert: See above for cases
193 {
194  DIAG_DevMsgIf(DBG, "VMAIntervalSet::insert [begin]\n"
195  << " this: " << toString() << endl
196  << " add : " << x.toString());
197 
198  // empty interval
199  if (x.empty()) {
200  return iteratorPair (end(), false);
201  }
202 
203  // empty set
204  if (empty()) {
205  return My_t::insert(x);
206  }
207 
208  VMA low = x.beg();
209  VMA high = x.end();
210 
211  // find it = last interval with it.beg <= low if there is one, or
212  // else first interval with it.beg > low, but it is never end().
213  // this is the only interval that could contain low.
214  auto it = upper_bound(VMAInterval(low, low));
215 
216  if (it != begin() && (it == end() || it->beg() > low)) {
217  it--;
218  }
219 
220  // if x is a subset of it, then return it. this is the only case
221  // that returns false (not created).
222  if (it->beg() <= low && high <= it->end()) {
223  return iteratorPair (it, false);
224  }
225 
226  // if x intersects interval to the left, then extend low. this can
227  // only happen once at it.
228  if (it->beg() <= low) {
229  auto next_it = it; next_it++;
230 
231  if (it->end() >= low) {
232  low = std::min(low, it->beg());
233  My_t::erase(it);
234  }
235  it = next_it;
236  }
237 
238  // if x intersects intervals to the right, then extend high. this
239  // can happen multiple times.
240  while (it != end() && it->beg() <= high) {
241  auto next_it = it; next_it++;
242  high = std::max(high, it->end());
243  My_t::erase(it);
244  it = next_it;
245  }
246 
247  // finally, re-insert [low, high) which covers all of the erased
248  // intervals plus the original x.
249  return My_t::insert(VMAInterval(low, high));
250 }
251 
252 
253 // erase: See above for cases
254 void
256 {
257  if (x.empty()) {
258  return;
259  }
260 
261  // -------------------------------------------------------
262  // find [lb, ub) where lb is the first element !< x and ub is the
263  // first element > x. IOW, if lb != end() then (x <= lb < ub).
264  // -------------------------------------------------------
265  std::pair<VMAIntervalSet::iterator, VMAIntervalSet::iterator> lu =
266  equal_range(x);
267  VMAIntervalSet::iterator lb = lu.first;
268  VMAIntervalSet::iterator ub = lu.second;
269 
270  // find (lb <= x < ub) such that lb != x
271  if (lb == end()) {
272  if (!empty()) { // all elements are less than x
273  lb = --end();
274  }
275  }
276  else {
277  if (lb == begin()) { // no element is less than x
278  lb = end();
279  }
280  else {
281  --lb;
282  }
283  }
284 
285  // -------------------------------------------------------
286  // Detect the appropriate case. Note that we do not have to
287  // explicitly consider Case 1 since it amounts to a NOP.
288  // -------------------------------------------------------
289  VMA lb_beg = (lb != end()) ? lb->beg() : 0;
290  VMA ub_end = (ub != end()) ? ub->end() : 0;
291 
292  if (lb != end() && lb->contains(x)) {
293  // Case 0: split interval: erase [lb, ub);
294  // insert [lb->beg(), x.beg()), [x.end(), lb->end())
295  VMA lb_end = lb->end();
296  My_t::erase(lb, ub);
297  if (lb_beg < x.beg()) {
298  My_t::insert( VMAInterval(lb_beg, x.beg()) );
299  }
300  if (lb_end > x.end()) {
301  My_t::insert( VMAInterval(x.end(), lb_end) );
302  }
303  }
304  else if (lb == end() && ub == end()) { // size >= 1
305  if (!empty()) {
306  // Case 5: erase everything
307  My_t::clear();
308  }
309  }
310  else if (lb == end()) {
311  // INVARIANT: ub != end()
312 
313  if ( !(x.end() < ub->beg()) ) {
314  // Case 3a: erase [begin(), ub + 1); insert [x.end(), ub->end())
316  My_t::erase(begin(), ++end);
317  if (x.end() < ub_end) {
318  My_t::insert( VMAInterval(x.end(), ub_end) );
319  }
320  }
321  }
322  else if (ub == end()) {
323  // INVARIANT: lb != end()
324 
325  if ( !(lb->end() < x.beg()) ) {
326  // Case 2a: erase [lb, end()); insert [lb->beg(), x.beg())
327  My_t::erase(lb, end());
328  if (lb_beg < x.beg()) {
329  My_t::insert( VMAInterval(lb_beg, x.beg()) );
330  }
331  }
332  }
333  else {
334  // INVARIANT: lb != end() && ub != end()
335 
336  if (x.beg() <= lb->end() && x.end() < ub->beg()) {
337  // Case 2b: erase [lb, ub); insert [lb->beg(), x.beg())
338  My_t::erase(lb, ub);
339  if (lb_beg < x.beg()) {
340  My_t::insert( VMAInterval(lb_beg, x.beg()) );
341  }
342  }
343  else if (lb->end() < x.beg() && ub->beg() <= x.end()) {
344  // Case 3b: erase [lb + 1, ub + 1): insert [x.end(), ub->end())
347  My_t::erase(++beg, ++end);
348  if (x.end() < ub_end) {
349  My_t::insert( VMAInterval(x.end(), ub_end) );
350  }
351  }
352  else if ( !(lb->end() < x.beg() && x.end() < ub->beg()) ) {
353  // Case 4: erase [lb, ub + 1);
354  // insert [lb->beg(), x.beg()) and [x.end(), ub->end()).
356  My_t::erase(lb, ++end);
357  My_t::insert( VMAInterval(lb_beg, x.beg()) );
358  My_t::insert( VMAInterval(x.end(), ub_end) );
359  }
360  }
361 }
362 
363 
364 void
366 {
367  for (const_iterator it = x.begin(); it != x.end(); ++it) {
368  insert(*it); // the overloaded insert
369  }
370 }
371 
372 
373 string
375 {
376  string self = "{";
377  bool needSeparator = false;
378  for (const_iterator it = this->begin(); it != this->end(); ++it) {
379  if (needSeparator) { self += " "; }
380  self += (*it).toString();
381  needSeparator = true;
382  }
383  self += "}";
384  return self;
385 }
386 
387 
388 void
389 VMAIntervalSet::fromString(const char* formattedstr)
390 {
391  const char* s = formattedstr;
392  const char* p = formattedstr;
393 
394  // ignore leading whitespace
395  if (!p || p[0] == '\0') { return; }
396 
397  // skip '{'
398  DIAG_Assert(*p == '{', DIAG_UnexpectedInput << "'" << s << "'");
399  p++;
400  // INVARIANT: q points to either next interval or close of set
401 
402  // find intervals: p points to '[' and q points to ')'
403  const char* q = p;
404  while ( (p = strchr(q, '[')) ) {
405  VMAInterval vmaint(p);
406  insert(vmaint); // the overloaded insert
407 
408  // post-INVARIANT: q points to either next interval or close of set
409  q = strchr(p, ')');
410  q++;
411  }
412 
413  // skip '}'
414  DIAG_Assert(*q == '}', DIAG_UnexpectedInput << "'" << s << "'");
415  p++;
416 }
417 
418 
419 std::ostream&
420 VMAIntervalSet::dump(std::ostream& os) const
421 {
422  bool needSeparator = false;
423  os << "{";
424  for (const_iterator it = this->begin(); it != this->end(); ++it) {
425  if (needSeparator) { os << " "; }
426  (*it).dump(os);
427  needSeparator = true;
428  }
429  os << "}";
430  return os;
431 }
432 
433 
434 void
436 {
437  dump(std::cout);
438  std::cout.flush();
439 }
440 
441 
442 //***************************************************************************
443 // VMAIntervalMap
444 //***************************************************************************
445 
446 /*
447 Cf. LoadModScope::dumpmaps
448 
449 template<typename T>
450 void
451 VMAIntervalMap_ddump(VMAIntervalMap<T>* x)
452 {
453  x->ddump();
454 }
455 */
VMAInterval(VMA beg, VMA end)
Definition: VMAInterval.hpp:94
bfd_vma VMA
Definition: ISATypes.hpp:79
My_t::iterator iterator
void merge(const VMAIntervalSet &x)
My_t::const_iterator const_iterator
uint64_t toUInt64(const char *str, unsigned *endidx)
Definition: StrUtil.cpp:189
string toStr(const int x, int base)
Definition: StrUtil.cpp:243
std::ostream & dump(std::ostream &os) const
void ddump() const
VMA beg() const
#define DBG
Definition: VMAInterval.cpp:84
void erase(const VMA beg, const VMA end)
void fromString(const char *formattedstr)
std::ostream & dump(std::ostream &os) const
bool empty() const
VMA end() const
std::pair< iterator, bool > insert(const VMA beg, const VMA end)
std::string toString() const
std::pair< VMAIntervalSet::iterator, bool > iteratorPair
void ddump() const
const char * DIAG_UnexpectedInput
std::string toString() const
Definition: VMAInterval.cpp:93
void fromString(const char *formattedstr)