Waymarking.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. //===- Waymarking.h - Array waymarking algorithm ----------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // Utility to backtrace an array's head, from a pointer into it. For the
  10. // backtrace to work, we use "Waymarks", which are special tags embedded into
  11. // the array's elements.
  12. //
  13. // A Tag of n-bits (in size) is composed as follows:
  14. //
  15. // bits: | n-1 | n-2 ... 0 |
  16. // .---------.------------------------------------.
  17. // |Stop Mask|(2^(n-1))-ary numeric system - digit|
  18. // '---------'------------------------------------'
  19. //
  20. // Backtracing is done as follows:
  21. // Walk back (starting from a given pointer to an element into the array), until
  22. // a tag with a "Stop Mask" is reached. Then start calculating the "Offset" from
  23. // the array's head, by picking up digits along the way, until another stop is
  24. // reached. The "Offset" is then subtracted from the current pointer, and the
  25. // result is the array's head.
  26. // A special case - if we first encounter a Tag with a Stop and a zero digit,
  27. // then this is already the head.
  28. //
  29. // For example:
  30. // In case of 2 bits:
  31. //
  32. // Tags:
  33. // x0 - binary digit 0
  34. // x1 - binary digit 1
  35. // 1x - stop and calculate (s)
  36. //
  37. // Array:
  38. // .---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.
  39. // head -> |s0 |s1 | 0 |s1 | 0 | 0 |s1 | 1 | 1 |s1 | 0 | 1 | 0 |s1 | 0 | 1 |
  40. // '---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'
  41. // |-1 |-2 |-4 |-7 |-10 |-14
  42. // <_ | | | | | |
  43. // <_____ | | | | |
  44. // <_____________ | | | |
  45. // <_________________________ | | |
  46. // <_____________________________________ | |
  47. // <_____________________________________________________ |
  48. //
  49. //
  50. // In case of 3 bits:
  51. //
  52. // Tags:
  53. // x00 - quaternary digit 0
  54. // x01 - quaternary digit 1
  55. // x10 - quaternary digit 2
  56. // x11 - quaternary digit 3
  57. // 1xy - stop and calculate (s)
  58. //
  59. // Array:
  60. // .---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.
  61. // head -> |s0 |s1 |s2 |s3 | 0 |s1 | 2 |s1 | 0 |s2 | 2 |s2 | 0 |s3 | 2 |s3 |
  62. // '---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'
  63. // |-1 |-2 |-3 |-4 |-6 |-8 |-10 |-12 |-14 |-16
  64. // <_ | | | | | | | | | |
  65. // <_____ | | | | | | | | |
  66. // <_________ | | | | | | | |
  67. // <_____________ | | | | | | |
  68. // <_____________________ | | | | | |
  69. // <_____________________________ | | | | |
  70. // <_____________________________________ | | | |
  71. // <_____________________________________________ | | |
  72. // <_____________________________________________________ | |
  73. // <_____________________________________________________________ |
  74. //
  75. //
  76. // The API introduce 2 functions:
  77. // 1. fillWaymarks
  78. // 2. followWaymarks
  79. //
  80. // Example:
  81. // int N = 10;
  82. // int M = 5;
  83. // int **A = new int *[N + M]; // Define the array.
  84. // for (int I = 0; I < N + M; ++I)
  85. // A[I] = new int(I);
  86. //
  87. // fillWaymarks(A, A + N); // Set the waymarks for the first N elements
  88. // // of the array.
  89. // // Note that it must be done AFTER we fill
  90. // // the array's elements.
  91. //
  92. // ... // Elements which are not in the range
  93. // // [A, A+N) will not be marked, and we won't
  94. // // be able to call followWaymarks on them.
  95. //
  96. // ... // Elements which will be changed after the
  97. // // call to fillWaymarks, will have to be
  98. // // retagged.
  99. //
  100. // fillWaymarks(A + N, A + N + M, N); // Set the waymarks of the remaining M
  101. // // elements.
  102. // ...
  103. // int **It = A + N + 1;
  104. // int **B = followWaymarks(It); // Find the head of the array containing It.
  105. // assert(B == A);
  106. //
  107. //===----------------------------------------------------------------------===//
  108. #ifndef LLVM_ADT_WAYMARKING_H
  109. #define LLVM_ADT_WAYMARKING_H
  110. #include "llvm/ADT/STLExtras.h"
  111. #include "llvm/Support/PointerLikeTypeTraits.h"
  112. namespace llvm {
  113. namespace detail {
  114. template <unsigned NumBits> struct WaymarkingTraits {
  115. enum : unsigned {
  116. // The number of bits of a Waymarking Tag.
  117. NUM_BITS = NumBits,
  118. // A Tag is composed from a Mark and a Stop mask.
  119. MARK_SIZE = NUM_BITS - 1,
  120. STOP_MASK = (1 << MARK_SIZE),
  121. MARK_MASK = (STOP_MASK - 1),
  122. TAG_MASK = (MARK_MASK | STOP_MASK),
  123. // The number of pre-computed tags (for fast fill).
  124. NUM_STATIC_TAGS = 32
  125. };
  126. private:
  127. // Add a new tag, calculated from Count and Stop, to the Vals pack, while
  128. // continuing recursively to decrease Len down to 0.
  129. template <unsigned Len, bool Stop, unsigned Count, uint8_t... Vals>
  130. struct AddTag;
  131. // Delegate to the specialized AddTag according to the need of a Stop mask.
  132. template <unsigned Len, unsigned Count, uint8_t... Vals> struct GenTag {
  133. typedef
  134. typename AddTag<Len, (Count <= MARK_MASK), Count, Vals...>::Xdata Xdata;
  135. };
  136. // Start adding tags while calculating the next Count, which is actually the
  137. // number of already calculated tags (equivalent to the position in the
  138. // array).
  139. template <unsigned Len, uint8_t... Vals> struct GenOffset {
  140. typedef typename GenTag<Len, sizeof...(Vals), Vals...>::Xdata Xdata;
  141. };
  142. // Add the tag and remove it from Count.
  143. template <unsigned Len, unsigned Count, uint8_t... Vals>
  144. struct AddTag<Len, false, Count, Vals...> {
  145. typedef typename GenTag<Len - 1, (Count >> MARK_SIZE), Vals...,
  146. Count & MARK_MASK>::Xdata Xdata;
  147. };
  148. // We have reached the end of this Count, so start with a new Count.
  149. template <unsigned Len, unsigned Count, uint8_t... Vals>
  150. struct AddTag<Len, true, Count, Vals...> {
  151. typedef typename GenOffset<Len - 1, Vals...,
  152. (Count & MARK_MASK) | STOP_MASK>::Xdata Xdata;
  153. };
  154. template <unsigned Count, uint8_t... Vals> struct TagsData {
  155. // The remaining number for calculating the next tag, following the last one
  156. // in Values.
  157. static const unsigned Remain = Count;
  158. // The array of ordered pre-computed Tags.
  159. static const uint8_t Values[sizeof...(Vals)];
  160. };
  161. // Specialize the case when Len equals 0, as the recursion stop condition.
  162. template <unsigned Count, uint8_t... Vals>
  163. struct AddTag<0, false, Count, Vals...> {
  164. typedef TagsData<Count, Vals...> Xdata;
  165. };
  166. template <unsigned Count, uint8_t... Vals>
  167. struct AddTag<0, true, Count, Vals...> {
  168. typedef TagsData<Count, Vals...> Xdata;
  169. };
  170. public:
  171. typedef typename GenOffset<NUM_STATIC_TAGS>::Xdata Tags;
  172. };
  173. template <unsigned NumBits>
  174. template <unsigned Count, uint8_t... Vals>
  175. const uint8_t WaymarkingTraits<NumBits>::TagsData<
  176. Count, Vals...>::Values[sizeof...(Vals)] = {Vals...};
  177. } // end namespace detail
  178. /// This class is responsible for tagging (and retrieving the tag of) a given
  179. /// element of type T.
  180. template <class T, class WTraits = detail::WaymarkingTraits<
  181. PointerLikeTypeTraits<T>::NumLowBitsAvailable>>
  182. struct Waymarker {
  183. using Traits = WTraits;
  184. static void setWaymark(T &N, unsigned Tag) { N.setWaymark(Tag); }
  185. static unsigned getWaymark(const T &N) { return N.getWaymark(); }
  186. };
  187. template <class T, class WTraits> struct Waymarker<T *, WTraits> {
  188. using Traits = WTraits;
  189. static void setWaymark(T *&N, unsigned Tag) {
  190. reinterpret_cast<uintptr_t &>(N) |= static_cast<uintptr_t>(Tag);
  191. }
  192. static unsigned getWaymark(const T *N) {
  193. return static_cast<unsigned>(reinterpret_cast<uintptr_t>(N)) &
  194. Traits::TAG_MASK;
  195. }
  196. };
  197. /// Sets up the waymarking algorithm's tags for a given range [Begin, End).
  198. ///
  199. /// \param Begin The beginning of the range to mark with tags (inclusive).
  200. /// \param End The ending of the range to mark with tags (exclusive).
  201. /// \param Offset The position in the supposed tags array from which to start
  202. /// marking the given range.
  203. template <class TIter, class Marker = Waymarker<
  204. typename std::iterator_traits<TIter>::value_type>>
  205. void fillWaymarks(TIter Begin, TIter End, size_t Offset = 0) {
  206. if (Begin == End)
  207. return;
  208. size_t Count = Marker::Traits::Tags::Remain;
  209. if (Offset <= Marker::Traits::NUM_STATIC_TAGS) {
  210. // Start by filling the pre-calculated tags, starting from the given offset.
  211. while (Offset != Marker::Traits::NUM_STATIC_TAGS) {
  212. Marker::setWaymark(*Begin, Marker::Traits::Tags::Values[Offset]);
  213. ++Offset;
  214. ++Begin;
  215. if (Begin == End)
  216. return;
  217. }
  218. } else {
  219. // The given offset is larger than the number of pre-computed tags, so we
  220. // must do it the hard way.
  221. // Calculate the next remaining Count, as if we have filled the tags up to
  222. // the given offset.
  223. size_t Off = Marker::Traits::NUM_STATIC_TAGS;
  224. do {
  225. ++Off;
  226. unsigned Tag = Count & Marker::Traits::MARK_MASK;
  227. // If the count can fit into the tag, then the counting must stop.
  228. if (Count <= Marker::Traits::MARK_MASK) {
  229. Tag |= Marker::Traits::STOP_MASK;
  230. Count = Off;
  231. } else
  232. Count >>= Marker::Traits::MARK_SIZE;
  233. } while (Off != Offset);
  234. }
  235. // By now, we have the matching remaining Count for the current offset.
  236. do {
  237. ++Offset;
  238. unsigned Tag = Count & Marker::Traits::MARK_MASK;
  239. // If the count can fit into the tag, then the counting must stop.
  240. if (Count <= Marker::Traits::MARK_MASK) {
  241. Tag |= Marker::Traits::STOP_MASK;
  242. Count = Offset;
  243. } else
  244. Count >>= Marker::Traits::MARK_SIZE;
  245. Marker::setWaymark(*Begin, Tag);
  246. ++Begin;
  247. } while (Begin != End);
  248. }
  249. /// Sets up the waymarking algorithm's tags for a given range.
  250. ///
  251. /// \param Range The range to mark with tags.
  252. /// \param Offset The position in the supposed tags array from which to start
  253. /// marking the given range.
  254. template <typename R, class Marker = Waymarker<typename std::remove_reference<
  255. decltype(*std::begin(std::declval<R &>()))>::type>>
  256. void fillWaymarks(R &&Range, size_t Offset = 0) {
  257. return fillWaymarks<decltype(std::begin(std::declval<R &>())), Marker>(
  258. adl_begin(Range), adl_end(Range), Offset);
  259. }
  260. /// Retrieves the element marked with tag of only STOP_MASK, by following the
  261. /// waymarks. This is the first element in a range passed to a previous call to
  262. /// \c fillWaymarks with \c Offset 0.
  263. ///
  264. /// For the trivial usage of calling \c fillWaymarks(Array), and \I is an
  265. /// iterator inside \c Array, this function retrieves the head of \c Array, by
  266. /// following the waymarks.
  267. ///
  268. /// \param I The iterator into an array which was marked by the waymarking tags
  269. /// (by a previous call to \c fillWaymarks).
  270. template <class TIter, class Marker = Waymarker<
  271. typename std::iterator_traits<TIter>::value_type>>
  272. TIter followWaymarks(TIter I) {
  273. unsigned Tag;
  274. do
  275. Tag = Marker::getWaymark(*I--);
  276. while (!(Tag & Marker::Traits::STOP_MASK));
  277. // Special case for the first Use.
  278. if (Tag != Marker::Traits::STOP_MASK) {
  279. ptrdiff_t Offset = Tag & Marker::Traits::MARK_MASK;
  280. while (!((Tag = Marker::getWaymark(*I)) & Marker::Traits::STOP_MASK)) {
  281. Offset = (Offset << Marker::Traits::MARK_SIZE) + Tag;
  282. --I;
  283. }
  284. I -= Offset;
  285. }
  286. return ++I;
  287. }
  288. } // end namespace llvm
  289. #endif // LLVM_ADT_WAYMARKING_H