obsolete handing: handle a few more subcases in a useful way

Distinguish instructions which have once been valid (OBSOLETE) from
those that never saw the light of day (NEVER). Futhermore, flag
instructions which devolve to an architectural noop from those with
undefined behavior and possibly recycled opcodes.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin (Intel) 2019-08-09 14:52:16 -07:00
parent fb11889040
commit 5b39461178
5 changed files with 46 additions and 15 deletions

View File

@ -781,6 +781,11 @@ int64_t assemble(int32_t segment, int64_t start, int bits, insn *instruction)
if (m == MOK_GOOD) {
/* Matches! */
if (unlikely(itemp_has(temp, IF_OBSOLETE))) {
errflags warning;
const char *whathappened;
const char *validity;
bool never = itemp_has(temp, IF_NEVER);
/*
* If IF_OBSOLETE is set, warn the user. Different
* warning classes for "obsolete but valid for this
@ -794,20 +799,34 @@ int64_t assemble(int32_t segment, int64_t start, int bits, insn *instruction)
*! which, \c{0Fh}, instead is an opcode prefix on
*! CPUs newer than the first generation 8086.
*
*!obsolete-nop [on] instruction obsolete and is a noop on the target CPU
*! warns for an instruction which has been removed
*! from the architecture, but has been architecturally
*! defined to be a noop for future CPUs.
*
*!obsolete-valid [on] instruction obsolete but valid on the target CPU
*! warns for an instruction which has been removed
*! from the architecture, but is still valid on the
*! specific CPU given in the \c{CPU} directive. Code
*! using these instructions is not forward compatible.
*! using these instructions is most likely not
*! forward compatible.
*/
if (iflag_cmp_cpu_level(&insns_flags[temp->iflag_idx], &cpu)) {
nasm_warn(WARN_OBSOLETE_REMOVED,
"instruction obsolete and removed on the target CPU");
whathappened = never ? "never implemented" : "obsolete";
if (!never && !iflag_cmp_cpu_level(&insns_flags[temp->iflag_idx], &cpu)) {
warning = WARN_OBSOLETE_VALID;
validity = "but valid on";
} else if (itemp_has(temp, IF_NOP)) {
warning = WARN_OBSOLETE_NOP;
validity = "and is a noop on";
} else {
nasm_warn(WARN_OBSOLETE_VALID,
"instruction obsolete but valid on the target CPU");
warning = WARN_OBSOLETE_REMOVED;
validity = "and removed from";
}
nasm_warn(warning, "instruction %s %s the target CPU",
whathappened, validity);
}
data.itemp = temp;

View File

@ -7,3 +7,6 @@
cpu 386
pop cs
mov cs,ax
cpu any
pcommit

View File

@ -83,8 +83,10 @@ if_("AVX5124FMAPS", "AVX-512 4-iteration multiply-add");
if_("AVX5124VNNIW", "AVX-512 4-iteration dot product");
if_("SGX", "Intel Software Guard Extensions (SGX)");
# Put these last
# Put these last [hpa: why?]
if_("OBSOLETE", "Instruction removed from architecture");
if_("NEVER", "Instruction never implemented");
if_("NOP", "Instruction is always a (nonintentional) NOP");
if_("VEX", "VEX or XOP encoded instruction");
if_("EVEX", "EVEX encoded instruction");

View File

@ -5262,7 +5262,7 @@ RDPID reg32 [m: f3 0f c7 /7] X64,UNDOC,FUTURE
CLFLUSHOPT mem [m: 66 0f ae /7] FUTURE
CLWB mem [m: 66 0f ae /6] FUTURE
; This one was killed before it saw the light of day
PCOMMIT void [ 66 0f ae f8] FUTURE,UNDOC,OBSOLETE
PCOMMIT void [ 66 0f ae f8] FUTURE,NEVER,NOP
; AMD Zen v1
CLZERO void [ 0f 01 fc] FUTURE,AMD

View File

@ -499,25 +499,32 @@ sub format_insn($$$$$) {
}
$decorators =~ tr/a-z/A-Z/;
# expand the flags
my @flags;
# expand and uniqify the flags
my %flags;
foreach my $flag (split(',', $flags)) {
if ($flag eq 'ND') {
$nd = 1;
} elsif ($flag eq 'X64') {
push(@flags, 'LONG', 'X86_64');
# X64 is shorthand for "LONG,X86_64"
$flags{'LONG'}++;
$flags{'X86_64'}++;
} elsif ($flag ne '') {
push(@flags, $flag);
$flags{$flag}++;
}
if ($flag eq 'NEVER' || $flag eq 'NOP') {
# These flags imply OBSOLETE
$flags{'OBSOLETE'}++;
}
}
if ($codes =~ /evex\./) {
push(@flags, 'EVEX');
$flags{'EVEX'}++;
} elsif ($codes =~ /(vex|xop)\./) {
push(@flags, 'VEX');
$flags{'VEX'}++;
}
$flagsindex = insns_flag_index(@flags);
$flagsindex = insns_flag_index(keys %flags);
die "$fname:$line: error in flags $flags" unless (defined($flagsindex));
@bytecode = (decodify($codes, $relax), 0);