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(Arg: EA.getValue());
211 }
212
213 static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddr &EA) {
214 return SPSArgList<uint64_t>::serialize(OB&: BOB, Arg: EA.getValue());
215 }
216
217 static bool deserialize(SPSInputBuffer &BIB, ExecutorAddr &EA) {
218 uint64_t Tmp;
219 if (!SPSArgList<uint64_t>::deserialize(IB&: BIB, Arg&: 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(Arg: Value.Start,
234 Args: Value.End);
235 }
236
237 static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddrRange &Value) {
238 return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::serialize(
239 OB&: BOB, Arg: Value.Start, Args: Value.End);
240 }
241
242 static bool deserialize(SPSInputBuffer &BIB, ExecutorAddrRange &Value) {
243 return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::deserialize(
244 IB&: BIB, Arg&: Value.Start, Args&: 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