1 // [AsmJit]
2 // Machine Code Generation for C++.
3 //
4 // [License]
5 // Zlib - See LICENSE.md file in the package.
6 
7 #ifndef _ASMJIT_CORE_INST_H
8 #define _ASMJIT_CORE_INST_H
9 
10 #include "../core/cpuinfo.h"
11 #include "../core/operand.h"
12 #include "../core/string.h"
13 #include "../core/support.h"
14 
15 ASMJIT_BEGIN_NAMESPACE
16 
17 //! \addtogroup asmjit_core
18 //! \{
19 
20 // ============================================================================
21 // [asmjit::InstInfo]
22 // ============================================================================
23 
24 // TODO: Finalize instruction info and make more x86::InstDB methods/structs private.
25 
26 /*
27 
28 struct InstInfo {
29   //! Architecture agnostic attributes.
30   enum Attributes : uint32_t {
31 
32 
33   };
34 
35   //! Instruction attributes.
36   uint32_t _attributes;
37 
38   inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
39 
40   inline uint32_t attributes() const noexcept { return _attributes; }
41   inline bool hasAttribute(uint32_t attr) const noexcept { return (_attributes & attr) != 0; }
42 };
43 
44 //! Gets attributes of the given instruction.
45 ASMJIT_API Error queryCommonInfo(uint32_t archId, uint32_t instId, InstInfo& out) noexcept;
46 
47 */
48 
49 // ============================================================================
50 // [asmjit::InstRWInfo / OpRWInfo]
51 // ============================================================================
52 
53 //! Read/Write information related to a single operand, used by `InstRWInfo`.
54 struct OpRWInfo {
55   //! Read/Write flags, see `OpRWInfo::Flags`.
56   uint32_t _opFlags;
57   //! Physical register index, if required.
58   uint8_t _physId;
59   //! Size of a possible memory operand that can replace a register operand.
60   uint8_t _rmSize;
61   //! Reserved for future use.
62   uint8_t _reserved[2];
63   //! Read bit-mask where each bit represents one byte read from Reg/Mem.
64   uint64_t _readByteMask;
65   //! Write bit-mask where each bit represents one byte written to Reg/Mem.
66   uint64_t _writeByteMask;
67   //! Zero/Sign extend bit-mask where each bit represents one byte written to Reg/Mem.
68   uint64_t _extendByteMask;
69 
70   //! Flags describe how the operand is accessed and some additional information.
71   enum Flags : uint32_t {
72     //! Operand is read.
73     //!
74     //! \note This flag must be `0x00000001`.
75     kRead = 0x00000001u,
76 
77     //! Operand is written.
78     //!
79     //! \note This flag must be `0x00000002`.
80     kWrite = 0x00000002u,
81 
82     //! Operand is both read and written.
83     //!
84     //! \note This combination of flags must be `0x00000003`.
85     kRW = 0x00000003u,
86 
87     //! Register operand can be replaced by a memory operand.
88     kRegMem = 0x00000004u,
89 
90     //! The `extendByteMask()` represents a zero extension.
91     kZExt = 0x00000010u,
92 
93     //! Register operand must use `physId()`.
94     kRegPhysId = 0x00000100u,
95     //! Base register of a memory operand must use `physId()`.
96     kMemPhysId = 0x00000200u,
97 
98     //! This memory operand is only used to encode registers and doesn't access memory.
99     //!
100     //! X86 Specific
101     //! ------------
102     //!
103     //! Instructions that use such feature include BNDLDX, BNDSTX, and LEA.
104     kMemFake = 0x000000400u,
105 
106     //! Base register of the memory operand will be read.
107     kMemBaseRead = 0x00001000u,
108     //! Base register of the memory operand will be written.
109     kMemBaseWrite = 0x00002000u,
110     //! Base register of the memory operand will be read & written.
111     kMemBaseRW = 0x00003000u,
112 
113     //! Index register of the memory operand will be read.
114     kMemIndexRead = 0x00004000u,
115     //! Index register of the memory operand will be written.
116     kMemIndexWrite = 0x00008000u,
117     //! Index register of the memory operand will be read & written.
118     kMemIndexRW = 0x0000C000u,
119 
120     //! Base register of the memory operand will be modified before the operation.
121     kMemBasePreModify = 0x00010000u,
122     //! Base register of the memory operand will be modified after the operation.
123     kMemBasePostModify = 0x00020000u
124   };
125 
126   static_assert(kRead  == 0x1, "OpRWInfo::kRead flag must be 0x1");
127   static_assert(kWrite == 0x2, "OpRWInfo::kWrite flag must be 0x2");
128   static_assert(kRegMem == 0x4, "OpRWInfo::kRegMem flag must be 0x4");
129 
130   //! \name Reset
131   //! \{
132 
resetOpRWInfo133   inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
134   inline void reset(uint32_t opFlags, uint32_t regSize, uint32_t physId = BaseReg::kIdBad) noexcept {
135     _opFlags = opFlags;
136     _physId = uint8_t(physId);
137     _rmSize = uint8_t((opFlags & kRegMem) ? regSize : uint32_t(0));
138     _resetReserved();
139 
140     uint64_t mask = Support::lsbMask<uint64_t>(regSize);
141     _readByteMask = opFlags & kRead ? mask : uint64_t(0);
142     _writeByteMask = opFlags & kWrite ? mask : uint64_t(0);
143     _extendByteMask = 0;
144   }
145 
_resetReservedOpRWInfo146   inline void _resetReserved() noexcept {
147     memset(_reserved, 0, sizeof(_reserved));
148   }
149 
150   //! \}
151 
152   //! \name Operand Flags
153   //! \{
154 
opFlagsOpRWInfo155   inline uint32_t opFlags() const noexcept { return _opFlags; }
hasOpFlagOpRWInfo156   inline bool hasOpFlag(uint32_t flag) const noexcept { return (_opFlags & flag) != 0; }
157 
addOpFlagsOpRWInfo158   inline void addOpFlags(uint32_t flags) noexcept { _opFlags |= flags; }
clearOpFlagsOpRWInfo159   inline void clearOpFlags(uint32_t flags) noexcept { _opFlags &= ~flags; }
160 
isReadOpRWInfo161   inline bool isRead() const noexcept { return hasOpFlag(kRead); }
isWriteOpRWInfo162   inline bool isWrite() const noexcept { return hasOpFlag(kWrite); }
isReadWriteOpRWInfo163   inline bool isReadWrite() const noexcept { return (_opFlags & kRW) == kRW; }
isReadOnlyOpRWInfo164   inline bool isReadOnly() const noexcept { return (_opFlags & kRW) == kRead; }
isWriteOnlyOpRWInfo165   inline bool isWriteOnly() const noexcept { return (_opFlags & kRW) == kWrite; }
isRmOpRWInfo166   inline bool isRm() const noexcept { return hasOpFlag(kRegMem); }
isZExtOpRWInfo167   inline bool isZExt() const noexcept { return hasOpFlag(kZExt); }
168 
169   //! \}
170 
171   //! \name Physical Register ID
172   //! \{
173 
physIdOpRWInfo174   inline uint32_t physId() const noexcept { return _physId; }
hasPhysIdOpRWInfo175   inline bool hasPhysId() const noexcept { return _physId != BaseReg::kIdBad; }
setPhysIdOpRWInfo176   inline void setPhysId(uint32_t physId) noexcept { _physId = uint8_t(physId); }
177 
178   //! \}
179 
180   //! \name Reg/Mem
181   //! \{
182 
rmSizeOpRWInfo183   inline uint32_t rmSize() const noexcept { return _rmSize; }
setRmSizeOpRWInfo184   inline void setRmSize(uint32_t rmSize) noexcept { _rmSize = uint8_t(rmSize); }
185 
186   //! \}
187 
188   //! \name Read & Write Masks
189   //! \{
190 
readByteMaskOpRWInfo191   inline uint64_t readByteMask() const noexcept { return _readByteMask; }
writeByteMaskOpRWInfo192   inline uint64_t writeByteMask() const noexcept { return _writeByteMask; }
extendByteMaskOpRWInfo193   inline uint64_t extendByteMask() const noexcept { return _extendByteMask; }
194 
setReadByteMaskOpRWInfo195   inline void setReadByteMask(uint64_t mask) noexcept { _readByteMask = mask; }
setWriteByteMaskOpRWInfo196   inline void setWriteByteMask(uint64_t mask) noexcept { _writeByteMask = mask; }
setExtendByteMaskOpRWInfo197   inline void setExtendByteMask(uint64_t mask) noexcept { _extendByteMask = mask; }
198 
199   //! \}
200 };
201 
202 //! Read/Write information of an instruction.
203 struct InstRWInfo {
204   //! Instruction flags.
205   uint32_t _instFlags;
206   //! Mask of flags read.
207   uint32_t _readFlags;
208   //! Mask of flags written.
209   uint32_t _writeFlags;
210   //! Count of operands.
211   uint8_t _opCount;
212   //! CPU feature required for replacing register operand with memory operand.
213   uint8_t _rmFeature;
214   //! Reserved for future use.
215   uint8_t _reserved[19];
216   //! Read/Write onfo of extra register (rep{} or kz{}).
217   OpRWInfo _extraReg;
218   //! Read/Write info of instruction operands.
219   OpRWInfo _operands[Globals::kMaxOpCount];
220 
resetInstRWInfo221   inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
222 
instFlagsInstRWInfo223   inline uint32_t instFlags() const noexcept { return _instFlags; }
hasInstFlagInstRWInfo224   inline bool hasInstFlag(uint32_t flag) const noexcept { return (_instFlags & flag) != 0; }
225 
opCountInstRWInfo226   inline uint32_t opCount() const noexcept { return _opCount; }
227 
readFlagsInstRWInfo228   inline uint32_t readFlags() const noexcept { return _readFlags; }
writeFlagsInstRWInfo229   inline uint32_t writeFlags() const noexcept { return _writeFlags; }
230 
231   //! Returns the CPU feature required to replace a register operand with memory
232   //! operand. If the returned feature is zero (none) then this instruction
233   //! either doesn't provide memory operand combination or there is no extra
234   //! CPU feature required.
235   //!
236   //! X86 Specific
237   //! ------------
238   //!
239   //! Some AVX+ instructions may require extra features for replacing registers
240   //! with memory operands, for example VPSLLDQ instruction only supports
241   //! 'reg/reg/imm' combination on AVX/AVX2 capable CPUs and requires AVX-512 for
242   //! 'reg/mem/imm' combination.
rmFeatureInstRWInfo243   inline uint32_t rmFeature() const noexcept { return _rmFeature; }
244 
extraRegInstRWInfo245   inline const OpRWInfo& extraReg() const noexcept { return _extraReg; }
operandsInstRWInfo246   inline const OpRWInfo* operands() const noexcept { return _operands; }
247 
operandInstRWInfo248   inline const OpRWInfo& operand(size_t index) const noexcept {
249     ASMJIT_ASSERT(index < Globals::kMaxOpCount);
250     return _operands[index];
251   }
252 };
253 
254 // ============================================================================
255 // [asmjit::BaseInst]
256 // ============================================================================
257 
258 //! Instruction id, options, and extraReg in a single structure. This structure
259 //! exists mainly to simplify analysis and validation API that requires `BaseInst`
260 //! and `Operand[]` array.
261 class BaseInst {
262 public:
263   //! Instruction id.
264   uint32_t _id;
265   //! Instruction options.
266   uint32_t _options;
267   //! Extra register used by instruction (either REP register or AVX-512 selector).
268   RegOnly _extraReg;
269 
270   enum Id : uint32_t {
271     //! Invalid or uninitialized instruction id.
272     kIdNone               = 0x00000000u,
273     //! Abstract instruction (BaseBuilder and BaseCompiler).
274     kIdAbstract           = 0x80000000u
275   };
276 
277   enum Options : uint32_t {
278     //! Used internally by emitters for handling errors and rare cases.
279     kOptionReserved       = 0x00000001u,
280 
281     //! Used only by Assembler to mark that `_op4` and `_op5` are used (internal).
282     kOptionOp4Op5Used     = 0x00000002u,
283 
284     //! Prevents following a jump during compilation (BaseCompiler).
285     kOptionUnfollow       = 0x00000010u,
286 
287     //! Overwrite the destination operand(s) (BaseCompiler).
288     //!
289     //! Hint that is important for register liveness analysis. It tells the
290     //! compiler that the destination operand will be overwritten now or by
291     //! adjacent instructions. BaseCompiler knows when a register is completely
292     //! overwritten by a single instruction, for example you don't have to
293     //! mark "movaps" or "pxor x, x", however, if a pair of instructions is
294     //! used and the first of them doesn't completely overwrite the content
295     //! of the destination, BaseCompiler fails to mark that register as dead.
296     //!
297     //! X86 Specific
298     //! ------------
299     //!
300     //!   - All instructions that always overwrite at least the size of the
301     //!     register the virtual-register uses , for example "mov", "movq",
302     //!     "movaps" don't need the overwrite option to be used - conversion,
303     //!     shuffle, and other miscellaneous instructions included.
304     //!
305     //!   - All instructions that clear the destination register if all operands
306     //!     are the same, for example "xor x, x", "pcmpeqb x x", etc...
307     //!
308     //!   - Consecutive instructions that partially overwrite the variable until
309     //!     there is no old content require `BaseCompiler::overwrite()` to be used.
310     //!     Some examples (not always the best use cases thought):
311     //!
312     //!     - `movlps xmm0, ?` followed by `movhps xmm0, ?` and vice versa
313     //!     - `movlpd xmm0, ?` followed by `movhpd xmm0, ?` and vice versa
314     //!     - `mov al, ?` followed by `and ax, 0xFF`
315     //!     - `mov al, ?` followed by `mov ah, al`
316     //!     - `pinsrq xmm0, ?, 0` followed by `pinsrq xmm0, ?, 1`
317     //!
318     //!   - If allocated variable is used temporarily for scalar operations. For
319     //!     example if you allocate a full vector like `x86::Compiler::newXmm()`
320     //!     and then use that vector for scalar operations you should use
321     //!     `overwrite()` directive:
322     //!
323     //!     - `sqrtss x, y` - only LO element of `x` is changed, if you don't
324     //!       use HI elements, use `compiler.overwrite().sqrtss(x, y)`.
325     kOptionOverwrite      = 0x00000020u,
326 
327     //! Emit short-form of the instruction.
328     kOptionShortForm      = 0x00000040u,
329     //! Emit long-form of the instruction.
330     kOptionLongForm       = 0x00000080u,
331 
332     //! Conditional jump is likely to be taken.
333     kOptionTaken          = 0x00000100u,
334     //! Conditional jump is unlikely to be taken.
335     kOptionNotTaken       = 0x00000200u
336   };
337 
338   //! Control type.
339   enum ControlType : uint32_t {
340     //! No control type (doesn't jump).
341     kControlNone = 0u,
342     //! Unconditional jump.
343     kControlJump = 1u,
344     //! Conditional jump (branch).
345     kControlBranch = 2u,
346     //! Function call.
347     kControlCall = 3u,
348     //! Function return.
349     kControlReturn = 4u
350   };
351 
352   //! \name Construction & Destruction
353   //! \{
354 
355   inline explicit BaseInst(uint32_t id = 0, uint32_t options = 0) noexcept
_id(id)356     : _id(id),
357       _options(options),
358       _extraReg() {}
359 
BaseInst(uint32_t id,uint32_t options,const RegOnly & extraReg)360   inline BaseInst(uint32_t id, uint32_t options, const RegOnly& extraReg) noexcept
361     : _id(id),
362       _options(options),
363       _extraReg(extraReg) {}
364 
BaseInst(uint32_t id,uint32_t options,const BaseReg & extraReg)365   inline BaseInst(uint32_t id, uint32_t options, const BaseReg& extraReg) noexcept
366     : _id(id),
367       _options(options),
368       _extraReg { extraReg.signature(), extraReg.id() } {}
369 
370   //! \}
371 
372   //! \name Instruction ID
373   //! \{
374 
id()375   inline uint32_t id() const noexcept { return _id; }
setId(uint32_t id)376   inline void setId(uint32_t id) noexcept { _id = id; }
resetId()377   inline void resetId() noexcept { _id = 0; }
378 
379   //! \}
380 
381   //! \name Instruction Options
382   //! \{
383 
options()384   inline uint32_t options() const noexcept { return _options; }
setOptions(uint32_t options)385   inline void setOptions(uint32_t options) noexcept { _options = options; }
addOptions(uint32_t options)386   inline void addOptions(uint32_t options) noexcept { _options |= options; }
clearOptions(uint32_t options)387   inline void clearOptions(uint32_t options) noexcept { _options &= ~options; }
resetOptions()388   inline void resetOptions() noexcept { _options = 0; }
389 
390   //! \}
391 
392   //! \name Extra Register
393   //! \{
394 
hasExtraReg()395   inline bool hasExtraReg() const noexcept { return _extraReg.isReg(); }
extraReg()396   inline RegOnly& extraReg() noexcept { return _extraReg; }
extraReg()397   inline const RegOnly& extraReg() const noexcept { return _extraReg; }
setExtraReg(const BaseReg & reg)398   inline void setExtraReg(const BaseReg& reg) noexcept { _extraReg.init(reg); }
setExtraReg(const RegOnly & reg)399   inline void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); }
resetExtraReg()400   inline void resetExtraReg() noexcept { _extraReg.reset(); }
401 
402   //! \}
403 };
404 
405 // ============================================================================
406 // [asmjit::InstAPI]
407 // ============================================================================
408 
409 //! Instruction API.
410 namespace InstAPI {
411 
412 #ifndef ASMJIT_NO_TEXT
413 //! Appends the name of the instruction specified by `instId` and `instOptions`
414 //! into the `output` string.
415 //!
416 //! \note Instruction options would only affect instruction prefix & suffix,
417 //! other options would be ignored. If `instOptions` is zero then only raw
418 //! instruction name (without any additional text) will be appended.
419 ASMJIT_API Error instIdToString(uint32_t archId, uint32_t instId, String& output) noexcept;
420 
421 //! Parses an instruction name in the given string `s`. Length is specified
422 //! by `len` argument, which can be `SIZE_MAX` if `s` is known to be null
423 //! terminated.
424 //!
425 //! The output is stored in `instId`.
426 ASMJIT_API uint32_t stringToInstId(uint32_t archId, const char* s, size_t len) noexcept;
427 #endif // !ASMJIT_NO_TEXT
428 
429 #ifndef ASMJIT_NO_VALIDATION
430 //! Validates the given instruction.
431 ASMJIT_API Error validate(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept;
432 #endif // !ASMJIT_NO_VALIDATION
433 
434 #ifndef ASMJIT_NO_INTROSPECTION
435 //! Gets Read/Write information of the given instruction.
436 ASMJIT_API Error queryRWInfo(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, InstRWInfo& out) noexcept;
437 
438 //! Gets CPU features required by the given instruction.
439 ASMJIT_API Error queryFeatures(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, BaseFeatures& out) noexcept;
440 #endif // !ASMJIT_NO_INTROSPECTION
441 
442 } // {InstAPI}
443 
444 //! \}
445 
446 ASMJIT_END_NAMESPACE
447 
448 #endif // _ASMJIT_CORE_INST_H
449