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