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_CORE_ARCHTRAITS_H_INCLUDED
8 : #define ASMJIT_CORE_ARCHTRAITS_H_INCLUDED
9 :
10 : #include "operand.h"
11 : #include "support.h"
12 : #include "type.h"
13 :
14 : ASMJIT_BEGIN_NAMESPACE
15 :
16 : //! \addtogroup asmjit_core
17 : //! \{
18 :
19 : //! Instruction set architecture (ISA).
20 : enum class Arch : uint8_t {
21 : //! Unknown or uninitialized ISA.
22 : kUnknown = 0,
23 :
24 : //! 32-bit X86 ISA.
25 : kX86 = 1,
26 : //! 64-bit X86 ISA also known as X64, X86_64, and AMD64.
27 : kX64 = 2,
28 :
29 : //! 32-bit RISC-V ISA.
30 : kRISCV32 = 3,
31 : //! 64-bit RISC-V ISA.
32 : kRISCV64 = 4,
33 :
34 : //! 32-bit ARM ISA (little endian).
35 : kARM = 5,
36 : //! 64-bit ARM ISA in (little endian).
37 : kAArch64 = 6,
38 : //! 32-bit ARM ISA in Thumb mode (little endian).
39 : kThumb = 7,
40 :
41 : // 8 is not used at the moment, even numbers are 64-bit architectures.
42 :
43 : //! 32-bit MIPS ISA in (little endian).
44 : kMIPS32_LE = 9,
45 : //! 64-bit MIPS ISA in (little endian).
46 : kMIPS64_LE = 10,
47 :
48 : //! 32-bit ARM ISA (big endian).
49 : kARM_BE = 11,
50 : //! 64-bit ARM ISA in (big endian).
51 : kAArch64_BE = 12,
52 : //! 32-bit ARM ISA in Thumb mode (big endian).
53 : kThumb_BE = 13,
54 :
55 : // 14 is not used at the moment, even numbers are 64-bit architectures.
56 :
57 : //! 32-bit MIPS ISA in (big endian).
58 : kMIPS32_BE = 15,
59 : //! 64-bit MIPS ISA in (big endian).
60 : kMIPS64_BE = 16,
61 :
62 : //! Maximum value of `Arch`.
63 : kMaxValue = kMIPS64_BE,
64 :
65 : //! Mask used by 32-bit ISAs (odd are 32-bit, even are 64-bit).
66 : k32BitMask = 0x01,
67 : //! First big-endian architecture.
68 : kBigEndian = kARM_BE,
69 :
70 : //! ISA detected at compile-time (ISA of the host).
71 : kHost =
72 : #if defined(_DOXYGEN)
73 : DETECTED_AT_COMPILE_TIME
74 : #else
75 : ASMJIT_ARCH_X86 == 32 ? kX86 :
76 : ASMJIT_ARCH_X86 == 64 ? kX64 :
77 :
78 : ASMJIT_ARCH_ARM == 32 && ASMJIT_ARCH_LE ? kARM :
79 : ASMJIT_ARCH_ARM == 32 && ASMJIT_ARCH_BE ? kARM_BE :
80 : ASMJIT_ARCH_ARM == 64 && ASMJIT_ARCH_LE ? kAArch64 :
81 : ASMJIT_ARCH_ARM == 64 && ASMJIT_ARCH_BE ? kAArch64_BE :
82 :
83 : ASMJIT_ARCH_MIPS == 32 && ASMJIT_ARCH_LE ? kMIPS32_LE :
84 : ASMJIT_ARCH_MIPS == 32 && ASMJIT_ARCH_BE ? kMIPS32_BE :
85 : ASMJIT_ARCH_MIPS == 64 && ASMJIT_ARCH_LE ? kMIPS64_LE :
86 : ASMJIT_ARCH_MIPS == 64 && ASMJIT_ARCH_BE ? kMIPS64_BE :
87 :
88 : kUnknown
89 : #endif
90 : };
91 :
92 : //! Sub-architecture.
93 : enum class SubArch : uint8_t {
94 : //! Unknown or uninitialized architecture sub-type.
95 : kUnknown = 0,
96 :
97 : //! Maximum value of `SubArch`.
98 : kMaxValue = kUnknown,
99 :
100 : //! Sub-architecture detected at compile-time (sub-architecture of the host).
101 : kHost =
102 : #if defined(_DOXYGEN)
103 : DETECTED_AT_COMPILE_TIME
104 : #else
105 : kUnknown
106 : #endif
107 : };
108 :
109 : //! Identifier used to represent names of different data types across architectures.
110 : enum class ArchTypeNameId : uint8_t {
111 : //! Describes 'db' (X86/X86_64 convention, always 8-bit quantity).
112 : kDB = 0,
113 : //! Describes 'dw' (X86/X86_64 convention, always 16-bit word).
114 : kDW,
115 : //! Describes 'dd' (X86/X86_64 convention, always 32-bit word).
116 : kDD,
117 : //! Describes 'dq' (X86/X86_64 convention, always 64-bit word).
118 : kDQ,
119 : //! Describes 'byte' (always 8-bit quantity).
120 : kByte,
121 : //! Describes 'half' (most likely 16-bit word).
122 : kHalf,
123 : //! Describes 'word' (either 16-bit or 32-bit word).
124 : kWord,
125 : //! Describes 'hword' (most likely 16-bit word).
126 : kHWord,
127 : //! Describes 'dword' (either 32-bit or 64-bit word).
128 : kDWord,
129 : //! Describes 'qword' (64-bit word).
130 : kQWord,
131 : //! Describes 'xword' (64-bit word).
132 : kXWord,
133 : //! Describes 'short' (always 16-bit word).
134 : kShort,
135 : //! Describes 'long' (most likely 32-bit word).
136 : kLong,
137 : //! Describes 'quad' (64-bit word).
138 : kQuad,
139 :
140 : //! Maximum value of `ArchTypeNameId`.
141 : kMaxValue = kQuad
142 : };
143 :
144 : //! Instruction feature hints for each register group provided by \ref ArchTraits.
145 : //!
146 : //! Instruction feature hints describe miscellaneous instructions provided by the architecture that can be used by
147 : //! register allocator to make certain things simpler - like register swaps or emitting register push/pop sequences.
148 : //!
149 : //! \remarks Instruction feature hints are only defined for register groups that can be used with \ref
150 : //! asmjit_compiler infrastructure. Register groups that are not managed by Compiler are not provided by
151 : //! \ref ArchTraits and cannot be queried.
152 : enum class InstHints : uint8_t {
153 : //! No feature hints.
154 : kNoHints = 0,
155 :
156 : //! Architecture supports a register swap by using a single instruction.
157 : kRegSwap = 0x01u,
158 : //! Architecture provides push/pop instructions.
159 : kPushPop = 0x02u
160 : };
161 : ASMJIT_DEFINE_ENUM_FLAGS(InstHints)
162 :
163 : //! Architecture traits used by Function API and Compiler's register allocator.
164 : struct ArchTraits {
165 : //! \name Members
166 : //! \{
167 :
168 : //! Stack pointer register id.
169 : uint8_t _spRegId;
170 : //! Frame pointer register id.
171 : uint8_t _fpRegId;
172 : //! Link register id.
173 : uint8_t _linkRegId;
174 : //! Instruction pointer (or program counter) register id, if accessible.
175 : uint8_t _ipRegId;
176 :
177 : // Reserved.
178 : uint8_t _reserved[3];
179 : //! Hardware stack alignment requirement.
180 : uint8_t _hwStackAlignment;
181 :
182 : //! Minimum addressable offset on stack guaranteed for all instructions.
183 : uint32_t _minStackOffset;
184 : //! Maximum addressable offset on stack depending on specific instruction.
185 : uint32_t _maxStackOffset;
186 :
187 : //! Flags for each virtual register group.
188 : Support::Array<InstHints, Globals::kNumVirtGroups> _instHints;
189 :
190 : //! Maps register type into a signature, that provides group, size and can be used to construct register operands.
191 : Support::Array<OperandSignature, uint32_t(RegType::kMaxValue) + 1> _regSignature;
192 : //! Maps a register to type-id, see \ref TypeId.
193 : Support::Array<TypeId, uint32_t(RegType::kMaxValue) + 1> _regTypeToTypeId;
194 : //! Maps scalar TypeId values (from TypeId::_kIdBaseStart) to register types, see \ref TypeId.
195 : Support::Array<RegType, 32> _typeIdToRegType;
196 :
197 : //! Word name identifiers of 8-bit, 16-bit, 32-biit, and 64-bit quantities that appear in formatted text.
198 : ArchTypeNameId _typeNameIdTable[4];
199 :
200 : //! \}
201 :
202 : //! \name Accessors
203 : //! \{
204 :
205 : //! Returns stack pointer register id.
206 82476 : inline uint32_t spRegId() const noexcept { return _spRegId; }
207 : //! Returns stack frame register id.
208 27492 : inline uint32_t fpRegId() const noexcept { return _fpRegId; }
209 : //! Returns link register id, if the architecture provides it.
210 27492 : inline uint32_t linkRegId() const noexcept { return _linkRegId; }
211 : //! Returns instruction pointer register id, if the architecture provides it.
212 : inline uint32_t ipRegId() const noexcept { return _ipRegId; }
213 :
214 : //! Returns a hardware stack alignment requirement.
215 : //!
216 : //! \note This is a hardware constraint. Architectures that don't constrain it would return the lowest alignment
217 : //! (1), however, some architectures may constrain the alignment, for example AArch64 requires 16-byte alignment.
218 : inline uint32_t hwStackAlignment() const noexcept { return _hwStackAlignment; }
219 :
220 : //! Tests whether the architecture provides link register, which is used across function calls. If the link
221 : //! register is not provided then a function call pushes the return address on stack (X86/X64).
222 27492 : inline bool hasLinkReg() const noexcept { return _linkRegId != BaseReg::kIdBad; }
223 :
224 : //! Returns minimum addressable offset on stack guaranteed for all instructions.
225 : inline uint32_t minStackOffset() const noexcept { return _minStackOffset; }
226 : //! Returns maximum addressable offset on stack depending on specific instruction.
227 : inline uint32_t maxStackOffset() const noexcept { return _maxStackOffset; }
228 :
229 : //! Returns ISA flags of the given register `group`.
230 : inline InstHints instFeatureHints(RegGroup group) const noexcept { return _instHints[group]; }
231 : //! Tests whether the given register `group` has the given `flag` set.
232 109968 : inline bool hasInstHint(RegGroup group, InstHints feature) const noexcept { return Support::test(_instHints[group], feature); }
233 : //! Tests whether the ISA provides register swap instruction for the given register `group`.
234 : inline bool hasInstRegSwap(RegGroup group) const noexcept { return hasInstHint(group, InstHints::kRegSwap); }
235 : //! Tests whether the ISA provides push/pop instructions for the given register `group`.
236 : inline bool hasInstPushPop(RegGroup group) const noexcept { return hasInstHint(group, InstHints::kPushPop); }
237 :
238 0 : inline bool hasRegType(RegType type) const noexcept {
239 0 : return type <= RegType::kMaxValue && _regSignature[type].isValid();
240 : }
241 :
242 : //! Returns an operand signature from the given register `type` of this architecture.
243 356253 : inline OperandSignature regTypeToSignature(RegType type) const noexcept { return _regSignature[type]; }
244 : //! Returns a register from the given register `type` of this architecture.
245 : inline RegGroup regTypeToGroup(RegType type) const noexcept { return _regSignature[type].regGroup(); }
246 : //! Returns a register size the given register `type` of this architecture.
247 : inline uint32_t regTypeToSize(RegType type) const noexcept { return _regSignature[type].size(); }
248 : //! Returns a corresponding `TypeId` from the given register `type` of this architecture.
249 0 : inline TypeId regTypeToTypeId(RegType type) const noexcept { return _regTypeToTypeId[type]; }
250 :
251 : //! Returns a table of ISA word names that appear in formatted text. Word names are ISA dependent.
252 : //!
253 : //! The index of this table is log2 of the size:
254 : //! - [0] 8-bits
255 : //! - [1] 16-bits
256 : //! - [2] 32-bits
257 : //! - [3] 64-bits
258 : inline const ArchTypeNameId* typeNameIdTable() const noexcept { return _typeNameIdTable; }
259 :
260 : //! Returns an ISA word name identifier of the given `index`, see \ref typeNameIdTable() for more details.
261 0 : inline ArchTypeNameId typeNameIdByIndex(uint32_t index) const noexcept { return _typeNameIdTable[index]; }
262 :
263 : //! \}
264 :
265 : //! \name Statics
266 : //! \{
267 :
268 : //! Returns a const reference to `ArchTraits` for the given architecture `arch`.
269 : static inline const ArchTraits& byArch(Arch arch) noexcept;
270 :
271 : //! \}
272 : };
273 :
274 : ASMJIT_VARAPI const ArchTraits _archTraits[uint32_t(Arch::kMaxValue) + 1];
275 :
276 : //! \cond
277 521205 : inline const ArchTraits& ArchTraits::byArch(Arch arch) noexcept { return _archTraits[uint32_t(arch)]; }
278 : //! \endcond
279 :
280 : //! Architecture utilities.
281 : namespace ArchUtils {
282 :
283 : ASMJIT_API Error typeIdToRegSignature(Arch arch, TypeId typeId, TypeId* typeIdOut, OperandSignature* regSignatureOut) noexcept;
284 :
285 : } // {ArchUtils}
286 :
287 : //! \}
288 :
289 : ASMJIT_END_NAMESPACE
290 :
291 : #endif // ASMJIT_CORE_ARCHTRAITS_H_INCLUDED
292 :
293 : #endif // __PLUMED_HAS_ASMJIT
|