1//===------ ExecutorAddress.h - Executing process address -------*- 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// Represents an address in the executing program.
10//
11// This file was derived from
12// llvm/include/llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h.
13//
14//===----------------------------------------------------------------------===//
15
16#ifndef ORC_RT_EXECUTOR_ADDRESS_H
17#define ORC_RT_EXECUTOR_ADDRESS_H
18
19#include "adt.h"
20#include "simple_packed_serialization.h"
21
22#include <cassert>
23#include <type_traits>
24
25namespace __orc_rt {
26
27using ExecutorAddrDiff = uint64_t;
28
29/// Represents an address in the executor process.
30class ExecutorAddr {
31public:
32  /// A wrap/unwrap function that leaves pointers unmodified.
33  template <typename T> using rawPtr = __orc_rt::identity<T *>;
34
35  /// Default wrap function to use on this host.
36  template <typename T> using defaultWrap = rawPtr<T>;
37
38  /// Default unwrap function to use on this host.
39  template <typename T> using defaultUnwrap = rawPtr<T>;
40
41  /// Merges a tag into the raw address value:
42  ///   P' = P | (TagValue << TagOffset).
43  class Tag {
44  public:
45    constexpr Tag(uintptr_t TagValue, uintptr_t TagOffset)
46        : TagMask(TagValue << TagOffset) {}
47
48    template <typename T> constexpr T *operator()(T *P) {
49      return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(P) | TagMask);
50    }
51
52  private:
53    uintptr_t TagMask;
54  };
55
56  /// Strips a tag of the given length from the given offset within the pointer:
57  /// P' = P & ~(((1 << TagLen) -1) << TagOffset)
58  class Untag {
59  public:
60    constexpr Untag(uintptr_t TagLen, uintptr_t TagOffset)
61        : UntagMask(~(((uintptr_t(1) << TagLen) - 1) << TagOffset)) {}
62
63    template <typename T> constexpr T *operator()(T *P) {
64      return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(P) & UntagMask);
65    }
66
67  private:
68    uintptr_t UntagMask;
69  };
70
71  ExecutorAddr() = default;
72  explicit ExecutorAddr(uint64_t Addr) : Addr(Addr) {}
73
74  /// Create an ExecutorAddr from the given pointer.
75  template <typename T, typename UnwrapFn = defaultUnwrap<T>>
76  static ExecutorAddr fromPtr(T *Ptr, UnwrapFn &&Unwrap = UnwrapFn()) {
77    return ExecutorAddr(
78        static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Unwrap(Ptr))));
79  }
80
81  /// Cast this ExecutorAddr to a pointer of the given type.
82  template <typename T, typename WrapFn = defaultWrap<std::remove_pointer_t<T>>>
83  std::enable_if_t<std::is_pointer<T>::value, T>
84  toPtr(WrapFn &&Wrap = WrapFn()) const {
85    uintptr_t IntPtr = static_cast<uintptr_t>(Addr);
86    assert(IntPtr == Addr && "ExecutorAddr value out of range for uintptr_t");
87    return Wrap(reinterpret_cast<T>(IntPtr));
88  }
89
90  /// Cast this ExecutorAddr to a pointer of the given function type.
91  template <typename T, typename WrapFn = defaultWrap<T>>
92  std::enable_if_t<std::is_function<T>::value, T *>
93  toPtr(WrapFn &&Wrap = WrapFn()) const {
94    uintptr_t IntPtr = static_cast<uintptr_t>(Addr);
95    assert(IntPtr == Addr && "ExecutorAddr value out of range for uintptr_t");
96    return Wrap(reinterpret_cast<T *>(IntPtr));
97  }
98
99  uint64_t getValue() const { return Addr; }
100  void setValue(uint64_t Addr) { this->Addr = Addr; }
101  bool isNull() const { return Addr == 0; }
102
103  explicit operator bool() const { return Addr != 0; }
104
105  friend bool operator==(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
106    return LHS.Addr == RHS.Addr;
107  }
108
109  friend bool operator!=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
110    return LHS.Addr != RHS.Addr;
111  }
112
113  friend bool operator<(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
114    return LHS.Addr < RHS.Addr;
115  }
116
117  friend bool operator<=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
118    return LHS.Addr <= RHS.Addr;
119  }
120
121  friend bool operator>(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
122    return LHS.Addr > RHS.Addr;
123  }
124
125  friend bool operator>=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
126    return LHS.Addr >= RHS.Addr;
127  }
128
129  ExecutorAddr &operator++() {
130    ++Addr;
131    return *this;
132  }
133  ExecutorAddr &operator--() {
134    --Addr;
135    return *this;
136  }
137  ExecutorAddr operator++(int) { return ExecutorAddr(Addr++); }
138  ExecutorAddr operator--(int) { return ExecutorAddr(Addr++); }
139
140  ExecutorAddr &operator+=(const ExecutorAddrDiff Delta) {
141    Addr += Delta;
142    return *this;
143  }
144
145  ExecutorAddr &operator-=(const ExecutorAddrDiff Delta) {
146    Addr -= Delta;
147    return *this;
148  }
149
150private:
151  uint64_t Addr = 0;
152};
153
154/// Subtracting two addresses yields an offset.
155inline ExecutorAddrDiff operator-(const ExecutorAddr &LHS,
156                                  const ExecutorAddr &RHS) {
157  return ExecutorAddrDiff(LHS.getValue() - RHS.getValue());
158}
159
160/// Adding an offset and an address yields an address.
161inline ExecutorAddr operator+(const ExecutorAddr &LHS,
162                              const ExecutorAddrDiff &RHS) {
163  return ExecutorAddr(LHS.getValue() + RHS);
164}
165
166/// Adding an address and an offset yields an address.
167inline ExecutorAddr operator+(const ExecutorAddrDiff &LHS,
168                              const ExecutorAddr &RHS) {
169  return ExecutorAddr(LHS + RHS.getValue());
170}
171
172/// Represents an address range in the exceutor process.
173struct ExecutorAddrRange {
174  ExecutorAddrRange() = default;
175  ExecutorAddrRange(ExecutorAddr Start, ExecutorAddr End)
176      : Start(Start), End(End) {}
177  ExecutorAddrRange(ExecutorAddr Start, ExecutorAddrDiff Size)
178      : Start(Start), End(Start + Size) {}
179
180  bool empty() const { return Start == End; }
181  ExecutorAddrDiff size() const { return End - Start; }
182
183  friend bool operator==(const ExecutorAddrRange &LHS,
184                         const ExecutorAddrRange &RHS) {
185    return LHS.Start == RHS.Start && LHS.End == RHS.End;
186  }
187  friend bool operator!=(const ExecutorAddrRange &LHS,
188                         const ExecutorAddrRange &RHS) {
189    return !(LHS == RHS);
190  }
191  bool contains(ExecutorAddr Addr) const { return Start <= Addr && Addr < End; }
192  bool overlaps(const ExecutorAddrRange &Other) {
193    return !(Other.End <= Start || End <= Other.Start);
194  }
195
196  template <typename T> span<T> toSpan() const {
197    assert(size() % sizeof(T) == 0 &&
198           "AddressRange is not a multiple of sizeof(T)");
199    return span<T>(Start.toPtr<T *>(), size() / sizeof(T));
200  }
201
202  ExecutorAddr Start;
203  ExecutorAddr End;
204};
205
206/// SPS serializatior for ExecutorAddr.
207template <> class SPSSerializationTraits<SPSExecutorAddr, ExecutorAddr> {
208public:
209  static size_t size(const ExecutorAddr &EA) {
210    return SPSArgList<uint64_t>::size(EA.getValue());
211  }
212
213  static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddr &EA) {
214    return SPSArgList<uint64_t>::serialize(BOB, EA.getValue());
215  }
216
217  static bool deserialize(SPSInputBuffer &BIB, ExecutorAddr &EA) {
218    uint64_t Tmp;
219    if (!SPSArgList<uint64_t>::deserialize(BIB, Tmp))
220      return false;
221    EA = ExecutorAddr(Tmp);
222    return true;
223  }
224};
225
226using SPSExecutorAddrRange = SPSTuple<SPSExecutorAddr, SPSExecutorAddr>;
227
228/// Serialization traits for address ranges.
229template <>
230class SPSSerializationTraits<SPSExecutorAddrRange, ExecutorAddrRange> {
231public:
232  static size_t size(const ExecutorAddrRange &Value) {
233    return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::size(Value.Start,
234                                                              Value.End);
235  }
236
237  static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddrRange &Value) {
238    return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::serialize(
239        BOB, Value.Start, Value.End);
240  }
241
242  static bool deserialize(SPSInputBuffer &BIB, ExecutorAddrRange &Value) {
243    return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::deserialize(
244        BIB, Value.Start, Value.End);
245  }
246};
247
248using SPSExecutorAddrRangeSequence = SPSSequence<SPSExecutorAddrRange>;
249
250} // End namespace __orc_rt
251
252namespace std {
253
254// Make ExecutorAddr hashable.
255template <> struct hash<__orc_rt::ExecutorAddr> {
256  size_t operator()(const __orc_rt::ExecutorAddr &A) const {
257    return hash<uint64_t>()(A.getValue());
258  }
259};
260
261} // namespace std
262
263#endif // ORC_RT_EXECUTOR_ADDRESS_H
264