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)
suffix = ++sufsp;
nasm_warn(ERR_PASS2 | WARN_NUMBER_OVERFLOW,
nasm_warn(WARN_NUMBER_OVERFLOW|ERR_PASS2,
"%s%s%s%s%s exceeds bounds",
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:
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",
prefix_name(rep_pfx));
}
break;
case w_inval:
nasm_warn(WARN_PREFIX_HLE|ERR_PASS2,
nasm_warn(WARN_PREFIX_HLE,
"%s invalid with this instruction",
prefix_name(rep_pfx));
break;
@@ -1784,7 +1784,7 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
if (bits != 16 && pfx == P_OSP) {
/* Allow osp prefix as is */
} 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",
prefix_name(pfx));
} 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) {
/* Allow osp prefix as is */
} 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",
prefix_name(pfx));
} 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))
ins->rex |= REX_W;
} 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",
prefix_name(pfx));
} else if (!(opt_opsize & 64)) {
@@ -2013,7 +2013,7 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
*! \c{bnd jmp dword}.
*/
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");
}
break;
@@ -2246,7 +2246,7 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
*!=lock
*! 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) {
/*!
*!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
*! 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");
}
}
@@ -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)))
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
@@ -2347,9 +2368,11 @@ static int prefix_byte(enum prefixes pfx, const int bits)
return 0xF3;
case R_CS:
case P_PN:
return 0x2E;
case R_DS:
case P_PT:
return 0x3E;
case R_ES:
@@ -2673,7 +2696,7 @@ static void gencode(struct out_data *data, insn *ins)
nasm_nonfatal("non-absolute expression not permitted "
"as argument %d", op2);
else if (opy->offset & ~mask)
nasm_warn(ERR_PASS2|WARN_NUMBER_OVERFLOW,
nasm_warn(WARN_NUMBER_OVERFLOW,
"is4 argument exceeds bounds");
c = opy->offset & mask;
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
* 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",
(opx->type & BITS8) ? "signed byte" :
s == 16 ? "word" :
@@ -2797,7 +2820,7 @@ static void gencode(struct out_data *data, insn *ins)
emit_rex(data, ins);
if (absolute_op(opx)) {
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);
} else {
@@ -3629,7 +3652,7 @@ static int process_ea(operand *input, int rfield, opflags_t rflags,
*/
if (input->segment == NO_SEG ||
(input->opflags & OPFLAG_RELATIVE)) {
nasm_warn(WARN_EA_ABSOLUTE|ERR_PASS2,
nasm_warn(WARN_EA_ABSOLUTE,
"absolute address can not be RIP-relative");
input->type &= ~IP_REL;
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
## the specific copyright holders.
##
@@ -89,6 +89,10 @@ nf
% TOKEN_PREFIX, PPS_ZU, TFLAG_BRC, P_*
zu
% TOKEN_PREFIX, PPS_SEG, TFLAG_BRC, P_*
pt
pn
% TOKEN_SIZE, SIZE_*, 0, S_*
byte
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
* the specific copyright holders.
*
@@ -67,7 +67,8 @@ const char *prefix_name(int token)
"a16", "a32", "a64", "asp", "lock", "o16", "o32", "o64", "osp",
"rep", "repe", "repne", "repnz", "repz", "wait",
"xacquire", "xrelease", "bnd", "nobnd", "{rex}", "{rex2}",
"{evex}", "{vex}", "{vex3}", "{vex2}", "{nf}", "{zu}"
"{evex}", "{vex}", "{vex3}", "{vex2}", "{nf}", "{zu}",
"{pt}", "{pn}"
};
const char *name;

View File

@@ -1226,9 +1226,16 @@ static int matches(const uint8_t *data, const struct prefix_info *prefix,
return 0;
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) {
/* Emit segment override prefix explicitly */
ins->prefixes[PPS_SEG] = prefix->segover;
/* Emit any possible segment override prefix explicitly */
if (!ins->prefixes[PPS_SEG])
ins->prefixes[PPS_SEG] = prefix->segover;
if (prefix->asp) {
if (ins->prefixes[PPS_ASIZE])

View File

@@ -684,6 +684,8 @@ enum prefixes { /* instruction prefixes */
P_VEX2,
P_NF,
P_ZU,
P_PT,
P_PN,
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