Line data Source code
1 : #ifdef __PLUMED_HAS_ASMJIT
2 : // This file is part of AsmJit project <https://asmjit.com>
3 : //
4 : // See asmjit.h or LICENSE.md for license and copyright information
5 : // SPDX-License-Identifier: Zlib
6 :
7 : #ifndef ASMJIT_ARM_ARMOPERAND_H_INCLUDED
8 : #define ASMJIT_ARM_ARMOPERAND_H_INCLUDED
9 :
10 : #include "archtraits.h"
11 : #include "operand.h"
12 : #include "type.h"
13 : #include "armglobals.h"
14 :
15 : ASMJIT_BEGIN_SUB_NAMESPACE(arm)
16 :
17 : //! \addtogroup asmjit_arm
18 : //! \{
19 :
20 : class Reg;
21 : class Mem;
22 :
23 : class Gp;
24 : class GpW;
25 : class GpX;
26 :
27 : class Vec;
28 : class VecB;
29 : class VecH;
30 : class VecS;
31 : class VecD;
32 : class VecV;
33 :
34 : //! Register traits (ARM/AArch64).
35 : //!
36 : //! Register traits contains information about a particular register type. It's used by asmjit to setup register
37 : //! information on-the-fly and to populate tables that contain register information (this way it's possible to
38 : //! change register types and groups without having to reorder these tables).
39 : template<RegType kRegType>
40 : struct RegTraits : public BaseRegTraits {};
41 :
42 : //! \cond
43 : // <--------------------+-----+-------------------------+------------------------+---+---+------------------+
44 : // | Reg | Reg-Type | Reg-Group |Sz |Cnt| TypeId |
45 : // <--------------------+-----+-------------------------+------------------------+---+---+------------------+
46 : ASMJIT_DEFINE_REG_TRAITS(GpW , RegType::kARM_GpW , RegGroup::kGp , 4 , 32, TypeId::kInt32 );
47 : ASMJIT_DEFINE_REG_TRAITS(GpX , RegType::kARM_GpX , RegGroup::kGp , 8 , 32, TypeId::kInt64 );
48 : ASMJIT_DEFINE_REG_TRAITS(VecB , RegType::kARM_VecB , RegGroup::kVec , 1 , 32, TypeId::kVoid );
49 : ASMJIT_DEFINE_REG_TRAITS(VecH , RegType::kARM_VecH , RegGroup::kVec , 2 , 32, TypeId::kVoid );
50 : ASMJIT_DEFINE_REG_TRAITS(VecS , RegType::kARM_VecS , RegGroup::kVec , 4 , 32, TypeId::kInt32x1 );
51 : ASMJIT_DEFINE_REG_TRAITS(VecD , RegType::kARM_VecD , RegGroup::kVec , 8 , 32, TypeId::kInt32x2 );
52 : ASMJIT_DEFINE_REG_TRAITS(VecV , RegType::kARM_VecV , RegGroup::kVec , 16, 32, TypeId::kInt32x4 );
53 : //! \endcond
54 :
55 : //! Register (ARM).
56 : class Reg : public BaseReg {
57 : public:
58 : ASMJIT_DEFINE_ABSTRACT_REG(Reg, BaseReg)
59 :
60 : //! Gets whether the register is a `R|W` register (32-bit).
61 : inline constexpr bool isGpW() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpW>::kSignature; }
62 : //! Gets whether the register is an `X` register (64-bit).
63 : inline constexpr bool isGpX() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpX>::kSignature; }
64 : //! Gets whether the register is a VEC-B register (8-bit).
65 : inline constexpr bool isVecB() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecB>::kSignature; }
66 : //! Gets whether the register is a VEC-H register (16-bit).
67 : inline constexpr bool isVecH() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecH>::kSignature; }
68 : //! Gets whether the register is a VEC-S register (32-bit).
69 : inline constexpr bool isVecS() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecS>::kSignature; }
70 : //! Gets whether the register is a VEC-D register (64-bit).
71 : inline constexpr bool isVecD() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecD>::kSignature; }
72 : //! Gets whether the register is a VEC-Q register (128-bit).
73 : inline constexpr bool isVecQ() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; }
74 :
75 : //! Gets whether the register is either VEC-D (64-bit) or VEC-Q (128-bit).
76 : inline constexpr bool isVecDOrQ() const noexcept { return uint32_t(type()) - uint32_t(RegType::kARM_VecD) <= 1u; }
77 :
78 : //! Gets whether the register is a VEC-V register (128-bit).
79 : inline constexpr bool isVecV() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; }
80 :
81 : template<RegType kRegType>
82 : inline void setRegT(uint32_t id) noexcept {
83 : setSignature(RegTraits<kRegType>::kSignature);
84 : setId(id);
85 : }
86 :
87 : inline void setTypeAndId(RegType type, uint32_t id) noexcept {
88 : setSignature(signatureOf(type));
89 : setId(id);
90 : }
91 :
92 : static inline RegGroup groupOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToGroup(type); }
93 : static inline TypeId typeIdOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToTypeId(type); }
94 : static inline OperandSignature signatureOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToSignature(type); }
95 :
96 : template<RegType kRegType>
97 : static inline RegGroup groupOfT() noexcept { return RegTraits<kRegType>::kGroup; }
98 :
99 : template<RegType kRegType>
100 : static inline TypeId typeIdOfT() noexcept { return RegTraits<kRegType>::kTypeId; }
101 :
102 : template<RegType kRegType>
103 : static inline OperandSignature signatureOfT() noexcept { return RegTraits<kRegType>::kSignature; }
104 :
105 : static inline bool isGpW(const Operand_& op) noexcept { return op.as<Reg>().isGpW(); }
106 : static inline bool isGpX(const Operand_& op) noexcept { return op.as<Reg>().isGpX(); }
107 : static inline bool isVecB(const Operand_& op) noexcept { return op.as<Reg>().isVecB(); }
108 : static inline bool isVecH(const Operand_& op) noexcept { return op.as<Reg>().isVecH(); }
109 : static inline bool isVecS(const Operand_& op) noexcept { return op.as<Reg>().isVecS(); }
110 : static inline bool isVecD(const Operand_& op) noexcept { return op.as<Reg>().isVecD(); }
111 : static inline bool isVecQ(const Operand_& op) noexcept { return op.as<Reg>().isVecQ(); }
112 : static inline bool isVecV(const Operand_& op) noexcept { return op.as<Reg>().isVecV(); }
113 :
114 : static inline bool isGpW(const Operand_& op, uint32_t id) noexcept { return isGpW(op) & (op.id() == id); }
115 : static inline bool isGpX(const Operand_& op, uint32_t id) noexcept { return isGpX(op) & (op.id() == id); }
116 : static inline bool isVecB(const Operand_& op, uint32_t id) noexcept { return isVecB(op) & (op.id() == id); }
117 : static inline bool isVecH(const Operand_& op, uint32_t id) noexcept { return isVecH(op) & (op.id() == id); }
118 : static inline bool isVecS(const Operand_& op, uint32_t id) noexcept { return isVecS(op) & (op.id() == id); }
119 : static inline bool isVecD(const Operand_& op, uint32_t id) noexcept { return isVecD(op) & (op.id() == id); }
120 : static inline bool isVecQ(const Operand_& op, uint32_t id) noexcept { return isVecQ(op) & (op.id() == id); }
121 : static inline bool isVecV(const Operand_& op, uint32_t id) noexcept { return isVecV(op) & (op.id() == id); }
122 : };
123 :
124 : //! General purpose register (ARM).
125 : class Gp : public Reg {
126 : public:
127 : ASMJIT_DEFINE_ABSTRACT_REG(Gp, Reg)
128 :
129 : //! Special register id.
130 : enum Id : uint32_t {
131 : //! Register that depends on OS, could be used as TLS offset.
132 : kIdOs = 18,
133 : //! Frame pointer.
134 : kIdFp = 29,
135 : //! Link register.
136 : kIdLr = 30,
137 : //! Stack register id.
138 : kIdSp = 31,
139 : //! Zero register id.
140 : //!
141 : //! Although zero register has the same id as stack register it has a special treatment, because we need to be
142 : //! able to distinguish between these two at API level. Some intructions were designed to be used with SP and
143 : //! some other with ZR - so we need a way to distinguish these two to make sure we emit the right thing.
144 : //!
145 : //! The number 63 is not random, when you perform `id & 31` you would always get 31 for both SP and ZR inputs,
146 : //! which is the identifier used by AArch64 ISA to encode either SP or ZR depending on the instruction.
147 : kIdZr = 63
148 : };
149 :
150 : inline constexpr bool isZR() const noexcept { return id() == kIdZr; }
151 : inline constexpr bool isSP() const noexcept { return id() == kIdSp; }
152 :
153 : //! Cast this register to a 32-bit R|W.
154 : inline GpW w() const noexcept;
155 : //! Cast this register to a 64-bit X.
156 : inline GpX x() const noexcept;
157 : };
158 :
159 : //! Vector register (ARM).
160 : class Vec : public Reg {
161 : public:
162 : ASMJIT_DEFINE_ABSTRACT_REG(Vec, Reg)
163 :
164 : //! Additional signature bits used by arm::Vec.
165 : enum AdditionalBits : uint32_t {
166 : // Register element type (3 bits).
167 : // |........|........|.XXX....|........|
168 : kSignatureRegElementTypeShift = 12,
169 : kSignatureRegElementTypeMask = 0x07 << kSignatureRegElementTypeShift,
170 :
171 : // Register has element index (1 bit).
172 : // |........|........|X.......|........|
173 : kSignatureRegElementFlagShift = 15,
174 : kSignatureRegElementFlagMask = 0x01 << kSignatureRegElementFlagShift,
175 :
176 : // Register element index (4 bits).
177 : // |........|....XXXX|........|........|
178 : kSignatureRegElementIndexShift = 16,
179 : kSignatureRegElementIndexMask = 0x0F << kSignatureRegElementIndexShift
180 : };
181 :
182 : //! Element type.
183 : enum ElementType : uint32_t {
184 : //! No element type specified.
185 : kElementTypeNone = 0,
186 : //! Byte elements (B8 or B16).
187 : kElementTypeB,
188 : //! Halfword elements (H4 or H8).
189 : kElementTypeH,
190 : //! Singleword elements (S2 or S4).
191 : kElementTypeS,
192 : //! Doubleword elements (D2).
193 : kElementTypeD,
194 : //! Byte elements grouped by 4 bytes (B4).
195 : //!
196 : //! \note This element-type is only used by few instructions.
197 : kElementTypeB4,
198 : //! Halfword elements grouped by 2 halfwords (H2).
199 : //!
200 : //! \note This element-type is only used by few instructions.
201 : kElementTypeH2,
202 :
203 : //! Count of element types.
204 : kElementTypeCount
205 : };
206 :
207 : //! \cond
208 : //! Shortcuts.
209 : enum SignatureReg : uint32_t {
210 : kSignatureElementB = kElementTypeB << kSignatureRegElementTypeShift,
211 : kSignatureElementH = kElementTypeH << kSignatureRegElementTypeShift,
212 : kSignatureElementS = kElementTypeS << kSignatureRegElementTypeShift,
213 : kSignatureElementD = kElementTypeD << kSignatureRegElementTypeShift,
214 : kSignatureElementB4 = kElementTypeB4 << kSignatureRegElementTypeShift,
215 : kSignatureElementH2 = kElementTypeH2 << kSignatureRegElementTypeShift
216 : };
217 : //! \endcond
218 :
219 : //! Returns whether the register has associated an element type.
220 : inline constexpr bool hasElementType() const noexcept { return _signature.hasField<kSignatureRegElementTypeMask>(); }
221 : //! Returns whether the register has element index (it's an element index access).
222 : inline constexpr bool hasElementIndex() const noexcept { return _signature.hasField<kSignatureRegElementFlagMask>(); }
223 : //! Returns whether the reggister has element type or element index (or both).
224 : inline constexpr bool hasElementTypeOrIndex() const noexcept { return _signature.hasField<kSignatureRegElementTypeMask | kSignatureRegElementFlagMask>(); }
225 :
226 : //! Returns element type of the register.
227 : inline constexpr uint32_t elementType() const noexcept { return _signature.getField<kSignatureRegElementTypeMask>(); }
228 : //! Sets element type of the register to `elementType`.
229 : inline void setElementType(uint32_t elementType) noexcept { _signature.setField<kSignatureRegElementTypeMask>(elementType); }
230 : //! Resets element type to none.
231 : inline void resetElementType() noexcept { _signature.setField<kSignatureRegElementTypeMask>(0); }
232 :
233 : //! Returns element index of the register.
234 : inline constexpr uint32_t elementIndex() const noexcept { return _signature.getField<kSignatureRegElementIndexMask>(); }
235 : //! Sets element index of the register to `elementType`.
236 : inline void setElementIndex(uint32_t elementIndex) noexcept {
237 : _signature |= kSignatureRegElementFlagMask;
238 : _signature.setField<kSignatureRegElementIndexMask>(elementIndex);
239 : }
240 : //! Resets element index of the register.
241 : inline void resetElementIndex() noexcept {
242 : _signature &= ~(kSignatureRegElementFlagMask | kSignatureRegElementIndexMask);
243 : }
244 :
245 : inline constexpr bool isVecB8() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecD>::kSignature | kSignatureElementB); }
246 : inline constexpr bool isVecH4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecD>::kSignature | kSignatureElementH); }
247 : inline constexpr bool isVecS2() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecD>::kSignature | kSignatureElementS); }
248 : inline constexpr bool isVecD1() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecD>::kSignature); }
249 :
250 : inline constexpr bool isVecB16() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementB); }
251 : inline constexpr bool isVecH8() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementH); }
252 : inline constexpr bool isVecS4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementS); }
253 : inline constexpr bool isVecD2() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementD); }
254 : inline constexpr bool isVecB4x4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementB4); }
255 : inline constexpr bool isVecH2x4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementH2); }
256 :
257 : //! Creates a cloned register with element access.
258 : inline Vec at(uint32_t elementIndex) const noexcept {
259 : return Vec((signature() & ~kSignatureRegElementIndexMask) | (elementIndex << kSignatureRegElementIndexShift) | kSignatureRegElementFlagMask, id());
260 : }
261 :
262 : //! Cast this register to an 8-bit B register (scalar).
263 : inline VecB b() const noexcept;
264 : //! Cast this register to a 16-bit H register (scalar).
265 : inline VecH h() const noexcept;
266 : //! Cast this register to a 32-bit S register (scalar).
267 : inline VecS s() const noexcept;
268 : //! Cast this register to a 64-bit D register (scalar).
269 : inline VecD d() const noexcept;
270 : //! Cast this register to a 128-bit Q register (scalar).
271 : inline VecV q() const noexcept;
272 : //! Cast this register to a 128-bit V register.
273 : inline VecV v() const noexcept;
274 :
275 : //! Cast this register to a 128-bit V.B[elementIndex] register.
276 : inline VecV b(uint32_t elementIndex) const noexcept;
277 : //! Cast this register to a 128-bit V.H[elementIndex] register.
278 : inline VecV h(uint32_t elementIndex) const noexcept;
279 : //! Cast this register to a 128-bit V.S[elementIndex] register.
280 : inline VecV s(uint32_t elementIndex) const noexcept;
281 : //! Cast this register to a 128-bit V.D[elementIndex] register.
282 : inline VecV d(uint32_t elementIndex) const noexcept;
283 : //! Cast this register to a 128-bit V.H2[elementIndex] register.
284 : inline VecV h2(uint32_t elementIndex) const noexcept;
285 : //! Cast this register to a 128-bit V.B4[elementIndex] register.
286 : inline VecV b4(uint32_t elementIndex) const noexcept;
287 :
288 : //! Cast this register to V.8B.
289 : inline VecD b8() const noexcept;
290 : //! Cast this register to V.16B.
291 : inline VecV b16() const noexcept;
292 : //! Cast this register to V.2H.
293 : inline VecS h2() const noexcept;
294 : //! Cast this register to V.4H.
295 : inline VecD h4() const noexcept;
296 : //! Cast this register to V.8H.
297 : inline VecV h8() const noexcept;
298 : //! Cast this register to V.2S.
299 : inline VecD s2() const noexcept;
300 : //! Cast this register to V.4S.
301 : inline VecV s4() const noexcept;
302 : //! Cast this register to V.2D.
303 : inline VecV d2() const noexcept;
304 :
305 : static inline constexpr OperandSignature _makeElementAccessSignature(uint32_t elementType, uint32_t elementIndex) noexcept {
306 : return OperandSignature{
307 : uint32_t(RegTraits<RegType::kARM_VecV>::kSignature) |
308 : uint32_t(kSignatureRegElementFlagMask) |
309 : uint32_t(elementType << kSignatureRegElementTypeShift) |
310 : uint32_t(elementIndex << kSignatureRegElementIndexShift)};
311 : }
312 : };
313 :
314 : //! 32-bit GPW (AArch64) and/or GPR (ARM/AArch32) register.
315 : class GpW : public Gp { ASMJIT_DEFINE_FINAL_REG(GpW, Gp, RegTraits<RegType::kARM_GpW>) };
316 : //! 64-bit GPX (AArch64) register.
317 : class GpX : public Gp { ASMJIT_DEFINE_FINAL_REG(GpX, Gp, RegTraits<RegType::kARM_GpX>) };
318 :
319 : //! 8-bit view (S) of VFP/SIMD register.
320 : class VecB : public Vec { ASMJIT_DEFINE_FINAL_REG(VecB, Vec, RegTraits<RegType::kARM_VecB>) };
321 : //! 16-bit view (S) of VFP/SIMD register.
322 : class VecH : public Vec { ASMJIT_DEFINE_FINAL_REG(VecH, Vec, RegTraits<RegType::kARM_VecH>) };
323 : //! 32-bit view (S) of VFP/SIMD register.
324 : class VecS : public Vec { ASMJIT_DEFINE_FINAL_REG(VecS, Vec, RegTraits<RegType::kARM_VecS>) };
325 : //! 64-bit view (D) of VFP/SIMD register.
326 : class VecD : public Vec { ASMJIT_DEFINE_FINAL_REG(VecD, Vec, RegTraits<RegType::kARM_VecD>) };
327 : //! 128-bit vector register (Q or V).
328 : class VecV : public Vec { ASMJIT_DEFINE_FINAL_REG(VecV, Vec, RegTraits<RegType::kARM_VecV>) };
329 :
330 : inline GpW Gp::w() const noexcept { return GpW(id()); }
331 : inline GpX Gp::x() const noexcept { return GpX(id()); }
332 :
333 : inline VecB Vec::b() const noexcept { return VecB(id()); }
334 : inline VecH Vec::h() const noexcept { return VecH(id()); }
335 : inline VecS Vec::s() const noexcept { return VecS(id()); }
336 : inline VecD Vec::d() const noexcept { return VecD(id()); }
337 : inline VecV Vec::q() const noexcept { return VecV(id()); }
338 : inline VecV Vec::v() const noexcept { return VecV(id()); }
339 :
340 : inline VecV Vec::b(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeB, elementIndex), id()); }
341 : inline VecV Vec::h(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeH, elementIndex), id()); }
342 : inline VecV Vec::s(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeS, elementIndex), id()); }
343 : inline VecV Vec::d(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeD, elementIndex), id()); }
344 : inline VecV Vec::h2(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeH2, elementIndex), id()); }
345 : inline VecV Vec::b4(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeB4, elementIndex), id()); }
346 :
347 : inline VecD Vec::b8() const noexcept { return VecD(OperandSignature{VecD::kSignature | kSignatureElementB}, id()); }
348 : inline VecS Vec::h2() const noexcept { return VecS(OperandSignature{VecS::kSignature | kSignatureElementH}, id()); }
349 : inline VecD Vec::h4() const noexcept { return VecD(OperandSignature{VecD::kSignature | kSignatureElementH}, id()); }
350 : inline VecD Vec::s2() const noexcept { return VecD(OperandSignature{VecD::kSignature | kSignatureElementS}, id()); }
351 : inline VecV Vec::b16() const noexcept { return VecV(OperandSignature{VecV::kSignature | kSignatureElementB}, id()); }
352 : inline VecV Vec::h8() const noexcept { return VecV(OperandSignature{VecV::kSignature | kSignatureElementH}, id()); }
353 : inline VecV Vec::s4() const noexcept { return VecV(OperandSignature{VecV::kSignature | kSignatureElementS}, id()); }
354 : inline VecV Vec::d2() const noexcept { return VecV(OperandSignature{VecV::kSignature | kSignatureElementD}, id()); }
355 :
356 : #ifndef _DOXYGEN
357 : namespace regs {
358 : #endif
359 :
360 : //! Creates a 32-bit W register operand (ARM/AArch64).
361 : static inline constexpr GpW w(uint32_t id) noexcept { return GpW(id); }
362 : //! Creates a 64-bit X register operand (AArch64).
363 : static inline constexpr GpX x(uint32_t id) noexcept { return GpX(id); }
364 : //! Creates a 32-bit S register operand (ARM/AArch64).
365 : static inline constexpr VecS s(uint32_t id) noexcept { return VecS(id); }
366 : //! Creates a 64-bit D register operand (ARM/AArch64).
367 : static inline constexpr VecD d(uint32_t id) noexcept { return VecD(id); }
368 : //! Creates a 1282-bit V register operand (ARM/AArch64).
369 : static inline constexpr VecV v(uint32_t id) noexcept { return VecV(id); }
370 :
371 : #ifndef _DOXYGEN
372 : } // {regs}
373 :
374 : // Make `arm::regs` accessible through `arm` namespace as well.
375 : using namespace regs;
376 : #endif
377 :
378 : //! Memory operand (ARM).
379 : class Mem : public BaseMem {
380 : public:
381 : //! \cond INTERNAL
382 : //! Additional bits of operand's signature used by `arm::Mem`.
383 : enum AdditionalBits : uint32_t {
384 : // Index shift value (5 bits).
385 : // |........|.....XXX|XX......|........|
386 : kSignatureMemShiftValueShift = 14,
387 : kSignatureMemShiftValueMask = 0x1Fu << kSignatureMemShiftValueShift,
388 :
389 : // Shift operation type (4 bits).
390 : // |........|XXXX....|........|........|
391 : kSignatureMemPredicateShift = 20,
392 : kSignatureMemPredicateMask = 0x0Fu << kSignatureMemPredicateShift
393 : };
394 : //! \endcond
395 :
396 : //! Memory offset mode.
397 : //!
398 : //! Additional constants that can be used with the `predicate`.
399 : enum OffsetMode : uint32_t {
400 : //! Pre-index "[BASE, #Offset {, <shift>}]!" with write-back.
401 : kOffsetPreIndex = 0xE,
402 : //! Post-index "[BASE], #Offset {, <shift>}" with write-back.
403 : kOffsetPostIndex = 0xF
404 : };
405 :
406 : //! \name Construction & Destruction
407 : //! \{
408 :
409 : //! Construct a default `Mem` operand, that points to [0].
410 : inline constexpr Mem() noexcept
411 : : BaseMem() {}
412 :
413 : inline constexpr Mem(const Mem& other) noexcept
414 : : BaseMem(other) {}
415 :
416 : inline explicit Mem(Globals::NoInit_) noexcept
417 : : BaseMem(Globals::NoInit) {}
418 :
419 : inline constexpr Mem(const Signature& signature, uint32_t baseId, uint32_t indexId, int32_t offset) noexcept
420 : : BaseMem(signature, baseId, indexId, offset) {}
421 :
422 : inline constexpr explicit Mem(const Label& base, int32_t off = 0, Signature signature = Signature{0}) noexcept
423 : : BaseMem(Signature::fromOpType(OperandType::kMem) |
424 : Signature::fromMemBaseType(RegType::kLabelTag) |
425 : signature, base.id(), 0, off) {}
426 :
427 : inline constexpr explicit Mem(const BaseReg& base, int32_t off = 0, Signature signature = Signature{0}) noexcept
428 : : BaseMem(Signature::fromOpType(OperandType::kMem) |
429 : Signature::fromMemBaseType(base.type()) |
430 : signature, base.id(), 0, off) {}
431 :
432 : inline constexpr Mem(const BaseReg& base, const BaseReg& index, Signature signature = Signature{0}) noexcept
433 : : BaseMem(Signature::fromOpType(OperandType::kMem) |
434 : Signature::fromMemBaseType(base.type()) |
435 : Signature::fromMemIndexType(index.type()) |
436 : signature, base.id(), index.id(), 0) {}
437 :
438 : inline constexpr Mem(const BaseReg& base, const BaseReg& index, const Shift& shift, Signature signature = Signature{0}) noexcept
439 : : BaseMem(Signature::fromOpType(OperandType::kMem) |
440 : Signature::fromMemBaseType(base.type()) |
441 : Signature::fromMemIndexType(index.type()) |
442 : Signature::fromValue<kSignatureMemPredicateMask>(uint32_t(shift.op())) |
443 : Signature::fromValue<kSignatureMemShiftValueMask>(shift.value()) |
444 : signature, base.id(), index.id(), 0) {}
445 :
446 : inline constexpr Mem(uint64_t base, Signature signature = Signature{0}) noexcept
447 : : BaseMem(Signature::fromOpType(OperandType::kMem) |
448 : signature, uint32_t(base >> 32), 0, int32_t(uint32_t(base & 0xFFFFFFFFu))) {}
449 :
450 : //! \}
451 :
452 : //! \name Overloaded Operators
453 : //! \{
454 :
455 : inline Mem& operator=(const Mem& other) noexcept = default;
456 :
457 : //! \}
458 :
459 : //! \name Clone
460 : //! \{
461 :
462 : //! Clones the memory operand.
463 : inline constexpr Mem clone() const noexcept { return Mem(*this); }
464 :
465 : //! Gets new memory operand adjusted by `off`.
466 : inline Mem cloneAdjusted(int64_t off) const noexcept {
467 : Mem result(*this);
468 : result.addOffset(off);
469 : return result;
470 : }
471 :
472 : //! Clones the memory operand and makes it pre-index.
473 : inline Mem pre() const noexcept {
474 : Mem result(*this);
475 : result.setPredicate(kOffsetPreIndex);
476 : return result;
477 : }
478 :
479 : //! Clones the memory operand, applies a given offset `off` and makes it pre-index.
480 : inline Mem pre(int64_t off) const noexcept {
481 : Mem result(*this);
482 : result.setPredicate(kOffsetPreIndex);
483 : result.addOffset(off);
484 : return result;
485 : }
486 :
487 : //! Clones the memory operand and makes it post-index.
488 : inline Mem post() const noexcept {
489 : Mem result(*this);
490 : result.setPredicate(kOffsetPreIndex);
491 : return result;
492 : }
493 :
494 : //! Clones the memory operand, applies a given offset `off` and makes it post-index.
495 : inline Mem post(int64_t off) const noexcept {
496 : Mem result(*this);
497 : result.setPredicate(kOffsetPostIndex);
498 : result.addOffset(off);
499 : return result;
500 : }
501 :
502 : //! \}
503 :
504 : //! \name Base & Index
505 : //! \{
506 :
507 : //! Converts memory `baseType` and `baseId` to `arm::Reg` instance.
508 : //!
509 : //! The memory must have a valid base register otherwise the result will be wrong.
510 : inline Reg baseReg() const noexcept { return Reg::fromTypeAndId(baseType(), baseId()); }
511 :
512 : //! Converts memory `indexType` and `indexId` to `arm::Reg` instance.
513 : //!
514 : //! The memory must have a valid index register otherwise the result will be wrong.
515 : inline Reg indexReg() const noexcept { return Reg::fromTypeAndId(indexType(), indexId()); }
516 :
517 : using BaseMem::setIndex;
518 :
519 : inline void setIndex(const BaseReg& index, uint32_t shift) noexcept {
520 : setIndex(index);
521 : setShift(shift);
522 : }
523 :
524 : //! \}
525 :
526 : //! \name ARM Specific Features
527 : //! \{
528 :
529 : //! Gets whether the memory operand has shift (aka scale) constant.
530 : inline constexpr bool hasShift() const noexcept { return _signature.hasField<kSignatureMemShiftValueMask>(); }
531 : //! Gets the memory operand's shift (aka scale) constant.
532 : inline constexpr uint32_t shift() const noexcept { return _signature.getField<kSignatureMemShiftValueMask>(); }
533 : //! Sets the memory operand's shift (aka scale) constant.
534 : inline void setShift(uint32_t shift) noexcept { _signature.setField<kSignatureMemShiftValueMask>(shift); }
535 : //! Resets the memory operand's shift (aka scale) constant to zero.
536 : inline void resetShift() noexcept { _signature.setField<kSignatureMemShiftValueMask>(0); }
537 :
538 : //! Gets memory predicate (shift mode or offset mode), see \ref ShiftOp and \ref OffsetMode.
539 : inline constexpr uint32_t predicate() const noexcept { return _signature.getField<kSignatureMemPredicateMask>(); }
540 : //! Sets memory predicate to `predicate`, see `Mem::ShiftOp`.
541 : inline void setPredicate(uint32_t predicate) noexcept { _signature.setField<kSignatureMemPredicateMask>(predicate); }
542 : //! Resets shift mode to LSL (default).
543 : inline void resetPredicate() noexcept { _signature.setField<kSignatureMemPredicateMask>(0); }
544 :
545 : inline constexpr bool isFixedOffset() const noexcept { return predicate() < kOffsetPreIndex; }
546 0 : inline constexpr bool isPreOrPost() const noexcept { return predicate() >= kOffsetPreIndex; }
547 0 : inline constexpr bool isPreIndex() const noexcept { return predicate() == kOffsetPreIndex; }
548 0 : inline constexpr bool isPostIndex() const noexcept { return predicate() == kOffsetPostIndex; }
549 :
550 : inline void resetToFixedOffset() noexcept { resetPredicate(); }
551 0 : inline void makePreIndex() noexcept { setPredicate(kOffsetPreIndex); }
552 0 : inline void makePostIndex() noexcept { setPredicate(kOffsetPostIndex); }
553 :
554 : //! \}
555 : };
556 :
557 : //! Creates `[base.reg, offset]` memory operand (offset mode).
558 : static inline constexpr Mem ptr(const Gp& base, int32_t offset = 0) noexcept {
559 : return Mem(base, offset);
560 : }
561 :
562 : //! Creates `[base.reg, offset]!` memory operand (pre-index mode).
563 : static inline constexpr Mem ptr_pre(const Gp& base, int32_t offset = 0) noexcept {
564 : return Mem(base, offset, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPreIndex));
565 : }
566 :
567 : //! Creates `[base.reg], offset` memory operand (post-index mode).
568 : static inline constexpr Mem ptr_post(const Gp& base, int32_t offset = 0) noexcept {
569 : return Mem(base, offset, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPostIndex));
570 : }
571 :
572 : //! Creates `[base.reg, index]` memory operand.
573 : static inline constexpr Mem ptr(const Gp& base, const Gp& index) noexcept {
574 : return Mem(base, index);
575 : }
576 :
577 : //! Creates `[base.reg], index` memory operand (post-index mode).
578 : static inline constexpr Mem ptr_post(const Gp& base, const Gp& index) noexcept {
579 : return Mem(base, index, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPostIndex));
580 : }
581 :
582 : //! Creates `[base.reg, index, SHIFT_OP #shift]` memory operand.
583 : static inline constexpr Mem ptr(const Gp& base, const Gp& index, const Shift& shift) noexcept {
584 : return Mem(base, index, shift);
585 : }
586 :
587 : //! Creates `[base + offset]` memory operand.
588 : static inline constexpr Mem ptr(const Label& base, int32_t offset = 0) noexcept {
589 : return Mem(base, offset);
590 : }
591 :
592 : // TODO: [ARM] PC + offset address.
593 : #if 0
594 : //! Creates `[PC + offset]` (relative) memory operand.
595 : static inline constexpr Mem ptr(const PC& pc, int32_t offset = 0) noexcept {
596 : return Mem(pc, offset);
597 : }
598 : #endif
599 :
600 : //! Creates `[base]` absolute memory operand.
601 : //!
602 : //! \note The concept of absolute memory operands doesn't exist on ARM, the ISA only provides PC relative addressing.
603 : //! Absolute memory operands can only be used if it's known that the PC relative offset is encodable and that it
604 : //! would be within the limits. Absolute address is also often output from disassemblers, so AsmJit support it so it
605 : //! can assemble it back.
606 : static inline constexpr Mem ptr(uint64_t base) noexcept { return Mem(base); }
607 :
608 : //! \}
609 :
610 : ASMJIT_END_SUB_NAMESPACE
611 :
612 : //! \cond INTERNAL
613 : ASMJIT_BEGIN_NAMESPACE
614 : ASMJIT_DEFINE_TYPE_ID(arm::GpW, TypeId::kInt32);
615 : ASMJIT_DEFINE_TYPE_ID(arm::GpX, TypeId::kInt64);
616 : ASMJIT_DEFINE_TYPE_ID(arm::VecS, TypeId::kFloat32x1);
617 : ASMJIT_DEFINE_TYPE_ID(arm::VecD, TypeId::kFloat64x1);
618 : ASMJIT_DEFINE_TYPE_ID(arm::VecV, TypeId::kInt32x4);
619 : ASMJIT_END_NAMESPACE
620 : //! \endcond
621 :
622 : #endif // ASMJIT_ARM_ARMOPERAND_H_INCLUDED
623 :
624 : #endif // __PLUMED_HAS_ASMJIT
|