Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2008-2017, Petr Kobalicek
3 :
4 : This software is provided 'as-is', without any express or implied
5 : warranty. In no event will the authors be held liable for any damages
6 : arising from the use of this software.
7 :
8 : Permission is granted to anyone to use this software for any purpose,
9 : including commercial applications, and to alter it and redistribute it
10 : freely, subject to the following restrictions:
11 :
12 : 1. The origin of this software must not be misrepresented; you must not
13 : claim that you wrote the original software. If you use this software
14 : in a product, an acknowledgment in the product documentation would be
15 : appreciated but is not required.
16 : 2. Altered source versions must be plainly marked as such, and must not be
17 : misrepresented as being the original software.
18 : 3. This notice may not be removed or altered from any source distribution.
19 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
20 : #ifdef __PLUMED_HAS_ASMJIT
21 : #pragma GCC diagnostic push
22 : #pragma GCC diagnostic ignored "-Wpedantic"
23 : // [AsmJit]
24 : // Complete x86/x64 JIT and Remote Assembler for C++.
25 : //
26 : // [License]
27 : // Zlib - See LICENSE.md file in the package.
28 :
29 : // [Export]
30 : #define ASMJIT_EXPORTS
31 :
32 : // [Dependencies]
33 : #include "./misc_p.h"
34 : #include "./utils.h"
35 : #include "./x86instimpl_p.h"
36 : #include "./x86operand.h"
37 :
38 : // [Api-Begin]
39 : #include "./asmjit_apibegin.h"
40 :
41 : namespace PLMD {
42 : namespace asmjit {
43 :
44 : // ============================================================================
45 : // [asmjit::X86InstImpl - Validate]
46 : // ============================================================================
47 :
48 : #if !defined(ASMJIT_DISABLE_VALIDATION)
49 : template<uint32_t RegType>
50 : struct X86OpTypeFromRegTypeT {
51 : enum {
52 : kValue = (RegType == X86Reg::kRegGpbLo) ? X86Inst::kOpGpbLo :
53 : (RegType == X86Reg::kRegGpbHi) ? X86Inst::kOpGpbHi :
54 : (RegType == X86Reg::kRegGpw ) ? X86Inst::kOpGpw :
55 : (RegType == X86Reg::kRegGpd ) ? X86Inst::kOpGpd :
56 : (RegType == X86Reg::kRegGpq ) ? X86Inst::kOpGpq :
57 : (RegType == X86Reg::kRegXmm ) ? X86Inst::kOpXmm :
58 : (RegType == X86Reg::kRegYmm ) ? X86Inst::kOpYmm :
59 : (RegType == X86Reg::kRegZmm ) ? X86Inst::kOpZmm :
60 : (RegType == X86Reg::kRegRip ) ? X86Inst::kOpNone :
61 : (RegType == X86Reg::kRegSeg ) ? X86Inst::kOpSeg :
62 : (RegType == X86Reg::kRegFp ) ? X86Inst::kOpFp :
63 : (RegType == X86Reg::kRegMm ) ? X86Inst::kOpMm :
64 : (RegType == X86Reg::kRegK ) ? X86Inst::kOpK :
65 : (RegType == X86Reg::kRegBnd ) ? X86Inst::kOpBnd :
66 : (RegType == X86Reg::kRegCr ) ? X86Inst::kOpCr :
67 : (RegType == X86Reg::kRegDr ) ? X86Inst::kOpDr : X86Inst::kOpNone
68 : };
69 : };
70 :
71 : template<uint32_t RegType>
72 : struct X86RegMaskFromRegTypeT {
73 : enum {
74 : kMask = (RegType == X86Reg::kRegGpbLo) ? 0x0000000FU :
75 : (RegType == X86Reg::kRegGpbHi) ? 0x0000000FU :
76 : (RegType == X86Reg::kRegGpw ) ? 0x000000FFU :
77 : (RegType == X86Reg::kRegGpd ) ? 0x000000FFU :
78 : (RegType == X86Reg::kRegGpq ) ? 0x000000FFU :
79 : (RegType == X86Reg::kRegXmm ) ? 0x000000FFU :
80 : (RegType == X86Reg::kRegYmm ) ? 0x000000FFU :
81 : (RegType == X86Reg::kRegZmm ) ? 0x000000FFU :
82 : (RegType == X86Reg::kRegRip ) ? 0x00000001U :
83 : (RegType == X86Reg::kRegSeg ) ? 0x0000007EU : // [ES|CS|SS|DS|FS|GS]
84 : (RegType == X86Reg::kRegFp ) ? 0x000000FFU :
85 : (RegType == X86Reg::kRegMm ) ? 0x000000FFU :
86 : (RegType == X86Reg::kRegK ) ? 0x000000FFU :
87 : (RegType == X86Reg::kRegBnd ) ? 0x0000000FU :
88 : (RegType == X86Reg::kRegCr ) ? 0x0000FFFFU :
89 : (RegType == X86Reg::kRegDr ) ? 0x000000FFU : X86Inst::kOpNone
90 : };
91 : };
92 :
93 : template<uint32_t RegType>
94 : struct X64RegMaskFromRegTypeT {
95 : enum {
96 : kMask = (RegType == X86Reg::kRegGpbLo) ? 0x0000FFFFU :
97 : (RegType == X86Reg::kRegGpbHi) ? 0x0000000FU :
98 : (RegType == X86Reg::kRegGpw ) ? 0x0000FFFFU :
99 : (RegType == X86Reg::kRegGpd ) ? 0x0000FFFFU :
100 : (RegType == X86Reg::kRegGpq ) ? 0x0000FFFFU :
101 : (RegType == X86Reg::kRegXmm ) ? 0xFFFFFFFFU :
102 : (RegType == X86Reg::kRegYmm ) ? 0xFFFFFFFFU :
103 : (RegType == X86Reg::kRegZmm ) ? 0xFFFFFFFFU :
104 : (RegType == X86Reg::kRegRip ) ? 0x00000001U :
105 : (RegType == X86Reg::kRegSeg ) ? 0x0000007EU : // [ES|CS|SS|DS|FS|GS]
106 : (RegType == X86Reg::kRegFp ) ? 0x000000FFU :
107 : (RegType == X86Reg::kRegMm ) ? 0x000000FFU :
108 : (RegType == X86Reg::kRegK ) ? 0x000000FFU :
109 : (RegType == X86Reg::kRegBnd ) ? 0x0000000FU :
110 : (RegType == X86Reg::kRegCr ) ? 0x0000FFFFU :
111 : (RegType == X86Reg::kRegDr ) ? 0x0000FFFFU : X86Inst::kOpNone
112 : };
113 : };
114 :
115 : struct X86ValidationData {
116 : //! Allowed registers by reg-type (X86::kReg...).
117 : uint32_t allowedRegMask[X86Reg::kRegMax + 1];
118 : uint32_t allowedMemBaseRegs;
119 : uint32_t allowedMemIndexRegs;
120 : };
121 :
122 : static const uint32_t _x86OpFlagFromRegType[X86Reg::kRegMax + 1] = {
123 : ASMJIT_TABLE_T_32(X86OpTypeFromRegTypeT, kValue, 0)
124 : };
125 :
126 : static const X86ValidationData _x86ValidationData = {
127 : { ASMJIT_TABLE_T_32(X86RegMaskFromRegTypeT, kMask, 0) },
128 : (1U << X86Reg::kRegGpw) | (1U << X86Reg::kRegGpd) | (1U << X86Reg::kRegRip) | (1U << Label::kLabelTag),
129 : (1U << X86Reg::kRegGpw) | (1U << X86Reg::kRegGpd) | (1U << X86Reg::kRegXmm) | (1U << X86Reg::kRegYmm) | (1U << X86Reg::kRegZmm)
130 : };
131 :
132 : static const X86ValidationData _x64ValidationData = {
133 : { ASMJIT_TABLE_T_32(X64RegMaskFromRegTypeT, kMask, 0) },
134 : (1U << X86Reg::kRegGpd) | (1U << X86Reg::kRegGpq) | (1U << X86Reg::kRegRip) | (1U << Label::kLabelTag),
135 : (1U << X86Reg::kRegGpd) | (1U << X86Reg::kRegGpq) | (1U << X86Reg::kRegXmm) | (1U << X86Reg::kRegYmm) | (1U << X86Reg::kRegZmm)
136 : };
137 :
138 : static ASMJIT_INLINE bool x86CheckOSig(const X86Inst::OSignature& op, const X86Inst::OSignature& ref, bool& immOutOfRange) noexcept {
139 : // Fail if operand types are incompatible.
140 0 : uint32_t opFlags = op.flags;
141 0 : if ((opFlags & ref.flags) == 0) {
142 : // Mark temporarily `immOutOfRange` so we can return a more descriptive error.
143 0 : if ((opFlags & X86Inst::kOpAllImm) && (ref.flags & X86Inst::kOpAllImm)) {
144 : immOutOfRange = true;
145 0 : return true;
146 : }
147 :
148 : return false;
149 : }
150 :
151 : // Fail if memory specific flags and sizes are incompatibles.
152 0 : uint32_t opMemFlags = op.memFlags;
153 0 : if (opMemFlags != 0) {
154 0 : uint32_t refMemFlags = ref.memFlags;
155 0 : if ((refMemFlags & opMemFlags) == 0)
156 : return false;
157 :
158 0 : if ((refMemFlags & X86Inst::kMemOpBaseOnly) && !(opMemFlags & X86Inst::kMemOpBaseOnly))
159 : return false;
160 : }
161 :
162 : // Specific register index.
163 0 : if (opFlags & X86Inst::kOpAllRegs) {
164 0 : uint32_t refRegMask = ref.regMask;
165 0 : if (refRegMask && !(op.regMask & refRegMask))
166 0 : return false;
167 : }
168 :
169 : return true;
170 : }
171 :
172 0 : ASMJIT_FAVOR_SIZE Error X86InstImpl::validate(uint32_t archType, const Inst::Detail& detail, const Operand_* operands, uint32_t count) noexcept {
173 : uint32_t i;
174 : uint32_t archMask;
175 : const X86ValidationData* vd;
176 :
177 0 : if (!ArchInfo::isX86Family(archType))
178 : return DebugUtils::errored(kErrorInvalidArch);
179 :
180 0 : if (archType == ArchInfo::kTypeX86) {
181 : vd = &_x86ValidationData;
182 : archMask = X86Inst::kArchMaskX86;
183 : }
184 : else {
185 : vd = &_x64ValidationData;
186 : archMask = X86Inst::kArchMaskX64;
187 : }
188 :
189 : // Get the instruction data.
190 0 : uint32_t instId = detail.instId;
191 0 : uint32_t options = detail.options;
192 :
193 0 : if (ASMJIT_UNLIKELY(instId >= X86Inst::_kIdCount))
194 : return DebugUtils::errored(kErrorInvalidArgument);
195 :
196 : const X86Inst* iData = &X86InstDB::instData[instId];
197 : uint32_t iFlags = iData->getFlags();
198 :
199 : // Validate LOCK, XACQUIRE, and XRELEASE prefixes.
200 : const uint32_t kLockXAcqRel = X86Inst::kOptionXAcquire | X86Inst::kOptionXRelease;
201 0 : if (options & (X86Inst::kOptionLock | kLockXAcqRel)) {
202 0 : if (options & X86Inst::kOptionLock) {
203 0 : if (ASMJIT_UNLIKELY(!(iFlags & X86Inst::kFlagLock) && !(options & kLockXAcqRel)))
204 : return DebugUtils::errored(kErrorInvalidLockPrefix);
205 :
206 0 : if (ASMJIT_UNLIKELY(count < 1 || !operands[0].isMem()))
207 : return DebugUtils::errored(kErrorInvalidLockPrefix);
208 : }
209 :
210 0 : if (options & kLockXAcqRel) {
211 0 : if (ASMJIT_UNLIKELY(!(options & X86Inst::kOptionLock) || (options & kLockXAcqRel) == kLockXAcqRel))
212 : return DebugUtils::errored(kErrorInvalidPrefixCombination);
213 :
214 0 : if (ASMJIT_UNLIKELY((options & X86Inst::kOptionXAcquire) && !(iFlags & X86Inst::kFlagXAcquire)))
215 : return DebugUtils::errored(kErrorInvalidXAcquirePrefix);
216 :
217 0 : if (ASMJIT_UNLIKELY((options & X86Inst::kOptionXRelease) && !(iFlags & X86Inst::kFlagXRelease)))
218 : return DebugUtils::errored(kErrorInvalidXReleasePrefix);
219 : }
220 : }
221 :
222 : // Validate REP and REPNZ prefixes.
223 : const uint32_t kRepRepRepnz = X86Inst::kOptionRep | X86Inst::kOptionRepnz;
224 0 : if (options & kRepRepRepnz) {
225 0 : if (ASMJIT_UNLIKELY((options & kRepRepRepnz) == kRepRepRepnz))
226 : return DebugUtils::errored(kErrorInvalidPrefixCombination);
227 :
228 0 : if (ASMJIT_UNLIKELY((options & X86Inst::kOptionRep) && !(iFlags & X86Inst::kFlagRep)))
229 : return DebugUtils::errored(kErrorInvalidRepPrefix);
230 :
231 0 : if (ASMJIT_UNLIKELY((options & X86Inst::kOptionRepnz) && !(iFlags & X86Inst::kFlagRepnz)))
232 : return DebugUtils::errored(kErrorInvalidRepPrefix);
233 :
234 : // TODO: Validate extraReg {cx|ecx|rcx}.
235 : }
236 :
237 : // Translate the given operands to `X86Inst::OSignature`.
238 : X86Inst::OSignature oSigTranslated[6];
239 : uint32_t combinedOpFlags = 0;
240 : uint32_t combinedRegMask = 0;
241 :
242 : const X86Mem* memOp = nullptr;
243 :
244 0 : for (i = 0; i < count; i++) {
245 0 : const Operand_& op = operands[i];
246 0 : if (op.getOp() == Operand::kOpNone) break;
247 :
248 : uint32_t opFlags = 0;
249 : uint32_t memFlags = 0;
250 : uint32_t regMask = 0;
251 :
252 0 : switch (op.getOp()) {
253 : case Operand::kOpReg: {
254 : uint32_t regType = op.as<Reg>().getType();
255 0 : if (ASMJIT_UNLIKELY(regType >= X86Reg::kRegCount))
256 : return DebugUtils::errored(kErrorInvalidRegType);
257 :
258 0 : opFlags = _x86OpFlagFromRegType[regType];
259 0 : if (ASMJIT_UNLIKELY(opFlags == 0))
260 : return DebugUtils::errored(kErrorInvalidRegType);
261 :
262 : // If `regId` is equal or greater than Operand::kPackedIdMin it means
263 : // that the register is virtual and its index will be assigned later
264 : // by the register allocator. We must pass unless asked to disallow
265 : // virtual registers.
266 : // TODO: We need an option to refuse virtual regs here.
267 : uint32_t regId = op.getId();
268 0 : if (regId < Operand::kPackedIdMin) {
269 0 : if (ASMJIT_UNLIKELY(regId >= 32))
270 : return DebugUtils::errored(kErrorInvalidPhysId);
271 :
272 : regMask = Utils::mask(regId);
273 0 : if (ASMJIT_UNLIKELY((vd->allowedRegMask[regType] & regMask) == 0))
274 : return DebugUtils::errored(kErrorInvalidPhysId);
275 :
276 0 : combinedRegMask |= regMask;
277 : }
278 : else {
279 : regMask = 0xFFFFFFFFU;
280 : }
281 : break;
282 : }
283 :
284 : // TODO: Validate base and index and combine with `combinedRegMask`.
285 : case Operand::kOpMem: {
286 : const X86Mem& m = op.as<X86Mem>();
287 :
288 : uint32_t baseType = m.getBaseType();
289 : uint32_t indexType = m.getIndexType();
290 :
291 : memOp = &m;
292 :
293 0 : if (m.getSegmentId() > 6)
294 : return DebugUtils::errored(kErrorInvalidSegment);
295 :
296 0 : if (baseType) {
297 : uint32_t baseId = m.getBaseId();
298 :
299 0 : if (m.isRegHome()) {
300 : // Home address of virtual register. In such case we don't want to
301 : // validate the type of the base register as it will always be patched
302 : // to ESP|RSP.
303 : }
304 : else {
305 0 : if (ASMJIT_UNLIKELY((vd->allowedMemBaseRegs & (1U << baseType)) == 0))
306 : return DebugUtils::errored(kErrorInvalidAddress);
307 : }
308 :
309 : // Create information that will be validated only if this is an implicit
310 : // memory operand. Basically only usable for string instructions and other
311 : // instructions where memory operand is implicit and has 'seg:[reg]' form.
312 0 : if (baseId < Operand::kPackedIdMin) {
313 : // Physical base id.
314 : regMask = Utils::mask(baseId);
315 0 : combinedRegMask |= regMask;
316 : }
317 : else {
318 : // Virtual base id - will the whole mask for implicit mem validation.
319 : // The register is not assigned yet, so we cannot predict the phys id.
320 : regMask = 0xFFFFFFFFU;
321 : }
322 :
323 0 : if (!indexType && !m.getOffsetLo32())
324 : memFlags |= X86Inst::kMemOpBaseOnly;
325 : }
326 : else {
327 : // Base is an address, make sure that the address doesn't overflow 32-bit
328 : // integer (either int32_t or uint32_t) in 32-bit targets.
329 : int64_t offset = m.getOffset();
330 0 : if (archMask == X86Inst::kArchMaskX86 && !Utils::isInt32(offset) && !Utils::isUInt32(offset))
331 : return DebugUtils::errored(kErrorInvalidAddress);
332 : }
333 :
334 0 : if (indexType) {
335 0 : if (ASMJIT_UNLIKELY((vd->allowedMemIndexRegs & (1U << indexType)) == 0))
336 : return DebugUtils::errored(kErrorInvalidAddress);
337 :
338 0 : if (indexType == X86Reg::kRegXmm) {
339 : opFlags |= X86Inst::kOpVm;
340 0 : memFlags |= X86Inst::kMemOpVm32x | X86Inst::kMemOpVm64x;
341 : }
342 0 : else if (indexType == X86Reg::kRegYmm) {
343 : opFlags |= X86Inst::kOpVm;
344 0 : memFlags |= X86Inst::kMemOpVm32y | X86Inst::kMemOpVm64y;
345 : }
346 0 : else if (indexType == X86Reg::kRegZmm) {
347 : opFlags |= X86Inst::kOpVm;
348 0 : memFlags |= X86Inst::kMemOpVm32z | X86Inst::kMemOpVm64z;
349 : }
350 : else {
351 : opFlags |= X86Inst::kOpMem;
352 0 : if (baseType)
353 0 : memFlags |= X86Inst::kMemOpMib;
354 : }
355 :
356 : // [RIP + {XMM|YMM|ZMM}] is not allowed.
357 0 : if (baseType == X86Reg::kRegRip && (opFlags & X86Inst::kOpVm))
358 : return DebugUtils::errored(kErrorInvalidAddress);
359 :
360 : uint32_t indexId = m.getIndexId();
361 0 : if (indexId < Operand::kPackedIdMin)
362 0 : combinedRegMask |= Utils::mask(indexId);
363 :
364 : // Only used for implicit memory operands having 'seg:[reg]' form, so clear it.
365 : regMask = 0;
366 : }
367 : else {
368 : opFlags |= X86Inst::kOpMem;
369 : }
370 :
371 : switch (m.getSize()) {
372 0 : case 0: memFlags |= X86Inst::kMemOpAny ; break;
373 0 : case 1: memFlags |= X86Inst::kMemOpM8 ; break;
374 0 : case 2: memFlags |= X86Inst::kMemOpM16 ; break;
375 0 : case 4: memFlags |= X86Inst::kMemOpM32 ; break;
376 0 : case 6: memFlags |= X86Inst::kMemOpM48 ; break;
377 0 : case 8: memFlags |= X86Inst::kMemOpM64 ; break;
378 0 : case 10: memFlags |= X86Inst::kMemOpM80 ; break;
379 0 : case 16: memFlags |= X86Inst::kMemOpM128; break;
380 0 : case 32: memFlags |= X86Inst::kMemOpM256; break;
381 0 : case 64: memFlags |= X86Inst::kMemOpM512; break;
382 : default:
383 : return DebugUtils::errored(kErrorInvalidOperandSize);
384 : }
385 :
386 : break;
387 : }
388 :
389 : case Operand::kOpImm: {
390 : uint64_t immValue = op.as<Imm>().getUInt64();
391 : uint32_t immFlags = 0;
392 :
393 0 : if (static_cast<int64_t>(immValue) >= 0) {
394 : const uint32_t k32AndMore = X86Inst::kOpI32 | X86Inst::kOpU32 |
395 : X86Inst::kOpI64 | X86Inst::kOpU64 ;
396 :
397 0 : if (immValue <= 0xFU)
398 : immFlags = X86Inst::kOpU4 | X86Inst::kOpI8 | X86Inst::kOpU8 | X86Inst::kOpI16 | X86Inst::kOpU16 | k32AndMore;
399 0 : else if (immValue <= 0x7FU)
400 : immFlags = X86Inst::kOpI8 | X86Inst::kOpU8 | X86Inst::kOpI16 | X86Inst::kOpU16 | k32AndMore;
401 0 : else if (immValue <= 0xFFU)
402 : immFlags = X86Inst::kOpU8 | X86Inst::kOpI16 | X86Inst::kOpU16 | k32AndMore;
403 0 : else if (immValue <= 0x7FFFU)
404 : immFlags = X86Inst::kOpI16 | X86Inst::kOpU16 | k32AndMore;
405 0 : else if (immValue <= 0xFFFFU)
406 : immFlags = X86Inst::kOpU16 | k32AndMore;
407 0 : else if (immValue <= 0x7FFFFFFFU)
408 : immFlags = k32AndMore;
409 0 : else if (immValue <= 0xFFFFFFFFU)
410 : immFlags = X86Inst::kOpU32 | X86Inst::kOpI64 | X86Inst::kOpU64;
411 : else if (immValue <= ASMJIT_UINT64_C(0x7FFFFFFFFFFFFFFF))
412 : immFlags = X86Inst::kOpI64 | X86Inst::kOpU64;
413 : else
414 : immFlags = X86Inst::kOpU64;
415 : }
416 : else {
417 : // 2s complement negation, as our number is unsigned...
418 0 : immValue = (~immValue + 1);
419 :
420 0 : if (immValue <= 0x80U)
421 : immFlags = X86Inst::kOpI8 | X86Inst::kOpI16 | X86Inst::kOpI32 | X86Inst::kOpI64;
422 0 : else if (immValue <= 0x8000U)
423 : immFlags = X86Inst::kOpI16 | X86Inst::kOpI32 | X86Inst::kOpI64;
424 0 : else if (immValue <= 0x80000000U)
425 : immFlags = X86Inst::kOpI32 | X86Inst::kOpI64;
426 : else
427 : immFlags = X86Inst::kOpI64;
428 : }
429 : opFlags |= immFlags;
430 : break;
431 : }
432 :
433 : case Operand::kOpLabel: {
434 : opFlags |= X86Inst::kOpRel8 | X86Inst::kOpRel32;
435 : break;
436 : }
437 :
438 : default:
439 : return DebugUtils::errored(kErrorInvalidState);
440 : }
441 :
442 : X86Inst::OSignature& tod = oSigTranslated[i];
443 0 : tod.flags = opFlags;
444 0 : tod.memFlags = static_cast<uint16_t>(memFlags);
445 0 : tod.regMask = static_cast<uint8_t>(regMask & 0xFFU);
446 0 : combinedOpFlags |= opFlags;
447 : }
448 :
449 : // Decrease the number of operands of those that are none. This is important
450 : // as Assembler and CodeCompiler may just pass more operands where some of
451 : // them are none (it means that no operand is given at that index). However,
452 : // validate that there are no gaps (like [reg, none, reg] or [none, reg]).
453 0 : if (i < count) {
454 0 : while (--count > i)
455 0 : if (ASMJIT_UNLIKELY(!operands[count].isNone()))
456 : return DebugUtils::errored(kErrorInvalidState);
457 : }
458 :
459 : // Validate X86 and X64 specific cases.
460 0 : if (archMask == X86Inst::kArchMaskX86) {
461 : // Illegal use of 64-bit register in 32-bit mode.
462 0 : if (ASMJIT_UNLIKELY((combinedOpFlags & X86Inst::kOpGpq) != 0))
463 : return DebugUtils::errored(kErrorInvalidUseOfGpq);
464 : }
465 : else {
466 : // Illegal use of a high 8-bit register with REX prefix.
467 0 : if (ASMJIT_UNLIKELY((combinedOpFlags & X86Inst::kOpGpbHi) != 0 && (combinedRegMask & 0xFFFFFF00U) != 0))
468 : return DebugUtils::errored(kErrorInvalidUseOfGpbHi);
469 : }
470 :
471 : // Validate instruction operands.
472 : const X86Inst::CommonData* commonData = &iData->getCommonData();
473 0 : const X86Inst::ISignature* iSig = X86InstDB::iSignatureData + commonData->_iSignatureIndex;
474 0 : const X86Inst::ISignature* iEnd = iSig + commonData->_iSignatureCount;
475 :
476 0 : if (iSig != iEnd) {
477 : const X86Inst::OSignature* oSigData = X86InstDB::oSignatureData;
478 :
479 : // If set it means that we matched a signature where only immediate value
480 : // was out of bounds. We can return a more descriptive error if we know this.
481 : bool globalImmOutOfRange = false;
482 :
483 : do {
484 : // Check if the architecture is compatible.
485 0 : if ((iSig->archMask & archMask) == 0) continue;
486 :
487 : // Compare the operands table with reference operands.
488 : uint32_t j = 0;
489 0 : uint32_t iSigCount = iSig->opCount;
490 : bool localImmOutOfRange = false;
491 :
492 0 : if (iSigCount == count) {
493 0 : for (j = 0; j < count; j++)
494 0 : if (!x86CheckOSig(oSigTranslated[j], oSigData[iSig->operands[j]], localImmOutOfRange))
495 : break;
496 : }
497 0 : else if (iSigCount - iSig->implicit == count) {
498 : uint32_t r = 0;
499 0 : for (j = 0; j < count && r < iSigCount; j++, r++) {
500 0 : const X86Inst::OSignature* oChk = oSigTranslated + j;
501 : const X86Inst::OSignature* oRef;
502 0 : Next:
503 0 : oRef = oSigData + iSig->operands[r];
504 : // Skip implicit.
505 0 : if ((oRef->flags & X86Inst::kOpImplicit) != 0) {
506 0 : if (++r >= iSigCount)
507 : break;
508 : else
509 0 : goto Next;
510 : }
511 :
512 0 : if (!x86CheckOSig(*oChk, *oRef, localImmOutOfRange))
513 : break;
514 : }
515 : }
516 :
517 0 : if (j == count) {
518 0 : if (!localImmOutOfRange) {
519 : // Match, must clear possible `globalImmOutOfRange`.
520 : globalImmOutOfRange = false;
521 : break;
522 : }
523 : globalImmOutOfRange = localImmOutOfRange;
524 : }
525 0 : } while (++iSig != iEnd);
526 :
527 0 : if (iSig == iEnd) {
528 0 : if (globalImmOutOfRange)
529 : return DebugUtils::errored(kErrorInvalidImmediate);
530 : else
531 0 : return DebugUtils::errored(kErrorInvalidInstruction);
532 : }
533 : }
534 :
535 : // Validate AVX-512 options:
536 : const RegOnly& extraReg = detail.extraReg;
537 : const uint32_t kAvx512Options = X86Inst::kOptionZMask |
538 : X86Inst::kOption1ToX |
539 : X86Inst::kOptionER |
540 : X86Inst::kOptionSAE ;
541 :
542 0 : if (!extraReg.isNone() || (options & kAvx512Options)) {
543 0 : if (commonData->hasFlag(X86Inst::kFlagEvex)) {
544 : // Validate AVX-512 {k} and {k}{z}.
545 0 : if (!extraReg.isNone()) {
546 : // Mask can only be specified by a 'k' register.
547 0 : if (ASMJIT_UNLIKELY(extraReg.getType() != X86Reg::kRegK))
548 : return DebugUtils::errored(kErrorInvalidKMaskReg);
549 :
550 0 : if (ASMJIT_UNLIKELY(!commonData->hasAvx512K()))
551 : return DebugUtils::errored(kErrorInvalidKMaskUse);
552 : }
553 :
554 0 : if ((options & X86Inst::kOptionZMask)) {
555 0 : if (ASMJIT_UNLIKELY((options & X86Inst::kOptionZMask) != 0 && !commonData->hasAvx512Z()))
556 : return DebugUtils::errored(kErrorInvalidKZeroUse);
557 : }
558 :
559 : // Validate AVX-512 broadcast {1tox}.
560 0 : if (options & X86Inst::kOption1ToX) {
561 0 : if (ASMJIT_UNLIKELY(!memOp))
562 : return DebugUtils::errored(kErrorInvalidBroadcast);
563 :
564 : uint32_t size = memOp->getSize();
565 0 : if (size != 0) {
566 : // The the size is specified it has to match the broadcast size.
567 0 : if (ASMJIT_UNLIKELY(commonData->hasAvx512B32() && size != 4))
568 : return DebugUtils::errored(kErrorInvalidBroadcast);
569 :
570 0 : if (ASMJIT_UNLIKELY(commonData->hasAvx512B64() && size != 8))
571 : return DebugUtils::errored(kErrorInvalidBroadcast);
572 : }
573 : }
574 :
575 : // Validate AVX-512 {sae} and {er}.
576 0 : if (options & (X86Inst::kOptionSAE | X86Inst::kOptionER)) {
577 : // Rounding control is impossible if the instruction is not reg-to-reg.
578 0 : if (ASMJIT_UNLIKELY(memOp))
579 : return DebugUtils::errored(kErrorInvalidEROrSAE);
580 :
581 : // Check if {sae} or {er} is supported by the instruction.
582 0 : if (options & X86Inst::kOptionER) {
583 : // NOTE: if both {sae} and {er} are set, we don't care, as {sae} is implied.
584 0 : if (ASMJIT_UNLIKELY(!commonData->hasAvx512ER()))
585 : return DebugUtils::errored(kErrorInvalidEROrSAE);
586 :
587 : // {er} is defined for scalar ops or vector ops using zmm (LL = 10). We
588 : // don't need any more bits in the instruction database to be able to
589 : // validate this, as each AVX512 instruction that has broadcast is vector
590 : // instruction (in this case we require zmm registers), otherwise it's a
591 : // scalar instruction, which is valid.
592 0 : if (commonData->hasAvx512B()) {
593 : // Supports broadcast, thus we require LL to be '10', which means there
594 : // have to be zmm registers used. We don't calculate LL here, but we know
595 : // that it would be '10' if there is at least one ZMM register used.
596 :
597 : // There is no 'ER' enabled instruction with less than two operands.
598 : ASMJIT_ASSERT(count >= 2);
599 0 : if (ASMJIT_UNLIKELY(!X86Reg::isZmm(operands[0]) && !X86Reg::isZmm(operands[1])))
600 : return DebugUtils::errored(kErrorInvalidEROrSAE);
601 : }
602 : }
603 : else {
604 : // {sae} doesn't have the same limitations as {er}, this is enough.
605 0 : if (ASMJIT_UNLIKELY(!commonData->hasAvx512SAE()))
606 : return DebugUtils::errored(kErrorInvalidEROrSAE);
607 : }
608 : }
609 : }
610 : else {
611 : // Not AVX512 instruction - maybe OpExtra is xCX register used by REP/REPNZ prefix. Otherwise the instruction is invalid.
612 0 : if ((options & kAvx512Options) || (options & (X86Inst::kOptionRep | X86Inst::kOptionRepnz)) == 0)
613 : return DebugUtils::errored(kErrorInvalidInstruction);
614 : }
615 : }
616 :
617 : return kErrorOk;
618 : }
619 : #endif
620 :
621 : // ============================================================================
622 : // [asmjit::X86InstImpl - CheckFeatures]
623 : // ============================================================================
624 :
625 : #if !defined(ASMJIT_DISABLE_EXTENSIONS)
626 0 : ASMJIT_FAVOR_SIZE static uint32_t x86GetRegTypesMask(const Operand_* operands, uint32_t count) noexcept {
627 : uint32_t mask = 0;
628 0 : for (uint32_t i = 0; i < count; i++) {
629 0 : const Operand_& op = operands[i];
630 0 : if (op.isReg()) {
631 : const Reg& reg = op.as<Reg>();
632 0 : mask |= Utils::mask(reg.getType());
633 : }
634 0 : else if (op.isMem()) {
635 : const Mem& mem = op.as<Mem>();
636 0 : if (mem.hasBaseReg()) mask |= Utils::mask(mem.getBaseType());
637 0 : if (mem.hasIndexReg()) mask |= Utils::mask(mem.getIndexType());
638 : }
639 : }
640 0 : return mask;
641 : }
642 :
643 0 : ASMJIT_FAVOR_SIZE Error X86InstImpl::checkFeatures(uint32_t archType, const Inst::Detail& detail, const Operand_* operands, uint32_t count, CpuFeatures& out) noexcept {
644 0 : if (!ArchInfo::isX86Family(archType))
645 : return DebugUtils::errored(kErrorInvalidArch);
646 :
647 : // Get the instruction data.
648 0 : uint32_t instId = detail.instId;
649 0 : if (ASMJIT_UNLIKELY(instId >= X86Inst::_kIdCount))
650 : return DebugUtils::errored(kErrorInvalidArgument);
651 :
652 : const X86Inst* iData = &X86InstDB::instData[instId];
653 : const X86Inst::OperationData& od = iData->getOperationData();
654 :
655 : const uint8_t* fData = od.getFeaturesData();
656 : const uint8_t* fEnd = od.getFeaturesEnd();
657 :
658 : // Copy all features to `out`.
659 : out.reset();
660 : do {
661 0 : uint32_t feature = fData[0];
662 0 : if (!feature)
663 : break;
664 : out.add(feature);
665 0 : } while (++fData != fEnd);
666 :
667 : // Since AsmJit merges all instructions that share the same name we have to
668 : // deal with some special cases and also with MMX/SSE and AVX/AVX2 overlaps.
669 :
670 : // Only proceed if there were some CPU flags set.
671 0 : if (fData != od.getFeaturesData()) {
672 0 : uint32_t mask = x86GetRegTypesMask(operands, count);
673 :
674 : // Check for MMX vs SSE overlap.
675 0 : if (out.has(CpuInfo::kX86FeatureMMX) || out.has(CpuInfo::kX86FeatureMMX2)) {
676 : // Only instructions defined by SSE and SSE2 overlap. Instructions introduced
677 : // by newer instruction sets like SSE3+ don't state MMX as they require SSE3+.
678 0 : if (out.has(CpuInfo::kX86FeatureSSE) || out.has(CpuInfo::kX86FeatureSSE2)) {
679 0 : if (!(mask & Utils::mask(X86Reg::kRegXmm))) {
680 : // The instruction doesn't use XMM register(s), thus it's MMX/MMX2 only.
681 : out.remove(CpuInfo::kX86FeatureSSE);
682 : out.remove(CpuInfo::kX86FeatureSSE2);
683 : }
684 : else {
685 : out.remove(CpuInfo::kX86FeatureMMX);
686 : out.remove(CpuInfo::kX86FeatureMMX2);
687 : }
688 :
689 : // Special case: PEXTRW instruction is MMX/SSE2 instruction. However, this
690 : // instruction couldn't access memory (only register to register extract) so
691 : // when SSE4.1 introduced the whole family of PEXTR/PINSR instructions they
692 : // also introduced PEXTRW with a new opcode 0x15 that can extract directly to
693 : // memory. This instruction is, of course, not compatible with MMX/SSE2 one.
694 0 : if (instId == X86Inst::kIdPextrw && count > 0 && !operands[0].isMem()) {
695 : out.remove(CpuInfo::kX86FeatureSSE4_1);
696 : }
697 : }
698 : }
699 :
700 : // Check for AVX vs AVX2 overlap.
701 0 : if (out.has(CpuInfo::kX86FeatureAVX) && out.has(CpuInfo::kX86FeatureAVX2)) {
702 : bool isAVX2 = true;
703 : // Special case: VBROADCASTSS and VBROADCASTSD were introduced in AVX, but
704 : // only version that uses memory as a source operand. AVX2 then added support
705 : // for register source operand.
706 0 : if (instId == X86Inst::kIdVbroadcastss || instId == X86Inst::kIdVbroadcastsd) {
707 0 : if (count > 1 && operands[0].isMem())
708 : isAVX2 = false;
709 : }
710 : else {
711 : // AVX instruction set doesn't support integer operations on YMM registers
712 : // as these were later introcuced by AVX2. In our case we have to check if
713 : // YMM register(s) are in use and if that is the case this is an AVX2 instruction.
714 0 : if (!(mask & Utils::mask(X86Reg::kRegYmm, X86Reg::kRegZmm)))
715 : isAVX2 = false;
716 : }
717 :
718 : if (isAVX2)
719 : out.remove(CpuInfo::kX86FeatureAVX);
720 : else
721 : out.remove(CpuInfo::kX86FeatureAVX2);
722 : }
723 :
724 : // Check for AVX|AVX2|FMA|F16C vs AVX512 overlap.
725 0 : if (out.has(CpuInfo::kX86FeatureAVX) || out.has(CpuInfo::kX86FeatureAVX2) || out.has(CpuInfo::kX86FeatureFMA) || out.has(CpuInfo::kX86FeatureF16C)) {
726 : // Only AVX512-F|BW|DQ allow to encode AVX/AVX2 instructions
727 0 : if (out.has(CpuInfo::kX86FeatureAVX512_F) || out.has(CpuInfo::kX86FeatureAVX512_BW) || out.has(CpuInfo::kX86FeatureAVX512_DQ)) {
728 0 : uint32_t options = detail.options;
729 : uint32_t kAvx512Options = X86Inst::kOptionEvex | X86Inst::_kOptionAvx512Mask;
730 :
731 0 : if (!(mask & Utils::mask(X86Reg::kRegZmm, X86Reg::kRegK)) && !(options & (kAvx512Options)) && detail.extraReg.getType() != X86Reg::kRegK) {
732 : out.remove(CpuInfo::kX86FeatureAVX512_F)
733 : .remove(CpuInfo::kX86FeatureAVX512_BW)
734 : .remove(CpuInfo::kX86FeatureAVX512_DQ)
735 : .remove(CpuInfo::kX86FeatureAVX512_VL);
736 : }
737 : }
738 : }
739 :
740 : // Remove or keep AVX512_VL feature.
741 0 : if (out.has(CpuInfo::kX86FeatureAVX512_VL)) {
742 0 : if (!(mask & Utils::mask(X86Reg::kRegZmm)))
743 : out.remove(CpuInfo::kX86FeatureAVX512_VL);
744 : }
745 : }
746 :
747 : return kErrorOk;
748 : }
749 : #endif
750 :
751 : } // asmjit namespace
752 : } // namespace PLMD
753 :
754 : // [Api-End]
755 : #include "./asmjit_apiend.h"
756 : #pragma GCC diagnostic pop
757 : #endif // __PLUMED_HAS_ASMJIT
|