mc2lib
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
cats.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2016, Marco Elver
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the
15  * distribution.
16  *
17  * * Neither the name of the software nor the names of its contributors
18  * may be used to endorse or promote products derived from this
19  * software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 
34 #ifndef MC2LIB_CODEGEN_CATS_HPP_
35 #define MC2LIB_CODEGEN_CATS_HPP_
36 
37 #include <cassert>
38 #include <cstddef>
39 #include <limits>
40 #include <sstream>
41 #include <stdexcept>
42 #include <unordered_map>
43 
44 #include "../memconsistency/cats.hpp"
45 #include "compiler.hpp"
46 
47 namespace mc2lib {
48 
49 namespace codegen {
50 
51 // Workaround for Wtype-limits warning.
52 template <class T1, class T2>
53 constexpr bool lt__(T1 a, T2 b) {
54  return a < b;
55 }
56 
78 class EvtStateCats {
79  public:
80  // 1 Op can at most emit 2 write Events
81  static constexpr std::size_t kMaxOpSize = sizeof(types::WriteID) * 2;
82  static constexpr std::size_t kMaxOpEvents =
83  kMaxOpSize / sizeof(types::WriteID);
84 
85  static constexpr types::Poi kMinOther = static_cast<types::Poi>(1)
86  << (sizeof(types::Poi) * 8 - 1);
87  static constexpr types::Poi kMaxOther =
88  std::numeric_limits<types::Poi>::max() - (kMaxOpEvents - 1);
89 
90  static constexpr types::WriteID kInitWrite =
91  std::numeric_limits<types::WriteID>::min();
92  static constexpr types::WriteID kMinWrite = kInitWrite + 1;
93 
94  static constexpr types::WriteID kMaxWrite =
95  (lt__(std::numeric_limits<types::WriteID>::max(), kMinOther)
96  ? std::numeric_limits<types::WriteID>::max()
97  : kMinOther - 1) -
98  (kMaxOpEvents - 1);
99 
100  static_assert(kMinOther > kMaxWrite, "Invalid read/write ID limits!");
101 
102  explicit EvtStateCats(mc::cats::ExecWitness *ew, mc::cats::Architecture *arch)
103  : ew_(ew), arch_(arch), addr_mask_(~0) {}
104 
105  void Reset() {
106  last_write_id_ = kMinWrite - 1;
107  last_other_id = kMinOther - 1;
108 
109  writes_.clear();
110  ew_->Clear();
111  arch_->Clear();
112  }
113 
114  bool Exhausted() const {
115  return last_write_id_ >= kMaxWrite || last_other_id >= kMaxOther;
116  }
117 
118  template <std::size_t max_size_bytes, class Func>
119  EventPtrs<max_size_bytes> MakeEvent(types::Pid pid, mc::Event::Type type,
120  std::size_t size, Func mkevt) {
121  static_assert(max_size_bytes <= kMaxOpSize, "Invalid size!");
122  static_assert(sizeof(types::WriteID) <= max_size_bytes, "Invalid size!");
123  static_assert(max_size_bytes % sizeof(types::WriteID) == 0,
124  "Invalid size!");
125  assert(size <= max_size_bytes);
126  assert(sizeof(types::WriteID) <= size);
127  assert(size % sizeof(types::WriteID) == 0);
128 
129  // Initialize to avoid uninitialized warning with some older compilers.
130  EventPtrs<max_size_bytes> result{{nullptr}};
131 
132  for (std::size_t i = 0; i < size / sizeof(types::WriteID); ++i) {
133  result[i] = mkevt(i * sizeof(types::WriteID));
134  }
135 
136  return result;
137  }
138 
139  mc::Event MakeOther(types::Pid pid, mc::Event::Type type, types::Addr addr) {
140  assert(!Exhausted());
141  addr &= addr_mask_;
142  return mc::Event(type, addr, mc::Iiid(pid, ++last_other_id));
143  }
144 
145  template <std::size_t max_size_bytes = sizeof(types::WriteID)>
146  EventPtrs<max_size_bytes> MakeRead(types::Pid pid, mc::Event::Type type,
147  types::Addr addr,
148  std::size_t size = max_size_bytes) {
149  assert(!Exhausted());
150  addr &= addr_mask_;
151  ++last_other_id;
152  return MakeEvent<max_size_bytes>(pid, type, size, [&](types::Addr offset) {
153  const mc::Event event =
154  mc::Event(type, addr + offset, mc::Iiid(pid, last_other_id));
155 
156  return &ew_->events.Insert(event, true);
157  });
158  }
159 
160  template <std::size_t max_size_bytes = sizeof(types::WriteID)>
161  EventPtrs<max_size_bytes> MakeWrite(types::Pid pid, mc::Event::Type type,
162  types::Addr addr, types::WriteID *data,
163  std::size_t size = max_size_bytes) {
164  assert(!Exhausted());
165  addr &= addr_mask_;
166  ++last_write_id_;
167  return MakeEvent<max_size_bytes>(pid, type, size, [&](types::Addr offset) {
168  const types::WriteID write_id = last_write_id_;
169 
170  const mc::Event event =
171  mc::Event(type, addr + offset, mc::Iiid(pid, write_id));
172 
173  *(data + offset) = write_id;
174  return (writes_[write_id] = &ew_->events.Insert(event, true));
175  });
176  }
177 
178  template <std::size_t max_size_bytes = sizeof(types::WriteID)>
180  types::Addr addr,
181  const types::WriteID *from_id,
182  std::size_t size = max_size_bytes) {
183  static_assert(max_size_bytes <= kMaxOpSize, "Invalid size!");
184  static_assert(sizeof(types::WriteID) <= max_size_bytes, "Invalid size!");
185  static_assert(max_size_bytes % sizeof(types::WriteID) == 0,
186  "Invalid size!");
187  assert(size <= max_size_bytes);
188  assert(sizeof(types::WriteID) <= size);
189  assert(size % sizeof(types::WriteID) == 0);
190  addr &= addr_mask_;
191 
193  result.fill(nullptr); // init
194 
195  for (std::size_t i = 0; i < size / sizeof(types::WriteID); ++i) {
196  WriteID_EventPtr::const_iterator write;
197 
198  const bool valid = from_id[i] != kInitWrite &&
199  (write = writes_.find(from_id[i])) != writes_.end() &&
200  write->second->addr == addr &&
201  write->second->iiid != after[i]->iiid;
202  if (valid) {
203  result[i] = write->second;
204  } else {
205  if (from_id[i] != kInitWrite) {
206  // While the checker works even if memory is not 0'ed out
207  // completely, as the chances of reading a write-id from a
208  // previous test that has already been used in this test is
209  // low and doesn't necessarily cause a false positive, it is
210  // recommended that memory is 0'ed out for every new test.
211  //
212  // This does also provides limited checking for single-copy
213  // atomicity violations where sizeof(WriteID) > 1.
214 
215  std::ostringstream oss;
216  oss << __func__ << ": Invalid write!"
217  << " A=" << std::hex << addr << " S=" << size;
218 
219  if (write != writes_.end()) {
220  oss << ((write->second->addr != addr) ? " (addr mismatch)" : "")
221  << ((write->second->iiid == after[i]->iiid) ? " (same iiid)"
222  : "");
223  }
224 
225  throw std::logic_error(oss.str());
226  }
227 
228  auto initial = mc::Event(mc::Event::kWrite, addr, mc::Iiid(-1, addr));
229  result[i] = &ew_->events.Insert(initial);
230  }
231 
232  addr += sizeof(types::WriteID);
233  }
234 
235  return result;
236  }
237 
238  mc::cats::ExecWitness *ew() { return ew_; }
239 
240  const mc::cats::ExecWitness *ew() const { return ew_; }
241 
242  mc::cats::Architecture *arch() { return arch_; }
243 
244  const mc::cats::Architecture *arch() const { return arch_; }
245 
254  void set_addr_mask(types::Addr val) { addr_mask_ = val; }
255 
256  types::Addr addr_mask() const { return addr_mask_; }
257 
258  private:
259  typedef std::unordered_map<types::WriteID, const mc::Event *>
261 
262  mc::cats::ExecWitness *ew_;
263  mc::cats::Architecture *arch_;
264 
266 
269 
271 };
272 
273 } // namespace codegen
274 } // namespace mc2lib
275 
276 #endif /* MC2LIB_CODEGEN_CATS_HPP_ */
277 
278 /* vim: set ts=2 sts=2 sw=2 et : */
static constexpr std::size_t kMaxOpSize
Definition: cats.hpp:81
std::unordered_map< types::WriteID, const mc::Event * > WriteID_EventPtr
Definition: cats.hpp:260
Types< true >::Poi Poi
Program order index type.
Definition: types.hpp:76
EvtStateCats(mc::cats::ExecWitness *ew, mc::cats::Architecture *arch)
Definition: cats.hpp:102
void set_addr_mask(types::Addr val)
Definition: cats.hpp:254
Interface to memconsistency::cats data structures.
Definition: cats.hpp:78
Definition: eventsets.hpp:53
Definition: cats.hpp:47
const mc::cats::Architecture * arch() const
Definition: cats.hpp:244
mc::cats::Architecture * arch_
Definition: cats.hpp:263
EventPtrs< max_size_bytes > MakeWrite(types::Pid pid, mc::Event::Type type, types::Addr addr, types::WriteID *data, std::size_t size=max_size_bytes)
Definition: cats.hpp:161
void Reset()
Definition: cats.hpp:105
types::Addr addr_mask_
Definition: cats.hpp:270
EventPtrs< max_size_bytes > MakeRead(types::Pid pid, mc::Event::Type type, types::Addr addr, std::size_t size=max_size_bytes)
Definition: cats.hpp:146
types::Addr addr_mask() const
Definition: cats.hpp:256
mc::cats::ExecWitness * ew()
Definition: cats.hpp:238
static constexpr std::size_t kMaxOpEvents
Definition: cats.hpp:82
static constexpr types::WriteID kInitWrite
Definition: cats.hpp:90
types::WriteID last_write_id_
Definition: cats.hpp:267
Definition: eventsets.hpp:103
mc::cats::ExecWitness * ew_
Definition: cats.hpp:262
static constexpr types::Poi kMaxOther
Definition: cats.hpp:87
WriteID_EventPtr writes_
Definition: cats.hpp:265
constexpr bool lt__(T1 a, T2 b)
Definition: cats.hpp:53
static constexpr types::WriteID kMinWrite
Definition: cats.hpp:92
std::array< const mc::Event *, max_size_bytes/sizeof(types::WriteID)> EventPtrs
Definition: compiler.hpp:64
mc::cats::Architecture * arch()
Definition: cats.hpp:242
Types< true >::WriteID WriteID
Write ID type.
Definition: types.hpp:86
static constexpr types::Poi kMinOther
Definition: cats.hpp:85
Types< true >::Addr Addr
Address type.
Definition: types.hpp:66
EventPtrs< max_size_bytes > GetWrite(const EventPtrs< max_size_bytes > &after, types::Addr addr, const types::WriteID *from_id, std::size_t size=max_size_bytes)
Definition: cats.hpp:179
const mc::cats::ExecWitness * ew() const
Definition: cats.hpp:240
static constexpr types::WriteID kMaxWrite
Definition: cats.hpp:94
types::Poi last_other_id
Definition: cats.hpp:268
Types< true >::Pid Pid
Processor/thread ID type.
Definition: types.hpp:71
mc::Event MakeOther(types::Pid pid, mc::Event::Type type, types::Addr addr)
Definition: cats.hpp:139
EventPtrs< max_size_bytes > MakeEvent(types::Pid pid, mc::Event::Type type, std::size_t size, Func mkevt)
Definition: cats.hpp:119
bool Exhausted() const
Definition: cats.hpp:114