Fixed Issue #24

Added move information to instruction database that the Compiler can use to make the read/write information of each operand more precise.
This commit is contained in:
kobalicekp
2014-05-03 00:55:43 +02:00
parent ca1726b0e0
commit 98b4880141
3 changed files with 1133 additions and 1040 deletions

View File

@@ -2182,27 +2182,46 @@ _NextGroup:
uint32_t combinedFlags; uint32_t combinedFlags;
if (i == 0) { if (i == 0) {
// Default for the first operand. // Read/Write is usualy the combination of the first operand.
combinedFlags = inFlags | outFlags; combinedFlags = inFlags | outFlags;
// Comparison/Test instructions never modify the source operand. // Move instructions typically overwrite the first operand,
if (info->isTest()) { // but there are some exceptions based on the operands' size
combinedFlags = inFlags; // and type.
} if (info->isMove()) {
// Move instructions typically overwrite the first operand, but uint32_t movSize = info->getMoveSize();
// there are some exceptions based on the operands' size and type. uint32_t varSize = vd->getSize();
else if (info->isMove()) {
// Cvttsd2si/Cvttss2si. In 32-bit mode the whole destination is replaced. // Exception - If the source operand is a memory location
// In 64-bit mode we need to check whether the destination operand size // promote move size into 16 bytes.
// is 64-bits. if (info->isZeroIfMem() && opList[1].isMem())
if (code == kInstCvttsd2si || code == kInstCvttss2si) movSize = 16;
combinedFlags = vd->getSize() > 4 ? (op->isRegType(kRegTypeGpq) ? outFlags : inFlags | outFlags) : outFlags;
// Movss/Movsd. These instructions won't overwrite the whole register if move if (movSize >= varSize) {
// is between two registers. // If move size is greater than or equal to the size of
else if (code == kInstMovss || code == kInstMovsd) // the variable there is nothing to do, because the move
combinedFlags = opList[1].isMem() ? outFlags : inFlags | outFlags; // will overwrite the variable in all cases.
else
combinedFlags = outFlags; combinedFlags = outFlags;
}
else if (static_cast<const X86Var*>(op)->isGp()) {
uint32_t opSize = static_cast<const X86Var*>(op)->getSize();
// Move size is zero in case that it should be determined
// from the destination register.
if (movSize == 0)
movSize = opSize;
// Handle the case that a 32-bit operation in 64-bit mode
// always zeroes the rest of the destination register and
// the case that move size is actually greater than or
// equal to the size of the variable.
if (movSize >= 4 || movSize >= varSize)
combinedFlags = outFlags;
}
}
// Comparison/Test instructions don't modify any operand.
else if (info->isTest()) {
combinedFlags = inFlags;
} }
// Imul. // Imul.
else if (code == kInstImul && opCount == 3) { else if (code == kInstImul && opCount == 3) {
@@ -2210,10 +2229,13 @@ _NextGroup:
} }
} }
else { else {
// Default for secon/third operands. // Read-Only is usualy the combination of the second/third/fourth operands.
combinedFlags = inFlags; combinedFlags = inFlags;
// Xchg/Xadd/Imul/Idiv. // Idiv is a special instruction, never handled here.
ASMJIT_ASSERT(code != kInstIdiv);
// Xchg/Xadd/Imul.
if (info->isXchg() || (code == kInstImul && opCount == 3 && i == 1)) if (info->isXchg() || (code == kInstImul && opCount == 3 && i == 1))
combinedFlags = inFlags | outFlags; combinedFlags = inFlags | outFlags;
} }
@@ -2240,26 +2262,26 @@ _NextGroup:
// Default for the first operand. // Default for the first operand.
combinedFlags = inFlags | outFlags; combinedFlags = inFlags | outFlags;
// Comparison/Test instructions never modify the source operand. // Move to memory - setting the right flags is important
if (info->isTest()) { // as if it's just move to the register. It's just a bit
combinedFlags = inFlags; // simpler as there are no special cases.
} if (info->isMove()) {
// Move instructions typically overwrite the first operand, but uint32_t movSize = IntUtil::iMax<uint32_t>(info->getMoveSize(), m->getSize());
// there are some exceptions based on the operands' size and type. uint32_t varSize = vd->getSize();
else if (info->isMove()) {
// Movss. if (movSize >= varSize)
if (code == kInstMovss)
combinedFlags = vd->getSize() == 4 ? outFlags : inFlags | outFlags;
// Movsd.
else if (code == kInstMovsd)
combinedFlags = vd->getSize() == 8 ? outFlags : inFlags | outFlags;
else
combinedFlags = outFlags; combinedFlags = outFlags;
} }
// Comparison/Test instructions don't modify any operand.
else if (info->isTest()) {
combinedFlags = inFlags;
}
} }
else { else {
// Default for the second operand. // Default for the second operand.
combinedFlags = inFlags; combinedFlags = inFlags;
// Handle Xchg instruction (modifies both operands).
if (info->isXchg()) if (info->isXchg())
combinedFlags = inFlags | outFlags; combinedFlags = inFlags | outFlags;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1698,17 +1698,21 @@ ASMJIT_ENUM(kInstFlags) {
//! //!
//! Move instructions typically overwrite the first operand by the second //! Move instructions typically overwrite the first operand by the second
//! operand. The first operand can be the exact copy of the second operand //! operand. The first operand can be the exact copy of the second operand
//! or it can be any kind of conversion. Mov instructions are typically //! or it can be any kind of conversion or shuffling.
//! 'mov', 'movd', 'movq', 'movdq?', 'cmov??' like instructions, but we also //!
//! consider 'lea' (Load Effective Address), multimedia instructions like //! Mov instructions are 'mov', 'movd', 'movq', movdq', 'lea', multimedia
//! 'cvtdq2pd', shuffle instructions like 'pshufb' and SSE/SSE2 mathematic //! instructions like 'cvtdq2pd', shuffle instructions like 'pshufb' and
//! instructions like 'rcp??', 'round??' and 'rsqrt??'. //! SSE/SSE2 mathematic instructions like 'rcp?', 'round?' and 'rsqrt?'.
//!
//! There are some MOV instructions that do only a partial move (for example
//! 'cvtsi2ss'), register allocator has to know the variable size and use
//! the flag accordingly to it.
kInstFlagMove = 0x0004, kInstFlagMove = 0x0004,
//! @brief Instruction is an exchange like instruction. //! @brief Instruction is an exchange like instruction.
//! //!
//! Exchange instruction typically overwrite first and second operand, we //! Exchange instruction typically overwrite first and second operand. So
//! count 'xchg' and 'xadd' instructions right now. //! far only the instructions 'xchg' and 'xadd' are considered.
kInstFlagXchg = 0x0008, kInstFlagXchg = 0x0008,
//! @brief Instruction accesses Fp register(s). //! @brief Instruction accesses Fp register(s).
@@ -1745,6 +1749,9 @@ ASMJIT_ENUM(kInstFlags) {
//! @brief Combination of @c kInstFlagMem4 and @c kInstFlagMem8 and @c kInstFlagMem10. //! @brief Combination of @c kInstFlagMem4 and @c kInstFlagMem8 and @c kInstFlagMem10.
kInstFlagMem4_8_10 = kInstFlagMem4_8 | kInstFlagMem10, kInstFlagMem4_8_10 = kInstFlagMem4_8 | kInstFlagMem10,
//! @brief Zeroes the rest of the register if the source operand is memory.
kInstFlagZeroIfMem = 0x1000,
//! @brief REX.W/VEX.W by default. //! @brief REX.W/VEX.W by default.
kInstFlagW = 0x8000 kInstFlagW = 0x8000
}; };
@@ -1938,54 +1945,98 @@ struct InstInfo {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! @brief Get instruction name string (null terminated string). //! @brief Get instruction name string (null terminated string).
ASMJIT_INLINE const char* getName() const { return _instName + static_cast<uint32_t>(_nameIndex); } ASMJIT_INLINE const char* getName() const {
return _instName + static_cast<uint32_t>(_nameIndex);
}
//! @brief Get instruction name index (index to @ref _instName array). //! @brief Get instruction name index (index to @ref _instName array).
ASMJIT_INLINE uint32_t _getNameIndex() const { return _nameIndex; } ASMJIT_INLINE uint32_t _getNameIndex() const {
return _nameIndex;
}
//! @brief Get instruction group, see @ref kInstGroup. //! @brief Get instruction group, see @ref kInstGroup.
ASMJIT_INLINE uint32_t getGroup() const { return _group; } ASMJIT_INLINE uint32_t getGroup() const {
return _group;
}
//! @brief Get size of move instruction in bytes.
//!
//! If zero, the size of MOV instruction is determined by the size of the
//! destination register (applies mostly for x86 arithmetic). This value is
//! useful for register allocator when determining if a variable is going to
//! be overwritten or not. Basically if the move size is equal or greater
//! than a variable itself it is considered overwritten.
ASMJIT_INLINE uint32_t getMoveSize() const {
return _moveSize;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Flags] // [Flags]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! @brief Get instruction flags, see @ref kInstFlags. //! @brief Get instruction flags, see @ref kInstFlags.
ASMJIT_INLINE uint32_t getFlags() const { return _flags; } ASMJIT_INLINE uint32_t getFlags() const {
return _flags;
}
//! @brief Get whether the instruction is a control-flow intruction. //! @brief Get whether the instruction is a control-flow intruction.
//! //!
//! Control flow instruction is instruction that modifies instruction pointer, //! Control flow instruction is instruction that modifies instruction pointer,
//! typically jmp, jcc, call, or ret. //! typically jmp, jcc, call, or ret.
ASMJIT_INLINE bool isFlow() const { return (_flags & kInstFlagFlow) != 0; } ASMJIT_INLINE bool isFlow() const {
return (_flags & kInstFlagFlow) != 0;
}
//! @brief Get whether the instruction is a compare/test like intruction. //! @brief Get whether the instruction is a compare/test like intruction.
ASMJIT_INLINE bool isTest() const { return (_flags & kInstFlagTest) != 0; } ASMJIT_INLINE bool isTest() const {
return (_flags & kInstFlagTest) != 0;
}
//! @brief Get whether the instruction is a typical Move instruction. //! @brief Get whether the instruction is a typical Move instruction.
//! //!
//! Move instructions typically overwrite the first operand, so it's an useful //! Move instructions typically overwrite the first operand, so it's an useful
//! hint for @ref Compiler. Applies also to multimedia instruction - MMX, //! hint for @ref Compiler. Applies also to multimedia instruction - MMX,
//! SSE, SSE2 and AVX moves). //! SSE, SSE2 and AVX moves).
ASMJIT_INLINE bool isMove() const { return (_flags & kInstFlagMove) != 0; } ASMJIT_INLINE bool isMove() const {
return (_flags & kInstFlagMove) != 0;
}
//! @brief Get whether the instruction is a typical Exchange instruction. //! @brief Get whether the instruction is a typical Exchange instruction.
//! //!
//! Exchange instructios are 'xchg' and 'xadd'. //! Exchange instructios are 'xchg' and 'xadd'.
ASMJIT_INLINE bool isXchg() const { return (_flags & kInstFlagXchg) != 0; } ASMJIT_INLINE bool isXchg() const {
return (_flags & kInstFlagXchg) != 0;
}
//! @brief Get whether the instruction accesses Fp register(s). //! @brief Get whether the instruction accesses Fp register(s).
ASMJIT_INLINE bool isFp() const { return (_flags & kInstFlagFp) != 0; } ASMJIT_INLINE bool isFp() const {
return (_flags & kInstFlagFp) != 0;
}
//! @brief Get whether the instruction can be prefixed by LOCK prefix. //! @brief Get whether the instruction can be prefixed by LOCK prefix.
ASMJIT_INLINE bool isLockable() const { return (_flags & kInstFlagLock) != 0; } ASMJIT_INLINE bool isLockable() const {
return (_flags & kInstFlagLock) != 0;
}
//! @brief Get whether the instruction is special type (this is used by //! @brief Get whether the instruction is special type (this is used by
//! @c Compiler to manage additional variables or functionality). //! @c Compiler to manage additional variables or functionality).
ASMJIT_INLINE bool isSpecial() const { return (_flags & kInstFlagSpecial) != 0; } ASMJIT_INLINE bool isSpecial() const {
return (_flags & kInstFlagSpecial) != 0;
}
//! @brief Get whether the instruction is special type and it performs //! @brief Get whether the instruction is special type and it performs
//! memory access. //! memory access.
ASMJIT_INLINE bool isSpecialMem() const { return (_flags & kInstFlagSpecialMem) != 0; } ASMJIT_INLINE bool isSpecialMem() const {
return (_flags & kInstFlagSpecialMem) != 0;
}
//! @brief Get whether the move instruction zeroes the rest of the register
//! if the source is memory operand.
//!
//! Basically flag needed by 'movsd' and 'movss' instructions.
ASMJIT_INLINE bool isZeroIfMem() const {
return (_flags & kInstFlagZeroIfMem) != 0;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
@@ -1997,8 +2048,13 @@ struct InstInfo {
uint16_t _flags; uint16_t _flags;
//! @brief Instruction group, used also by @c Compiler. //! @brief Instruction group, used also by @c Compiler.
uint8_t _group; uint8_t _group;
//! @brief Count of bytes overritten by a move instruction.
//!
//! Only used when kInstFlagMove flag is set. If this value is zero move
//! depends on the destination register size.
uint8_t _moveSize;
//! @brief Reserved for future use. //! @brief Reserved for future use.
uint8_t _reserved[3]; uint8_t _reserved[2];
//! @brief Operands' flags. //! @brief Operands' flags.
uint16_t _opFlags[4]; uint16_t _opFlags[4];
//! @brief Primary and secondary opcodes. //! @brief Primary and secondary opcodes.
@@ -2129,82 +2185,97 @@ struct RegMask {
// [Zero] // [Zero]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE void zero(uint32_t c) ASMJIT_INLINE void zero(uint32_t c) {
{ _packed.u16[c] = 0; } _packed.u16[c] = 0;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Get] // [Get]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE uint32_t get(uint32_t c) const ASMJIT_INLINE uint32_t get(uint32_t c) const {
{ return _packed.u16[c]; } return _packed.u16[c];
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Set] // [Set]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE void set(uint32_t c, uint32_t mask) ASMJIT_INLINE void set(uint32_t c, uint32_t mask) {
{ _packed.u16[c] = static_cast<uint16_t>(mask); } _packed.u16[c] = static_cast<uint16_t>(mask);
}
ASMJIT_INLINE void set(const RegMask& other) ASMJIT_INLINE void set(const RegMask& other) {
{ _packed.setUInt64(other._packed); } _packed.setUInt64(other._packed);
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Add] // [Add]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE void add(uint32_t c, uint32_t mask) ASMJIT_INLINE void add(uint32_t c, uint32_t mask) {
{ _packed.u16[c] |= static_cast<uint16_t>(mask); } _packed.u16[c] |= static_cast<uint16_t>(mask);
}
ASMJIT_INLINE void add(const RegMask& other) ASMJIT_INLINE void add(const RegMask& other) {
{ _packed.or_(other._packed); } _packed.or_(other._packed);
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Del] // [Del]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE void del(uint32_t c, uint32_t mask) ASMJIT_INLINE void del(uint32_t c, uint32_t mask) {
{ _packed.u16[c] &= ~static_cast<uint16_t>(mask); } _packed.u16[c] &= ~static_cast<uint16_t>(mask);
}
ASMJIT_INLINE void del(const RegMask& other) ASMJIT_INLINE void del(const RegMask& other) {
{ _packed.del(other._packed); } _packed.del(other._packed);
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [And] // [And]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE void and_(uint32_t c, uint32_t mask) ASMJIT_INLINE void and_(uint32_t c, uint32_t mask) {
{ _packed.u16[c] &= static_cast<uint16_t>(mask); } _packed.u16[c] &= static_cast<uint16_t>(mask);
}
ASMJIT_INLINE void and_(const RegMask& other) ASMJIT_INLINE void and_(const RegMask& other) {
{ _packed.and_(other._packed); } _packed.and_(other._packed);
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Xor] // [Xor]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE void xor_(uint32_t c, uint32_t mask) ASMJIT_INLINE void xor_(uint32_t c, uint32_t mask) {
{ _packed.u16[c] ^= static_cast<uint16_t>(mask); } _packed.u16[c] ^= static_cast<uint16_t>(mask);
}
ASMJIT_INLINE void xor_(const RegMask& other) ASMJIT_INLINE void xor_(const RegMask& other) {
{ _packed.xor_(other._packed); } _packed.xor_(other._packed);
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [IsEmpty / Has] // [IsEmpty / Has]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE bool isEmpty() const ASMJIT_INLINE bool isEmpty() const {
{ return _packed.isZero(); } return _packed.isZero();
}
ASMJIT_INLINE bool has(uint32_t c, uint32_t mask = 0xFFFFFFFF) const ASMJIT_INLINE bool has(uint32_t c, uint32_t mask = 0xFFFFFFFF) const {
{ return (static_cast<uint32_t>(_packed.u16[c]) & mask) != 0; } return (static_cast<uint32_t>(_packed.u16[c]) & mask) != 0;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Reset] // [Reset]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE void reset() ASMJIT_INLINE void reset() {
{ _packed.reset(); } _packed.reset();
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]