0
0
mirror of https://github.com/netwide-assembler/nasm.git synced 2025-10-10 00:25:06 -04:00

Add support for the {pt} and {pn} branch hint prefixes

Add support for the {pt} and {pn} branch hint prefixes, now when they
are no longer orphanned...

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin
2025-09-02 16:29:46 -07:00
parent 56567a0c4c
commit 80225b4722
6 changed files with 67 additions and 18 deletions

View File

@@ -220,7 +220,7 @@ static void warn_overflow(int size, const char *prefix, const char *suffix)
if (!suffix) if (!suffix)
suffix = ++sufsp; suffix = ++sufsp;
nasm_warn(ERR_PASS2 | WARN_NUMBER_OVERFLOW, nasm_warn(WARN_NUMBER_OVERFLOW|ERR_PASS2,
"%s%s%s%s%s exceeds bounds", "%s%s%s%s%s exceeds bounds",
prefix, pfxsp, size_name(size), sufsp, suffix); prefix, pfxsp, size_name(size), sufsp, suffix);
} }
@@ -1451,14 +1451,14 @@ static void bad_hle_warn(const insn * ins, uint8_t hleok)
case w_lock: case w_lock:
if (ins->prefixes[PPS_LOCK] != P_LOCK) { if (ins->prefixes[PPS_LOCK] != P_LOCK) {
nasm_warn(WARN_PREFIX_HLE|ERR_PASS2, nasm_warn(WARN_PREFIX_HLE,
"%s with this instruction requires lock", "%s with this instruction requires lock",
prefix_name(rep_pfx)); prefix_name(rep_pfx));
} }
break; break;
case w_inval: case w_inval:
nasm_warn(WARN_PREFIX_HLE|ERR_PASS2, nasm_warn(WARN_PREFIX_HLE,
"%s invalid with this instruction", "%s invalid with this instruction",
prefix_name(rep_pfx)); prefix_name(rep_pfx));
break; break;
@@ -1784,7 +1784,7 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
if (bits != 16 && pfx == P_OSP) { if (bits != 16 && pfx == P_OSP) {
/* Allow osp prefix as is */ /* Allow osp prefix as is */
} else if (pfx != P_none && pfx != P_O16) { } else if (pfx != P_none && pfx != P_O16) {
nasm_warn(WARN_PREFIX_OPSIZE|ERR_PASS2, nasm_warn(WARN_PREFIX_OPSIZE,
"invalid operand size prefix %s, must be o16", "invalid operand size prefix %s, must be o16",
prefix_name(pfx)); prefix_name(pfx));
} else if (!(opt_opsize & 16)) { } else if (!(opt_opsize & 16)) {
@@ -1805,7 +1805,7 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
} else if (bits == 16 && pfx == P_OSP) { } else if (bits == 16 && pfx == P_OSP) {
/* Allow osp prefix as is */ /* Allow osp prefix as is */
} else if (pfx != P_none && pfx != P_O32) { } else if (pfx != P_none && pfx != P_O32) {
nasm_warn(WARN_PREFIX_OPSIZE|ERR_PASS2, nasm_warn(WARN_PREFIX_OPSIZE,
"invalid operand size prefix %s, must be o32", "invalid operand size prefix %s, must be o32",
prefix_name(pfx)); prefix_name(pfx));
} else if (!(opt_opsize & 32)) { } else if (!(opt_opsize & 32)) {
@@ -1839,7 +1839,7 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
if (!(ins->rex & REX_NW)) if (!(ins->rex & REX_NW))
ins->rex |= REX_W; ins->rex |= REX_W;
} else if (pfx != P_none && pfx != P_O64) { } else if (pfx != P_none && pfx != P_O64) {
nasm_warn(WARN_PREFIX_OPSIZE|ERR_PASS2, nasm_warn(WARN_PREFIX_OPSIZE,
"invalid operand size prefix %s, must be o64", "invalid operand size prefix %s, must be o64",
prefix_name(pfx)); prefix_name(pfx));
} else if (!(opt_opsize & 64)) { } else if (!(opt_opsize & 64)) {
@@ -2013,7 +2013,7 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
*! \c{bnd jmp dword}. *! \c{bnd jmp dword}.
*/ */
if (!ins->dummy) if (!ins->dummy)
nasm_warn(WARN_PREFIX_BND|ERR_PASS2 , nasm_warn(WARN_PREFIX_BND,
"jmp short does not init bnd regs - bnd prefix dropped"); "jmp short does not init bnd regs - bnd prefix dropped");
} }
break; break;
@@ -2246,7 +2246,7 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
*!=lock *!=lock
*! warns about \c{LOCK} prefixes on unlockable instructions. *! warns about \c{LOCK} prefixes on unlockable instructions.
*/ */
nasm_warn(WARN_PREFIX_LOCK_ERROR|ERR_PASS2 , "instruction is not lockable"); nasm_warn(WARN_PREFIX_LOCK_ERROR, "instruction is not lockable");
} else if (temp->opcode == I_XCHG) { } else if (temp->opcode == I_XCHG) {
/*! /*!
*!prefix-lock-xchg [on] superfluous \c{LOCK} prefix on \c{XCHG} instruction *!prefix-lock-xchg [on] superfluous \c{LOCK} prefix on \c{XCHG} instruction
@@ -2256,7 +2256,7 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
*! explicitly provided by the user, so this warning indicates that *! explicitly provided by the user, so this warning indicates that
*! suboptimal code is being generated. *! suboptimal code is being generated.
*/ */
nasm_warn(WARN_PREFIX_LOCK_XCHG|ERR_PASS2, nasm_warn(WARN_PREFIX_LOCK_XCHG,
"superfluous LOCK prefix on XCHG instruction"); "superfluous LOCK prefix on XCHG instruction");
} }
} }
@@ -2272,6 +2272,27 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
(itemp_has(temp, IF_BND) && !has_prefix(ins, PPS_REP, P_NOBND))) (itemp_has(temp, IF_BND) && !has_prefix(ins, PPS_REP, P_NOBND)))
ins->prefixes[PPS_REP] = P_BND; ins->prefixes[PPS_REP] = P_BND;
/*
* Warn on {pt} or {pn} on a nonhintable instruction
*/
if (ins->prefixes[PPS_SEG] == P_PT || ins->prefixes[PPS_SEG] == P_PN) {
if (!itemp_has(temp, IF_JCC_HINT)) {
/*!
*!prefix-hint-dropped [on] invalid branch hint prefix dropped
*! warns that the \c{{PT}} (predict taken) or \c{{PN}}
*! (predict not taken) branch prediction hint prefixes
*! are specified on an instruction that does not take
*! these prefixes. As these prefixes alias the segment
*! override prefixes, this may be a very serious error,
*! and therefore NASM will not generate these prefixes.
*! To force these prefixes to be emitted, use \c{DS} or
*! \c{CS}, instead, respectively.
*/
nasm_warn(WARN_PREFIX_HINT_DROPPED,
"invalid branch hint prefix dropped");
ins->prefixes[PPS_SEG] = 0;
}
}
/* /*
* Add length of legacy prefixes * Add length of legacy prefixes
@@ -2347,9 +2368,11 @@ static int prefix_byte(enum prefixes pfx, const int bits)
return 0xF3; return 0xF3;
case R_CS: case R_CS:
case P_PN:
return 0x2E; return 0x2E;
case R_DS: case R_DS:
case P_PT:
return 0x3E; return 0x3E;
case R_ES: case R_ES:
@@ -2673,7 +2696,7 @@ static void gencode(struct out_data *data, insn *ins)
nasm_nonfatal("non-absolute expression not permitted " nasm_nonfatal("non-absolute expression not permitted "
"as argument %d", op2); "as argument %d", op2);
else if (opy->offset & ~mask) else if (opy->offset & ~mask)
nasm_warn(ERR_PASS2|WARN_NUMBER_OVERFLOW, nasm_warn(WARN_NUMBER_OVERFLOW,
"is4 argument exceeds bounds"); "is4 argument exceeds bounds");
c = opy->offset & mask; c = opy->offset & mask;
goto emit_is4; goto emit_is4;
@@ -2776,7 +2799,7 @@ static void gencode(struct out_data *data, insn *ins)
* If this wasn't explicitly byte-sized, warn as though we * If this wasn't explicitly byte-sized, warn as though we
* had fallen through to the imm16/32/64 case. * had fallen through to the imm16/32/64 case.
*/ */
nasm_warn(ERR_PASS2|WARN_NUMBER_OVERFLOW, nasm_warn(WARN_NUMBER_OVERFLOW|ERR_PASS2,
"%s exceeds bounds", "%s exceeds bounds",
(opx->type & BITS8) ? "signed byte" : (opx->type & BITS8) ? "signed byte" :
s == 16 ? "word" : s == 16 ? "word" :
@@ -2797,7 +2820,7 @@ static void gencode(struct out_data *data, insn *ins)
emit_rex(data, ins); emit_rex(data, ins);
if (absolute_op(opx)) { if (absolute_op(opx)) {
if (!is_hint_nop(opx->offset)) { if (!is_hint_nop(opx->offset)) {
nasm_warn(ERR_PASS2, "not a valid hint-NOP opcode (0D, 18-1F)"); nasm_warn(0, "not a valid hint-NOP opcode (0D, 18-1F)");
} }
out_rawbyte(data, opx->offset); out_rawbyte(data, opx->offset);
} else { } else {
@@ -3629,7 +3652,7 @@ static int process_ea(operand *input, int rfield, opflags_t rflags,
*/ */
if (input->segment == NO_SEG || if (input->segment == NO_SEG ||
(input->opflags & OPFLAG_RELATIVE)) { (input->opflags & OPFLAG_RELATIVE)) {
nasm_warn(WARN_EA_ABSOLUTE|ERR_PASS2, nasm_warn(WARN_EA_ABSOLUTE,
"absolute address can not be RIP-relative"); "absolute address can not be RIP-relative");
input->type &= ~IP_REL; input->type &= ~IP_REL;
input->type |= MEMORY; input->type |= MEMORY;

View File

@@ -1,6 +1,6 @@
## -------------------------------------------------------------------------- ## --------------------------------------------------------------------------
## ##
## Copyright 1996-2021 The NASM Authors - All Rights Reserved ## Copyright 1996-2025 The NASM Authors - All Rights Reserved
## See the file AUTHORS included with the NASM distribution for ## See the file AUTHORS included with the NASM distribution for
## the specific copyright holders. ## the specific copyright holders.
## ##
@@ -89,6 +89,10 @@ nf
% TOKEN_PREFIX, PPS_ZU, TFLAG_BRC, P_* % TOKEN_PREFIX, PPS_ZU, TFLAG_BRC, P_*
zu zu
% TOKEN_PREFIX, PPS_SEG, TFLAG_BRC, P_*
pt
pn
% TOKEN_SIZE, SIZE_*, 0, S_* % TOKEN_SIZE, SIZE_*, 0, S_*
byte byte
word word

View File

@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- * /* ----------------------------------------------------------------------- *
* *
* Copyright 1996-2024 The NASM Authors - All Rights Reserved * Copyright 1996-2025 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for * See the file AUTHORS included with the NASM distribution for
* the specific copyright holders. * the specific copyright holders.
* *
@@ -67,7 +67,8 @@ const char *prefix_name(int token)
"a16", "a32", "a64", "asp", "lock", "o16", "o32", "o64", "osp", "a16", "a32", "a64", "asp", "lock", "o16", "o32", "o64", "osp",
"rep", "repe", "repne", "repnz", "repz", "wait", "rep", "repe", "repne", "repnz", "repz", "wait",
"xacquire", "xrelease", "bnd", "nobnd", "{rex}", "{rex2}", "xacquire", "xrelease", "bnd", "nobnd", "{rex}", "{rex2}",
"{evex}", "{vex}", "{vex3}", "{vex2}", "{nf}", "{zu}" "{evex}", "{vex}", "{vex3}", "{vex2}", "{nf}", "{zu}",
"{pt}", "{pn}"
}; };
const char *name; const char *name;

View File

@@ -1226,9 +1226,16 @@ static int matches(const uint8_t *data, const struct prefix_info *prefix,
return 0; return 0;
ins->prefixes[PPS_OSIZE] = pfx; ins->prefixes[PPS_OSIZE] = pfx;
} }
if (itemp_has(t, IF_JCC_HINT)) {
if ((prefix->seg & ~0x10) == 0x2e)
ins->prefixes[PPS_SEG] = prefix->seg & 0x10 ? P_PT : P_PN;
}
if (!a_used) { if (!a_used) {
/* Emit segment override prefix explicitly */ /* Emit any possible segment override prefix explicitly */
ins->prefixes[PPS_SEG] = prefix->segover; if (!ins->prefixes[PPS_SEG])
ins->prefixes[PPS_SEG] = prefix->segover;
if (prefix->asp) { if (prefix->asp) {
if (ins->prefixes[PPS_ASIZE]) if (ins->prefixes[PPS_ASIZE])

View File

@@ -684,6 +684,8 @@ enum prefixes { /* instruction prefixes */
P_VEX2, P_VEX2,
P_NF, P_NF,
P_ZU, P_ZU,
P_PT,
P_PN,
PREFIX_ENUM_LIMIT PREFIX_ENUM_LIMIT
}; };

12
test/jcchint.asm Normal file
View File

@@ -0,0 +1,12 @@
bits 64
here:
cs jz there
ds jz there
{pt} jz there
{pn} jz there
es jz there
ss jz there
there:
{pt} jmp there
{pn} jmp there