1fe6060f1SDimitry Andric //===------ ExecutorAddress.h - Executing process address -------*- C++ -*-===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric //
9fe6060f1SDimitry Andric // Represents an address in the executing program.
10fe6060f1SDimitry Andric //
11fe6060f1SDimitry Andric // This file was derived from
12fe6060f1SDimitry Andric // llvm/include/llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h.
13fe6060f1SDimitry Andric //
14fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
15fe6060f1SDimitry Andric 
16fe6060f1SDimitry Andric #ifndef ORC_RT_EXECUTOR_ADDRESS_H
17fe6060f1SDimitry Andric #define ORC_RT_EXECUTOR_ADDRESS_H
18fe6060f1SDimitry Andric 
19fe6060f1SDimitry Andric #include "adt.h"
20fe6060f1SDimitry Andric #include "simple_packed_serialization.h"
21fe6060f1SDimitry Andric 
22fe6060f1SDimitry Andric #include <cassert>
23fe6060f1SDimitry Andric #include <type_traits>
24fe6060f1SDimitry Andric 
25fe6060f1SDimitry Andric namespace __orc_rt {
26fe6060f1SDimitry Andric 
27*bdd1243dSDimitry Andric using ExecutorAddrDiff = uint64_t;
28fe6060f1SDimitry Andric 
29fe6060f1SDimitry Andric /// Represents an address in the executor process.
30349cc55cSDimitry Andric class ExecutorAddr {
31fe6060f1SDimitry Andric public:
32*bdd1243dSDimitry Andric   /// A wrap/unwrap function that leaves pointers unmodified.
33*bdd1243dSDimitry Andric   template <typename T> using rawPtr = __orc_rt::identity<T *>;
34*bdd1243dSDimitry Andric 
35*bdd1243dSDimitry Andric   /// Default wrap function to use on this host.
36*bdd1243dSDimitry Andric   template <typename T> using defaultWrap = rawPtr<T>;
37*bdd1243dSDimitry Andric 
38*bdd1243dSDimitry Andric   /// Default unwrap function to use on this host.
39*bdd1243dSDimitry Andric   template <typename T> using defaultUnwrap = rawPtr<T>;
40*bdd1243dSDimitry Andric 
41*bdd1243dSDimitry Andric   /// Merges a tag into the raw address value:
42*bdd1243dSDimitry Andric   ///   P' = P | (TagValue << TagOffset).
43*bdd1243dSDimitry Andric   class Tag {
44*bdd1243dSDimitry Andric   public:
Tag(uintptr_t TagValue,uintptr_t TagOffset)45*bdd1243dSDimitry Andric     constexpr Tag(uintptr_t TagValue, uintptr_t TagOffset)
46*bdd1243dSDimitry Andric         : TagMask(TagValue << TagOffset) {}
47*bdd1243dSDimitry Andric 
operator()48*bdd1243dSDimitry Andric     template <typename T> constexpr T *operator()(T *P) {
49*bdd1243dSDimitry Andric       return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(P) | TagMask);
50*bdd1243dSDimitry Andric     }
51*bdd1243dSDimitry Andric 
52*bdd1243dSDimitry Andric   private:
53*bdd1243dSDimitry Andric     uintptr_t TagMask;
54*bdd1243dSDimitry Andric   };
55*bdd1243dSDimitry Andric 
56*bdd1243dSDimitry Andric   /// Strips a tag of the given length from the given offset within the pointer:
57*bdd1243dSDimitry Andric   /// P' = P & ~(((1 << TagLen) -1) << TagOffset)
58*bdd1243dSDimitry Andric   class Untag {
59*bdd1243dSDimitry Andric   public:
Untag(uintptr_t TagLen,uintptr_t TagOffset)60*bdd1243dSDimitry Andric     constexpr Untag(uintptr_t TagLen, uintptr_t TagOffset)
61*bdd1243dSDimitry Andric         : UntagMask(~(((uintptr_t(1) << TagLen) - 1) << TagOffset)) {}
62*bdd1243dSDimitry Andric 
operator()63*bdd1243dSDimitry Andric     template <typename T> constexpr T *operator()(T *P) {
64*bdd1243dSDimitry Andric       return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(P) & UntagMask);
65*bdd1243dSDimitry Andric     }
66*bdd1243dSDimitry Andric 
67*bdd1243dSDimitry Andric   private:
68*bdd1243dSDimitry Andric     uintptr_t UntagMask;
69*bdd1243dSDimitry Andric   };
70*bdd1243dSDimitry Andric 
71349cc55cSDimitry Andric   ExecutorAddr() = default;
ExecutorAddr(uint64_t Addr)72349cc55cSDimitry Andric   explicit ExecutorAddr(uint64_t Addr) : Addr(Addr) {}
73fe6060f1SDimitry Andric 
74349cc55cSDimitry Andric   /// Create an ExecutorAddr from the given pointer.
75*bdd1243dSDimitry Andric   template <typename T, typename UnwrapFn = defaultUnwrap<T>>
76*bdd1243dSDimitry Andric   static ExecutorAddr fromPtr(T *Ptr, UnwrapFn &&Unwrap = UnwrapFn()) {
77349cc55cSDimitry Andric     return ExecutorAddr(
78*bdd1243dSDimitry Andric         static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Unwrap(Ptr))));
79fe6060f1SDimitry Andric   }
80fe6060f1SDimitry Andric 
81349cc55cSDimitry Andric   /// Cast this ExecutorAddr to a pointer of the given type.
82*bdd1243dSDimitry Andric   template <typename T, typename WrapFn = defaultWrap<std::remove_pointer_t<T>>>
83*bdd1243dSDimitry Andric   std::enable_if_t<std::is_pointer<T>::value, T>
84*bdd1243dSDimitry Andric   toPtr(WrapFn &&Wrap = WrapFn()) const {
85fe6060f1SDimitry Andric     uintptr_t IntPtr = static_cast<uintptr_t>(Addr);
86*bdd1243dSDimitry Andric     assert(IntPtr == Addr && "ExecutorAddr value out of range for uintptr_t");
87*bdd1243dSDimitry Andric     return Wrap(reinterpret_cast<T>(IntPtr));
88*bdd1243dSDimitry Andric   }
89*bdd1243dSDimitry Andric 
90*bdd1243dSDimitry Andric   /// Cast this ExecutorAddr to a pointer of the given function type.
91*bdd1243dSDimitry Andric   template <typename T, typename WrapFn = defaultWrap<T>>
92*bdd1243dSDimitry Andric   std::enable_if_t<std::is_function<T>::value, T *>
93*bdd1243dSDimitry Andric   toPtr(WrapFn &&Wrap = WrapFn()) const {
94*bdd1243dSDimitry Andric     uintptr_t IntPtr = static_cast<uintptr_t>(Addr);
95*bdd1243dSDimitry Andric     assert(IntPtr == Addr && "ExecutorAddr value out of range for uintptr_t");
96*bdd1243dSDimitry Andric     return Wrap(reinterpret_cast<T *>(IntPtr));
97fe6060f1SDimitry Andric   }
98fe6060f1SDimitry Andric 
getValue()99fe6060f1SDimitry Andric   uint64_t getValue() const { return Addr; }
setValue(uint64_t Addr)100fe6060f1SDimitry Andric   void setValue(uint64_t Addr) { this->Addr = Addr; }
isNull()101fe6060f1SDimitry Andric   bool isNull() const { return Addr == 0; }
102fe6060f1SDimitry Andric 
103fe6060f1SDimitry Andric   explicit operator bool() const { return Addr != 0; }
104fe6060f1SDimitry Andric 
105349cc55cSDimitry Andric   friend bool operator==(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
106fe6060f1SDimitry Andric     return LHS.Addr == RHS.Addr;
107fe6060f1SDimitry Andric   }
108fe6060f1SDimitry Andric 
109349cc55cSDimitry Andric   friend bool operator!=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
110fe6060f1SDimitry Andric     return LHS.Addr != RHS.Addr;
111fe6060f1SDimitry Andric   }
112fe6060f1SDimitry Andric 
113349cc55cSDimitry Andric   friend bool operator<(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
114fe6060f1SDimitry Andric     return LHS.Addr < RHS.Addr;
115fe6060f1SDimitry Andric   }
116fe6060f1SDimitry Andric 
117349cc55cSDimitry Andric   friend bool operator<=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
118fe6060f1SDimitry Andric     return LHS.Addr <= RHS.Addr;
119fe6060f1SDimitry Andric   }
120fe6060f1SDimitry Andric 
121349cc55cSDimitry Andric   friend bool operator>(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
122fe6060f1SDimitry Andric     return LHS.Addr > RHS.Addr;
123fe6060f1SDimitry Andric   }
124fe6060f1SDimitry Andric 
125349cc55cSDimitry Andric   friend bool operator>=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
126fe6060f1SDimitry Andric     return LHS.Addr >= RHS.Addr;
127fe6060f1SDimitry Andric   }
128fe6060f1SDimitry Andric 
129349cc55cSDimitry Andric   ExecutorAddr &operator++() {
130fe6060f1SDimitry Andric     ++Addr;
131fe6060f1SDimitry Andric     return *this;
132fe6060f1SDimitry Andric   }
133349cc55cSDimitry Andric   ExecutorAddr &operator--() {
134fe6060f1SDimitry Andric     --Addr;
135fe6060f1SDimitry Andric     return *this;
136fe6060f1SDimitry Andric   }
137349cc55cSDimitry Andric   ExecutorAddr operator++(int) { return ExecutorAddr(Addr++); }
138349cc55cSDimitry Andric   ExecutorAddr operator--(int) { return ExecutorAddr(Addr++); }
139fe6060f1SDimitry Andric 
140349cc55cSDimitry Andric   ExecutorAddr &operator+=(const ExecutorAddrDiff Delta) {
141*bdd1243dSDimitry Andric     Addr += Delta;
142fe6060f1SDimitry Andric     return *this;
143fe6060f1SDimitry Andric   }
144fe6060f1SDimitry Andric 
145349cc55cSDimitry Andric   ExecutorAddr &operator-=(const ExecutorAddrDiff Delta) {
146*bdd1243dSDimitry Andric     Addr -= Delta;
147fe6060f1SDimitry Andric     return *this;
148fe6060f1SDimitry Andric   }
149fe6060f1SDimitry Andric 
150fe6060f1SDimitry Andric private:
151fe6060f1SDimitry Andric   uint64_t Addr = 0;
152fe6060f1SDimitry Andric };
153fe6060f1SDimitry Andric 
154fe6060f1SDimitry Andric /// Subtracting two addresses yields an offset.
155349cc55cSDimitry Andric inline ExecutorAddrDiff operator-(const ExecutorAddr &LHS,
156349cc55cSDimitry Andric                                   const ExecutorAddr &RHS) {
157fe6060f1SDimitry Andric   return ExecutorAddrDiff(LHS.getValue() - RHS.getValue());
158fe6060f1SDimitry Andric }
159fe6060f1SDimitry Andric 
160fe6060f1SDimitry Andric /// Adding an offset and an address yields an address.
161349cc55cSDimitry Andric inline ExecutorAddr operator+(const ExecutorAddr &LHS,
162fe6060f1SDimitry Andric                               const ExecutorAddrDiff &RHS) {
163*bdd1243dSDimitry Andric   return ExecutorAddr(LHS.getValue() + RHS);
164fe6060f1SDimitry Andric }
165fe6060f1SDimitry Andric 
166fe6060f1SDimitry Andric /// Adding an address and an offset yields an address.
167349cc55cSDimitry Andric inline ExecutorAddr operator+(const ExecutorAddrDiff &LHS,
168349cc55cSDimitry Andric                               const ExecutorAddr &RHS) {
169*bdd1243dSDimitry Andric   return ExecutorAddr(LHS + RHS.getValue());
170fe6060f1SDimitry Andric }
171fe6060f1SDimitry Andric 
172fe6060f1SDimitry Andric /// Represents an address range in the exceutor process.
173349cc55cSDimitry Andric struct ExecutorAddrRange {
174349cc55cSDimitry Andric   ExecutorAddrRange() = default;
ExecutorAddrRangeExecutorAddrRange175349cc55cSDimitry Andric   ExecutorAddrRange(ExecutorAddr Start, ExecutorAddr End)
176349cc55cSDimitry Andric       : Start(Start), End(End) {}
ExecutorAddrRangeExecutorAddrRange177349cc55cSDimitry Andric   ExecutorAddrRange(ExecutorAddr Start, ExecutorAddrDiff Size)
178349cc55cSDimitry Andric       : Start(Start), End(Start + Size) {}
179fe6060f1SDimitry Andric 
emptyExecutorAddrRange180349cc55cSDimitry Andric   bool empty() const { return Start == End; }
sizeExecutorAddrRange181349cc55cSDimitry Andric   ExecutorAddrDiff size() const { return End - Start; }
182349cc55cSDimitry Andric 
183349cc55cSDimitry Andric   friend bool operator==(const ExecutorAddrRange &LHS,
184349cc55cSDimitry Andric                          const ExecutorAddrRange &RHS) {
185349cc55cSDimitry Andric     return LHS.Start == RHS.Start && LHS.End == RHS.End;
186349cc55cSDimitry Andric   }
187349cc55cSDimitry Andric   friend bool operator!=(const ExecutorAddrRange &LHS,
188349cc55cSDimitry Andric                          const ExecutorAddrRange &RHS) {
189349cc55cSDimitry Andric     return !(LHS == RHS);
190349cc55cSDimitry Andric   }
containsExecutorAddrRange191349cc55cSDimitry Andric   bool contains(ExecutorAddr Addr) const { return Start <= Addr && Addr < End; }
overlapsExecutorAddrRange192349cc55cSDimitry Andric   bool overlaps(const ExecutorAddrRange &Other) {
193349cc55cSDimitry Andric     return !(Other.End <= Start || End <= Other.Start);
194349cc55cSDimitry Andric   }
195fe6060f1SDimitry Andric 
toSpanExecutorAddrRange196fe6060f1SDimitry Andric   template <typename T> span<T> toSpan() const {
197*bdd1243dSDimitry Andric     assert(size() % sizeof(T) == 0 &&
198fe6060f1SDimitry Andric            "AddressRange is not a multiple of sizeof(T)");
199*bdd1243dSDimitry Andric     return span<T>(Start.toPtr<T *>(), size() / sizeof(T));
200fe6060f1SDimitry Andric   }
201fe6060f1SDimitry Andric 
202349cc55cSDimitry Andric   ExecutorAddr Start;
203349cc55cSDimitry Andric   ExecutorAddr End;
204fe6060f1SDimitry Andric };
205fe6060f1SDimitry Andric 
206349cc55cSDimitry Andric /// SPS serializatior for ExecutorAddr.
207349cc55cSDimitry Andric template <> class SPSSerializationTraits<SPSExecutorAddr, ExecutorAddr> {
208fe6060f1SDimitry Andric public:
size(const ExecutorAddr & EA)209349cc55cSDimitry Andric   static size_t size(const ExecutorAddr &EA) {
210fe6060f1SDimitry Andric     return SPSArgList<uint64_t>::size(EA.getValue());
211fe6060f1SDimitry Andric   }
212fe6060f1SDimitry Andric 
serialize(SPSOutputBuffer & BOB,const ExecutorAddr & EA)213349cc55cSDimitry Andric   static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddr &EA) {
214fe6060f1SDimitry Andric     return SPSArgList<uint64_t>::serialize(BOB, EA.getValue());
215fe6060f1SDimitry Andric   }
216fe6060f1SDimitry Andric 
deserialize(SPSInputBuffer & BIB,ExecutorAddr & EA)217349cc55cSDimitry Andric   static bool deserialize(SPSInputBuffer &BIB, ExecutorAddr &EA) {
218fe6060f1SDimitry Andric     uint64_t Tmp;
219fe6060f1SDimitry Andric     if (!SPSArgList<uint64_t>::deserialize(BIB, Tmp))
220fe6060f1SDimitry Andric       return false;
221349cc55cSDimitry Andric     EA = ExecutorAddr(Tmp);
222fe6060f1SDimitry Andric     return true;
223fe6060f1SDimitry Andric   }
224fe6060f1SDimitry Andric };
225fe6060f1SDimitry Andric 
226349cc55cSDimitry Andric using SPSExecutorAddrRange = SPSTuple<SPSExecutorAddr, SPSExecutorAddr>;
227fe6060f1SDimitry Andric 
228fe6060f1SDimitry Andric /// Serialization traits for address ranges.
229fe6060f1SDimitry Andric template <>
230349cc55cSDimitry Andric class SPSSerializationTraits<SPSExecutorAddrRange, ExecutorAddrRange> {
231fe6060f1SDimitry Andric public:
size(const ExecutorAddrRange & Value)232349cc55cSDimitry Andric   static size_t size(const ExecutorAddrRange &Value) {
233349cc55cSDimitry Andric     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::size(Value.Start,
234349cc55cSDimitry Andric                                                               Value.End);
235fe6060f1SDimitry Andric   }
236fe6060f1SDimitry Andric 
serialize(SPSOutputBuffer & BOB,const ExecutorAddrRange & Value)237349cc55cSDimitry Andric   static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddrRange &Value) {
238349cc55cSDimitry Andric     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::serialize(
239349cc55cSDimitry Andric         BOB, Value.Start, Value.End);
240fe6060f1SDimitry Andric   }
241fe6060f1SDimitry Andric 
deserialize(SPSInputBuffer & BIB,ExecutorAddrRange & Value)242349cc55cSDimitry Andric   static bool deserialize(SPSInputBuffer &BIB, ExecutorAddrRange &Value) {
243349cc55cSDimitry Andric     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::deserialize(
244349cc55cSDimitry Andric         BIB, Value.Start, Value.End);
245fe6060f1SDimitry Andric   }
246fe6060f1SDimitry Andric };
247fe6060f1SDimitry Andric 
248349cc55cSDimitry Andric using SPSExecutorAddrRangeSequence = SPSSequence<SPSExecutorAddrRange>;
249fe6060f1SDimitry Andric 
250fe6060f1SDimitry Andric } // End namespace __orc_rt
251fe6060f1SDimitry Andric 
25281ad6265SDimitry Andric namespace std {
25381ad6265SDimitry Andric 
25481ad6265SDimitry Andric // Make ExecutorAddr hashable.
25581ad6265SDimitry Andric template <> struct hash<__orc_rt::ExecutorAddr> {
25681ad6265SDimitry Andric   size_t operator()(const __orc_rt::ExecutorAddr &A) const {
25781ad6265SDimitry Andric     return hash<uint64_t>()(A.getValue());
25881ad6265SDimitry Andric   }
25981ad6265SDimitry Andric };
26081ad6265SDimitry Andric 
26181ad6265SDimitry Andric } // namespace std
26281ad6265SDimitry Andric 
263fe6060f1SDimitry Andric #endif // ORC_RT_EXECUTOR_ADDRESS_H
264