XCHG: adjust lock prefix warning, add specific warning for LOCK XCHG

"LOCK XCHG reg,mem" would issue a warning for being unlockable, which
is incorrect. In this case the RM encoding is simply an alias for the
MR encoding. Add a "LOCK1" bit to deal with that.

However, XCHG is *always* locked, so create a new warning to
explicitly flag a user-specified LOCK XCHG; default off.

Consider optimizing that prefix away in the future, but for now, let's
stick to the user-requested code sequence.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin 2023-10-12 14:49:53 -07:00
parent 4d9c102e44
commit e993b75aa6
3 changed files with 30 additions and 20 deletions

View File

@ -1843,14 +1843,27 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits,
}
}
if (has_prefix(ins, PPS_LOCK, P_LOCK) && lockcheck &&
(!itemp_has(temp,IF_LOCK) || !is_class(MEMORY, ins->oprs[0].type))) {
/*!
*!prefix-lock [on] LOCK prefix on unlockable instructions
*!=lock
*! warns about \c{LOCK} prefixes on unlockable instructions.
*/
nasm_warn(WARN_PREFIX_LOCK|ERR_PASS2 , "instruction is not lockable");
if (lockcheck && has_prefix(ins, PPS_LOCK, P_LOCK)) {
if ((!itemp_has(temp,IF_LOCK) || !is_class(MEMORY, ins->oprs[0].type)) &&
(!itemp_has(temp,IF_LOCK1) || !is_class(MEMORY, ins->oprs[1].type))) {
/*!
*!prefix-lock-error [on] LOCK prefix on unlockable instruction
*!=lock
*! warns about \c{LOCK} prefixes on unlockable instructions.
*/
nasm_warn(WARN_PREFIX_LOCK_ERROR|ERR_PASS2 , "instruction is not lockable");
} else if (temp->opcode == I_XCHG) {
/*!
*!prefix-lock-xchg [on] superfluous LOCK prefix on XCHG instruction
*! warns about a \c{LOCK} prefix added to an \c{XCHG} instruction.
*! The \c{XCHG} instruction is \e{always} locking, and so this
*! prefix is not necessary; however, NASM will generate it if
*! explicitly provided by the user, so this warning indicates that
*! suboptimal code is being generated.
*/
nasm_warn(WARN_PREFIX_LOCK_XCHG|ERR_PASS2,
"superfluous LOCK prefix on XCHG instruction");
}
}
bad_hle_warn(ins, hleok);

View File

@ -34,6 +34,7 @@ if_("PRIV", "Privileged instruction");
if_("SMM", "Only valid in SMM");
if_("PROT", "Protected mode only");
if_("LOCK", "Lockable if operand 0 is memory");
if_("LOCK1", "Lockable if operand 1 is memory");
if_("NOLONG", "Not available in long mode");
if_("LONG", "Long mode");
if_("NOHLE", "HLE prefixes forbidden");

View File

@ -1455,22 +1455,18 @@ XCHG reg64,reg_rax [r-: o64 90+r] X86_64,LONG
; This must be NOLONG since opcode 90 is NOP, and in 64-bit mode
; "xchg eax,eax" is *not* a NOP.
XCHG reg_eax,reg_eax [--: o32 90] 386,NOLONG
XCHG reg8,mem [rm: hlenl 86 /r] 8086,SM,LOCK
XCHG reg8,reg8 [rm: 86 /r] 8086
XCHG reg16,mem [rm: hlenl o16 87 /r] 8086,SM,LOCK
XCHG reg16,reg16 [rm: o16 87 /r] 8086
XCHG reg32,mem [rm: hlenl o32 87 /r] 386,SM,LOCK
XCHG reg32,reg32 [rm: o32 87 /r] 386
XCHG reg64,mem [rm: hlenl o64 87 /r] X86_64,LONG,SM,LOCK
XCHG reg64,reg64 [rm: o64 87 /r] X86_64,LONG
XCHG mem,reg8 [mr: hlenl 86 /r] 8086,SM,LOCK
XCHG reg8,reg8 [mr: 86 /r] 8086
XCHG mem,reg16 [mr: hlenl o16 87 /r] 8086,SM,LOCK
XCHG reg16,reg16 [mr: o16 87 /r] 8086
XCHG mem,reg32 [mr: hlenl o32 87 /r] 386,SM,LOCK
XCHG reg32,reg32 [mr: o32 87 /r] 386
XCHG mem,reg64 [mr: hlenl o64 87 /r] X86_64,LONG,SM,LOCK
XCHG reg64,reg64 [mr: o64 87 /r] X86_64,LONG
XCHG mem,reg8 [mr: hlenl 86 /r] 8086,SM,LOCK
XCHG mem,reg16 [mr: hlenl o16 87 /r] 8086,SM,LOCK
XCHG mem,reg32 [mr: hlenl o32 87 /r] 386,SM,LOCK
XCHG mem,reg64 [mr: hlenl o64 87 /r] X86_64,LONG,SM,LOCK
XCHG reg8,mem [rm: hlenl 86 /r] 8086,SM,LOCK1
XCHG reg16,mem [rm: hlenl o16 87 /r] 8086,SM,LOCK1
XCHG reg32,mem [rm: hlenl o32 87 /r] 386,SM,LOCK1
XCHG reg64,mem [rm: hlenl o64 87 /r] X86_64,LONG,SM,LOCK1
XLATB void [ d7] 8086
XLAT void [ d7] 8086
XOR mem,reg8 [mr: hle 30 /r] 8086,SM,LOCK