mirror of
https://github.com/netwide-assembler/nasm
synced 2026-08-26 16:23:04 -04:00
WIP: work toward saner handling of CPU feature sets
With APX especially, it is going to be more important to have a consistent handling of CPU features. This is a WIP for generating flags and feature masks.
This commit is contained in:
parent
0ab85c391c
commit
00d7defbca
19 changed files with 923 additions and 421 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -94,6 +94,8 @@ TAGS
|
|||
/version.mac
|
||||
/version.mak
|
||||
/version.sed
|
||||
/x86/cpunames.h
|
||||
/x86/featureinfo.h
|
||||
/x86/iflag.c
|
||||
/x86/iflaggen.h
|
||||
/x86/insnsa.c
|
||||
|
|
|
|||
50
Makefile.in
50
Makefile.in
|
|
@ -137,7 +137,7 @@ LIBOBJ_NW = stdlib/snprintf.$(O) stdlib/vsnprintf.$(O) stdlib/strlcpy.$(O) \
|
|||
\
|
||||
x86/insnsa.$(O) x86/insnsb.$(O) x86/insnsd.$(O) x86/insnsn.$(O) \
|
||||
x86/regs.$(O) x86/regvals.$(O) x86/regflags.$(O) x86/regdis.$(O) \
|
||||
x86/iflag.$(O) \
|
||||
x86/iflag.$(O) x86/featureinfo.$(O) x86/cpunames.$(O) \
|
||||
\
|
||||
asm/error.$(O) \
|
||||
asm/floats.$(O) \
|
||||
|
|
@ -211,8 +211,9 @@ WARNSRCS = $(LIBOBJ_NW:.$(O)=.c) asm/nasm.c
|
|||
PERLREQ_CLEANABLE = \
|
||||
x86/insnsb.c x86/insnsa.c x86/insnsd.c x86/insnsi.h x86/insnsn.c \
|
||||
x86/regs.c x86/regs.h x86/regflags.c x86/regdis.c x86/regdis.h \
|
||||
x86/regvals.c asm/tokhash.c asm/tokens.h asm/pptok.h asm/pptok.c \
|
||||
x86/iflag.c x86/iflaggen.h \
|
||||
x86/regvals.c x86/iflag.c x86/iflaggen.h \
|
||||
x86/featureinfo.h x86/cpunames.h \
|
||||
asm/tokhash.c asm/tokens.h asm/pptok.h asm/pptok.c \
|
||||
macros/macros.c \
|
||||
asm/pptok.ph asm/directbl.c asm/directiv.h \
|
||||
$(WARNFILES) \
|
||||
|
|
@ -223,36 +224,41 @@ PERLREQ_CLEANABLE = \
|
|||
# by "make spotless"...
|
||||
PERLREQ = config/unconfig.h $(PERLREQ_CLEANABLE)
|
||||
|
||||
INSDEP = x86/insns.xda x86/insns.pl x86/insns-iflags.ph x86/iflags.ph
|
||||
|
||||
x86/insns.xda: x86/insns.dat x86/preinsns.pl
|
||||
$(RUNPERL) '$(srcdir)'/x86/preinsns.pl $< $@
|
||||
|
||||
config/unconfig.h: config/config.h.in autoconf/unconfig.pl
|
||||
$(RUNPERL) '$(srcdir)'/autoconf/unconfig.pl \
|
||||
'$(srcdir)' config/config.h.in config/unconfig.h
|
||||
|
||||
#
|
||||
# x86 feature flags and CPU names
|
||||
#
|
||||
FEATDEP = x86/x86features.ph x86/features.ph
|
||||
|
||||
x86/featureinfo.h: x86/featureinfo.pl $(FEATDEP)
|
||||
$(RUNPERL) $< $@
|
||||
x86/cpunames.h: x86/cpunames.pl x86/cpunames.ph $(FEATDEP)
|
||||
$(RUNPERL) $< $@
|
||||
|
||||
# Preprocess insns.dat. This is done as a separate step to make
|
||||
# debugging of the macro expansions easier.
|
||||
x86/insns.xda: x86/preinsns.pl x86/insns.dat
|
||||
$(RUNPERL) $^ $@
|
||||
|
||||
INSDEP = x86/insns.xda x86/insns-iflags.ph x86/iflags.ph $(FEATDEP)
|
||||
|
||||
x86/iflag.c: $(INSDEP)
|
||||
$(RUNPERL) $(srcdir)/x86/insns.pl -fc \
|
||||
$(srcdir)/x86/insns.xda x86/iflag.c
|
||||
$(RUNPERL) $(srcdir)/x86/insns.pl -fc $< $@
|
||||
x86/iflaggen.h: $(INSDEP)
|
||||
$(RUNPERL) $(srcdir)/x86/insns.pl -fh \
|
||||
$(srcdir)/x86/insns.xda x86/iflaggen.h
|
||||
$(RUNPERL) $(srcdir)/x86/insns.pl -fh $< $@
|
||||
x86/insnsb.c: $(INSDEP)
|
||||
$(RUNPERL) $(srcdir)/x86/insns.pl -b \
|
||||
$(srcdir)/x86/insns.xda x86/insnsb.c
|
||||
$(RUNPERL) $(srcdir)/x86/insns.pl -b $< $@
|
||||
x86/insnsa.c: $(INSDEP)
|
||||
$(RUNPERL) $(srcdir)/x86/insns.pl -a \
|
||||
$(srcdir)/x86/insns.xda x86/insnsa.c
|
||||
$(RUNPERL) $(srcdir)/x86/insns.pl -a $< $@
|
||||
x86/insnsd.c: $(INSDEP)
|
||||
$(RUNPERL) $(srcdir)/x86/insns.pl -d \
|
||||
$(srcdir)/x86/insns.xda x86/insnsd.c
|
||||
$(RUNPERL) $(srcdir)/x86/insns.pl -d $< $@
|
||||
x86/insnsi.h: $(INSDEP)
|
||||
$(RUNPERL) $(srcdir)/x86/insns.pl -i \
|
||||
$(srcdir)/x86/insns.xda x86/insnsi.h
|
||||
$(RUNPERL) $(srcdir)/x86/insns.pl -i $< $@
|
||||
x86/insnsn.c: $(INSDEP)
|
||||
$(RUNPERL) $(srcdir)/x86/insns.pl -n \
|
||||
$(srcdir)/x86/insns.xda x86/insnsn.c
|
||||
$(RUNPERL) $(srcdir)/x86/insns.pl -n $< $@
|
||||
|
||||
# These files contains all the standard macros that are derived from
|
||||
# the version number.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
@ -125,6 +125,9 @@ static int process_ea(operand *input, int rfield, opflags_t rflags,
|
|||
/* Convert a prefix to a byte value */
|
||||
static int prefix_byte(enum prefixes pfx, const int bits);
|
||||
|
||||
/* Map of feature flag indicies for which the current CPU flags are OK */
|
||||
static bool itemp_features_ok[ARRAY_SIZE(insns_flags)];
|
||||
|
||||
/*
|
||||
* Convert operand/address/mode size to a BITS opflag constant.
|
||||
* This is not valid for 80+ bits!
|
||||
|
|
@ -981,7 +984,7 @@ static int64_t assemble(insn *instruction)
|
|||
|
||||
whathappened = never ? "never implemented" : "obsolete";
|
||||
|
||||
if (!never && !iflag_cmp_cpu_level(&insns_flags[temp->iflag_idx], &cpu)) {
|
||||
if (!never && 1 /* !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)) {
|
||||
|
|
@ -2100,7 +2103,7 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
|
|||
ins->rex &= ~REX_L;
|
||||
ins->rex |= REX_P;
|
||||
} else if ((ins->rex & (REX_L|REX_W|REX_BXR)) == (REX_L|REX_R) &&
|
||||
iflag_cpu_level_ok(&cpu, IF_X86_64)) {
|
||||
iflag_test(&cpu, IF_LOCKREX)) {
|
||||
/* LOCK-as-REX.R */
|
||||
if (assert_no_prefix(ins, PPS_LOCK))
|
||||
return -1;
|
||||
|
|
@ -3315,9 +3318,9 @@ static enum match_result matches(const struct itemplate * const itemp,
|
|||
}
|
||||
|
||||
/*
|
||||
* Check template is okay at the set cpu level
|
||||
* Check CPU feature masking flags
|
||||
*/
|
||||
if (iflag_cmp_cpu_level(&insns_flags[itemp->iflag_idx], &cpu) > 0)
|
||||
if (!itemp_features_ok[itemp->iflag_idx])
|
||||
return MERR_BADCPU;
|
||||
|
||||
/*
|
||||
|
|
@ -3375,6 +3378,17 @@ static enum match_result matches(const struct itemplate * const itemp,
|
|||
return MOK_GOOD;
|
||||
}
|
||||
|
||||
/*
|
||||
* Recompute the list of valid instruction pattern indicies
|
||||
*/
|
||||
void asm_revalidate_cpu(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(insns_flags); i++)
|
||||
itemp_features_ok[i] = iflag_features_ok(&insns_flags[i], &cpu);
|
||||
}
|
||||
|
||||
/*
|
||||
* Select the mod part of modr/m for an memory operand with displacement.
|
||||
* zerook should be clear for the forbidden BP encodings; such instructions
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ void process_insn(insn *instruction);
|
|||
bool process_directives(char *);
|
||||
void process_pragma(char *);
|
||||
|
||||
void asm_revalidate_cpu(void);
|
||||
|
||||
/* Is this a compile-time absolute constant? */
|
||||
static inline bool op_compile_abs(const struct operand * const op)
|
||||
{
|
||||
|
|
|
|||
194
asm/directiv.c
194
asm/directiv.c
|
|
@ -52,124 +52,87 @@
|
|||
#include "listing.h"
|
||||
#include "labels.h"
|
||||
#include "iflag.h"
|
||||
|
||||
struct cpunames {
|
||||
const char *name;
|
||||
unsigned int level;
|
||||
/* Eventually a table of features */
|
||||
};
|
||||
|
||||
static void iflag_set_cpu(iflag_t *a, unsigned int lvl)
|
||||
{
|
||||
a->field[0] = 0; /* Not applicable to the CPU type */
|
||||
iflag_set_all_features(a); /* All feature masking bits set for now */
|
||||
if (lvl >= IF_ANY) {
|
||||
/* This is a hack for now */
|
||||
iflag_set(a, IF_LATEVEX);
|
||||
}
|
||||
a->field[IF_CPU_FIELD] &= ~IF_CPU_LEVEL_MASK;
|
||||
iflag_set(a, lvl);
|
||||
}
|
||||
#include "featureinfo.h"
|
||||
#include "cpunames.h"
|
||||
|
||||
void set_cpu(const char *value)
|
||||
{
|
||||
const char *p;
|
||||
char modifier;
|
||||
const struct cpunames *cpuflag;
|
||||
static const struct cpunames cpunames[] = {
|
||||
{ "default", IF_DEFAULT }, /* Must be first */
|
||||
{ "8086", IF_8086 },
|
||||
{ "186", IF_186 },
|
||||
{ "286", IF_286 },
|
||||
{ "386", IF_386 },
|
||||
{ "486", IF_486 },
|
||||
{ "586", IF_PENT },
|
||||
{ "pentium", IF_PENT },
|
||||
{ "pentiummmx", IF_PENT },
|
||||
{ "686", IF_P6 },
|
||||
{ "p6", IF_P6 },
|
||||
{ "ppro", IF_P6 },
|
||||
{ "pentiumpro", IF_P6 },
|
||||
{ "p2", IF_P6 }, /* +MMX */
|
||||
{ "pentiumii", IF_P6 },
|
||||
{ "p3", IF_KATMAI },
|
||||
{ "katmai", IF_KATMAI },
|
||||
{ "p4", IF_WILLAMETTE },
|
||||
{ "willamette", IF_WILLAMETTE },
|
||||
{ "prescott", IF_PRESCOTT },
|
||||
{ "x64", IF_X86_64 },
|
||||
{ "x86-64", IF_X86_64 },
|
||||
{ "ia64", IF_IA64 },
|
||||
{ "ia-64", IF_IA64 },
|
||||
{ "itanium", IF_IA64 },
|
||||
{ "itanic", IF_IA64 },
|
||||
{ "merced", IF_IA64 },
|
||||
{ "nehalem", IF_NEHALEM },
|
||||
{ "westmere", IF_WESTMERE },
|
||||
{ "sandybridge", IF_SANDYBRIDGE },
|
||||
{ "ivybridge", IF_FUTURE },
|
||||
{ "any", IF_ANY },
|
||||
{ "all", IF_ANY },
|
||||
{ "latevex", IF_LATEVEX },
|
||||
{ "apx", IF_APX },
|
||||
{ "evex", IF_EVEX },
|
||||
{ "vex", IF_VEX },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
if (!value) {
|
||||
iflag_set_cpu(&cpu, cpunames[0].level);
|
||||
return;
|
||||
}
|
||||
if (!value)
|
||||
value = "default";
|
||||
|
||||
p = value;
|
||||
modifier = '+';
|
||||
while (*p) {
|
||||
int len = strcspn(p, " ,");
|
||||
|
||||
while (len && (*p == '+' || *p == '-' || *p == '*')) {
|
||||
modifier = 0;
|
||||
while (*(p = nasm_skip_spaces(p))) {
|
||||
if (*p == '+' || *p == '-' || *p == '*' || *p == '^' || *p == ',') {
|
||||
modifier = *p++;
|
||||
len--;
|
||||
if (!len && modifier == '*')
|
||||
cpu = cmd_cpu;
|
||||
continue;
|
||||
}
|
||||
|
||||
int len = strcspn(p, " ,+-*^");
|
||||
if (!len && modifier == '*') {
|
||||
cpu = cmd_cpu;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
const struct cpu_feature_info *feat = NULL;
|
||||
bool invert_flag = false;
|
||||
|
||||
if (len >= 3 && !nasm_memicmp(p, "no", 2)) {
|
||||
if (len >= 2 && *p == '!') {
|
||||
invert_flag = true;
|
||||
do {
|
||||
p++;
|
||||
len--;
|
||||
} while (nasm_isspace(*p));
|
||||
} else if (len >= 3 && !nasm_memicmp(p, "no", 2)) {
|
||||
invert_flag = true;
|
||||
p += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
for (cpuflag = cpunames; cpuflag->name; cpuflag++)
|
||||
if (!nasm_strnicmp(p, cpuflag->name, len))
|
||||
break;
|
||||
|
||||
if (!cpuflag->name) {
|
||||
nasm_nonfatal("unknown CPU type or flag '%.*s'", len, p);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpuflag->level >= IF_CPU_FIRST && cpuflag->level <= IF_ANY) {
|
||||
iflag_set_cpu(&cpu, cpuflag->level);
|
||||
} else {
|
||||
switch (modifier) {
|
||||
case '-':
|
||||
invert_flag = !invert_flag;
|
||||
break;
|
||||
case '*':
|
||||
invert_flag ^= iflag_test(&cmd_cpu, cpuflag->level);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (!modifier && !invert_flag) {
|
||||
/* Search list of known CPUs */
|
||||
array_foreach (feat, known_cpus) {
|
||||
if (!nasm_strnicmp(p, feat->name, len)) {
|
||||
iflag_set_features(&cpu, feat->deps);
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
iflag_set(&cpu, cpuflag->level);
|
||||
if (invert_flag)
|
||||
iflag_clear(&cpu, cpuflag->level);
|
||||
}
|
||||
|
||||
/* Otherwise it should be a single feature flag */
|
||||
array_foreach (feat, cpu_feature_info) {
|
||||
if (!nasm_strnicmp(p, feat->name, len))
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* Otherwise... */
|
||||
nasm_nonfatal("unknown CPU type or feature flag '%.*s'", len, p);
|
||||
return;
|
||||
|
||||
found:
|
||||
switch (modifier) {
|
||||
case '-':
|
||||
invert_flag = !invert_flag;
|
||||
break;
|
||||
case '*':
|
||||
case '^':
|
||||
invert_flag ^= iflag_test_feature(&cmd_cpu, feat->num);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (invert_flag)
|
||||
iflag_del_feature(&cpu, feat->num);
|
||||
else
|
||||
iflag_add_feature(&cpu, feat->num);
|
||||
|
||||
next:
|
||||
modifier = '+';
|
||||
}
|
||||
p += len;
|
||||
if (!*p)
|
||||
|
|
@ -181,27 +144,24 @@ void set_cpu(const char *value)
|
|||
static int get_bits(const char *value)
|
||||
{
|
||||
int i = atoi(value);
|
||||
if (!i)
|
||||
return globalbits;
|
||||
|
||||
switch (i) {
|
||||
case 16:
|
||||
break; /* Always safe */
|
||||
case 32:
|
||||
if (!iflag_cpu_level_ok(&cpu, IF_386)) {
|
||||
if (!iflag_bits_ok(&cpu, i)) {
|
||||
i = globalbits;
|
||||
|
||||
switch (i) {
|
||||
case 32:
|
||||
nasm_nonfatal("cannot specify 32-bit segment on processor below a 386");
|
||||
i = 16;
|
||||
}
|
||||
break;
|
||||
case 64:
|
||||
if (!iflag_cpu_level_ok(&cpu, IF_X86_64)) {
|
||||
break;
|
||||
case 64:
|
||||
nasm_nonfatal("cannot specify 64-bit segment on processor below an x86-64");
|
||||
i = 16;
|
||||
break;
|
||||
default:
|
||||
nasm_nonfatal("`%s' is not a valid segment size; must be 16, 32 or 64",
|
||||
value);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
nasm_nonfatal("`%s' is not a valid segment size; must be 16, 32 or 64",
|
||||
value);
|
||||
i = 16;
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
|
@ -503,6 +463,12 @@ bool process_directives(char *directive)
|
|||
|
||||
case D_CPU: /* [CPU] */
|
||||
set_cpu(value);
|
||||
if (!iflag_bits_ok(&cpu, globalbits)) {
|
||||
nasm_nonfatal("invalid CPU for %d-bit mode", globalbits);
|
||||
while (!iflag_bits_ok(&cpu, globalbits >>= 1))
|
||||
;
|
||||
}
|
||||
asm_revalidate_cpu();
|
||||
break;
|
||||
|
||||
case D_LIST: /* [LIST {+|-}] */
|
||||
|
|
|
|||
22
asm/nasm.c
22
asm/nasm.c
|
|
@ -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.
|
||||
*
|
||||
|
|
@ -1603,20 +1603,10 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
|
|||
uint64_t prev_offset_changed;
|
||||
int64_t stall_count = 0; /* Make sure we make forward progress... */
|
||||
|
||||
switch (cmd_sb) {
|
||||
case 16:
|
||||
break;
|
||||
case 32:
|
||||
if (!iflag_cpu_level_ok(&cmd_cpu, IF_386))
|
||||
nasm_fatal("command line: 32-bit segment size requires a higher cpu");
|
||||
break;
|
||||
case 64:
|
||||
if (!iflag_cpu_level_ok(&cmd_cpu, IF_X86_64))
|
||||
nasm_fatal("command line: 64-bit segment size requires a higher cpu");
|
||||
break;
|
||||
default:
|
||||
panic();
|
||||
break;
|
||||
if (!iflag_bits_ok(&cmd_cpu, cmd_sb)) {
|
||||
nasm_fatal("command line: %d-bit segment size requires a higher cpu",
|
||||
cmd_sb);
|
||||
return;
|
||||
}
|
||||
|
||||
prev_offset_changed = INT64_MAX;
|
||||
|
|
@ -1657,6 +1647,8 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
|
|||
|
||||
globalbits = cmd_sb; /* set 'bits' to command line default */
|
||||
cpu = cmd_cpu;
|
||||
asm_revalidate_cpu();
|
||||
|
||||
if (listname) {
|
||||
if (list_on_this_pass()) {
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
#include "compiler.h"
|
||||
#include "ilog2.h"
|
||||
|
||||
|
||||
#include "iflaggen.h"
|
||||
#include "featureinfo.h"
|
||||
|
||||
#define IF_GENBIT(bit) (UINT32_C(1) << ((bit) & 31))
|
||||
|
||||
|
|
@ -39,6 +39,31 @@ static inline void iflag_set_all(iflag_t *f)
|
|||
memset(f, ~0, sizeof(*f));
|
||||
}
|
||||
|
||||
static inline bool iflag_bits_ok(const iflag_t *f, int bits)
|
||||
{
|
||||
switch (bits) {
|
||||
case 16:
|
||||
return true;
|
||||
case 32:
|
||||
return iflag_test(f, IF_386);
|
||||
case 64:
|
||||
return iflag_test(f, IF_X86_64);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool iflag_features_ok(const iflag_t *have, const iflag_t *need)
|
||||
{
|
||||
uint32_t bad = 0;
|
||||
size_t i;
|
||||
|
||||
for (i = IF_FEATURE_FIELD; i < IF_FEATURE_FIELD+IF_FEATURE_NFIELDS; i++)
|
||||
bad |= need->field[i] & ~have->field[i];
|
||||
|
||||
return !bad;
|
||||
}
|
||||
|
||||
#define iflag_for_each_field(v) for ((v) = 0; (v) < IF_FIELD_COUNT; (v)++)
|
||||
|
||||
static inline int iflag_cmp(const iflag_t *a, const iflag_t *b)
|
||||
|
|
@ -91,37 +116,46 @@ IF_GEN_HELPER(xor, ^)
|
|||
#define itemp_arx(itemp) _itemp_arx((itemp)->iflag_idx)
|
||||
#define itemp_smx(itemp) _itemp_smx((itemp)->iflag_idx)
|
||||
|
||||
/*
|
||||
* IF_ANY is the highest CPU level by definition
|
||||
*/
|
||||
#define IF_CPU_LEVEL_MASK ((IFM_ANY << 1) - 1)
|
||||
|
||||
static inline int iflag_cmp_cpu(const iflag_t *a, const iflag_t *b)
|
||||
{
|
||||
return ifcomp(a->field[IF_CPU_FIELD], b->field[IF_CPU_FIELD]);
|
||||
}
|
||||
|
||||
static inline uint32_t _iflag_cpu_level(const iflag_t *a)
|
||||
{
|
||||
return a->field[IF_CPU_FIELD] & IF_CPU_LEVEL_MASK;
|
||||
}
|
||||
|
||||
static inline int iflag_cmp_cpu_level(const iflag_t *a, const iflag_t *b)
|
||||
{
|
||||
return ifcomp(_iflag_cpu_level(a), _iflag_cpu_level(b));
|
||||
}
|
||||
|
||||
/* Returns true if the CPU level is at least a certain value */
|
||||
static inline bool iflag_cpu_level_ok(const iflag_t *a, unsigned int bit)
|
||||
{
|
||||
return _iflag_cpu_level(a) >= IF_GENBIT(bit);
|
||||
}
|
||||
|
||||
static inline void iflag_set_all_features(iflag_t *a)
|
||||
static inline void iflag_set_features(iflag_t *a, const uint32_t *features)
|
||||
{
|
||||
uint32_t *p = &a->field[IF_FEATURE_FIELD];
|
||||
|
||||
memset(p, -1, IF_FEATURE_NFIELDS * sizeof(uint32_t));
|
||||
memcpy(p, features, IF_FEATURE_NFIELDS * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
static inline void iflag_clear_features(iflag_t *a)
|
||||
{
|
||||
uint32_t *p = &a->field[IF_FEATURE_FIELD];
|
||||
|
||||
memset(p, 0, IF_FEATURE_NFIELDS * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
static inline bool iflag_test_feature(const iflag_t *a, unsigned int feature)
|
||||
{
|
||||
return iflag_test(a, feature + IF_FEATURE_FIRST);
|
||||
}
|
||||
|
||||
/*
|
||||
* When ADDING a feature, enable all features that depend on it as
|
||||
* well, for user sanity. When REMOVING a feature, delete only that
|
||||
* feature bit; the instruction feature masks take care of
|
||||
* dependencies (e.g. AVX512F depends on AVX512, so if the AVX512 bit
|
||||
* is off, an AVX512F instruction will not match even if the AVX512F
|
||||
* bit is still set.)
|
||||
*/
|
||||
static inline void iflag_add_feature(iflag_t *a, unsigned int feature)
|
||||
{
|
||||
unsigned int i;
|
||||
const uint32_t *p = cpu_feature_info[feature - IF_FEATURE_FIRST].deps;
|
||||
uint32_t *q = &a->field[IF_FEATURE_FIELD];
|
||||
|
||||
for (i = 0; i < IF_FEATURE_NFIELDS; i++)
|
||||
*q++ |= *p++;
|
||||
}
|
||||
|
||||
static inline void iflag_del_feature(iflag_t *a, unsigned int feature)
|
||||
{
|
||||
iflag_clear(a, feature + IF_FEATURE_FIRST);
|
||||
}
|
||||
|
||||
static inline iflag_t _iflag_pfmask(const iflag_t *a)
|
||||
|
|
|
|||
|
|
@ -305,6 +305,12 @@ const char *filename_set_extension(const char *inname, const char *extension);
|
|||
*/
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
/*
|
||||
* Iterate over all the elements of a known sized array
|
||||
*/
|
||||
#define array_foreach(var, arr) \
|
||||
for ((var) = (arr); (var) < &(arr)[ARRAY_SIZE(arr)]; (var)++)
|
||||
|
||||
/*
|
||||
* List handling
|
||||
*
|
||||
|
|
|
|||
2
x86/cpunames.c
Normal file
2
x86/cpunames.c
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#define COMPILING_CPUNAMES_C 1
|
||||
#include "cpunames.h"
|
||||
98
x86/cpunames.ph
Normal file
98
x86/cpunames.ph
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
# -*- perl -*-
|
||||
#
|
||||
# List of CPU names and their corresponding features
|
||||
# A + means include the feature set for that CPU, otherwise this
|
||||
# is the name of a base feature as defined in x86/features.ph.
|
||||
#
|
||||
|
||||
use integer;
|
||||
use strict;
|
||||
|
||||
our @cpufeatures;
|
||||
|
||||
#
|
||||
# Format:
|
||||
# c_(name, help text, feature set)
|
||||
# The feature set can include any set of CPU features as defined in
|
||||
# x86/features.ph, or "+cpu" to add all features present for "cpu"
|
||||
# (which has to be already defined in this file!), or "-feature" to
|
||||
# remove a feature.
|
||||
#
|
||||
# Dependent features (as defined in x86/x86features.ph) are automatically
|
||||
# included as well.
|
||||
#
|
||||
# a_(name, original, help text)
|
||||
# Indicate that "name" is an alias for "original"
|
||||
# If "help text" is undef then the alias is hidden from help text
|
||||
# and documentation.
|
||||
#
|
||||
# CPU and feature names are case insensitive and non-alphanumeric
|
||||
# characters ignored.
|
||||
#
|
||||
|
||||
# For legacy reasons FPU is always included
|
||||
c_("8086", "8086/8088 with optional 8087", qw(8086 8086only fpu undoc));
|
||||
c_("186", "80186/80188 with optional 8087", qw(+8086 -8086only 186));
|
||||
c_("286", "80286 with optional 80287", qw(+186 286 286only priv));
|
||||
c_("386", "80386 with optional 80387", qw(+286 -286only 386only));
|
||||
c_("486", "Early 486 without CPUID", qw(+386 -386only smm));
|
||||
c_("486dx", "486DX/487SX including CPUID", qw(+486 cpuid));
|
||||
c_("486sx", "486SX including CPUID, no FPU", qw(+486dx -fpu));
|
||||
c_("586", "Pentium P5/P54C", qw(+486dx pent));
|
||||
a_("586", "pentium");
|
||||
a_("586", "p5");
|
||||
a_("586", "p54");
|
||||
a_("586", "p54c");
|
||||
c_("ia64", "IA64 (in x86 mode)", qw(+pent jmpe));
|
||||
a_("itanium", "ia64");
|
||||
a_("itanic", "ia64");
|
||||
a_("merced", "ia64");
|
||||
c_("pentiummmx", "Pentium MMX (P55C)", qw(+pent mmx));
|
||||
a_("p55", "pentiummmx");
|
||||
a_("p55c", "pentiummmx");
|
||||
c_("p6", "Pentium Pro", qw(+pentiumpro cmov));
|
||||
c_("pentiumpro", "Pentium Pro", qw(+pent p6 cmov));
|
||||
# Some Pentium II steppings had fxsave support in anticipation of Pentium III
|
||||
c_("pentiumii", "Pentium II", qw(+p6 mmx sysenter fxsave));
|
||||
a_("pentiumii", "pentium2");
|
||||
a_("pentiumii", "p2");
|
||||
c_("katmai", "Pentium III", qw(+pentium2 sse));
|
||||
a_("katmai", "pentiumiii");
|
||||
a_("katmai", "pentium3");
|
||||
a_("katmai", "p3");
|
||||
c_("pentiumm", "Pentium M", qw(+katmai sse2));
|
||||
a_("pentiumm", "pm");
|
||||
a_("pentiumm", "centrino");
|
||||
# c_("k6", "AMD K6", qw(+pentiumii syscall 3dnow));
|
||||
# c_("k7", "AMD K7 (Athlon)", qw(+katmai syscall 3dnow));
|
||||
c_("willamette", "Intel Willamette", qw(+katmai sse2 willamette));
|
||||
a_("willamette", "pentium4");
|
||||
c_("prescott", "Intel Prescott", qw(+willamette prescott sse3));
|
||||
# For historical reasons this includes LOCKREX
|
||||
c_("x86-64-v1", "x86-64 level 1", qw(+willamette x86-64 sse2 lockrex));
|
||||
a_("x86-64-v1", "x64-1");
|
||||
# Legacy definition
|
||||
c_("x86-64", "Early x86-64 CPUs", qw(+x86-64-v1 cx16 lahf_lm sse3));
|
||||
a_("x64", "x86-64");
|
||||
c_("x86-64-v2", "x86-64 level 2", qw(+x86-64-v1 cx16 lahf_lm popcnt sse4.2"));
|
||||
a_("x86-64-v2", "x64-2");
|
||||
c_("x86-64-v3", "x86-64 level 3", qw(+x86-64-v2 avx2 vmi2 f16c lzcnt movbe xsave));
|
||||
a_("x86-64-v3", "x64-3");
|
||||
c_("x86-64-v4", "x86-64 level 4", qw(+x86-64-v3 avx512f avx512bw avx512cd avx512dq avx512vl));
|
||||
a_("x86-64-v4", "x64-4");
|
||||
c_("core2", qw(+x86-64-v1 +prescott cx16 lahf_lm ssse3));
|
||||
c_("nehalem", "Intel Nehalem", qw(+core2 nehalem sse4.2 popcnt));
|
||||
a_("nehalem", "corei7");
|
||||
c_("westmere", "Intel Westmere", qw(+nehalem westmere pclmul));
|
||||
c_("sandybridge", "Intel Sandy Bridge", qw(+westmere sandybridge avx xsave));
|
||||
c_("ivybridge", "Intel Ivy Bridge", qw(+sandybridge fsgsbase rdrand f16c));
|
||||
c_("haswell", "Intel Haswell", qw(+ivybridge avx2 bmi1 bmi2 lzcnt fma movbe hle));
|
||||
c_("broadwell", "Intel Broadwell", qw(+haswell rdseed adcx prefetchw));
|
||||
c_("skylake", "Intel Skylake", qw(+broadwell aes clflushopt xsavec xsaves sgx));
|
||||
|
||||
c_('any', "Enable all known CPU features",
|
||||
map { $_->{'name'} } @cpufeatures);
|
||||
a_("any", "all");
|
||||
c_("default", "Default CPU feature set", qw(+any -superceded -lateavx));
|
||||
|
||||
1;
|
||||
136
x86/cpunames.pl
Normal file
136
x86/cpunames.pl
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
#!/usr/bin/perl
|
||||
#
|
||||
# Create a list of CPU names and their corresponding CPU feature
|
||||
# flags. These are different from the corresponding feature flags in that:
|
||||
# a) their names can overlap with instruction flags.
|
||||
# b) they are never used for removal.
|
||||
#
|
||||
# These are usually used standalone to set the feature set to a
|
||||
# corresponding CPU.
|
||||
#
|
||||
|
||||
use integer;
|
||||
use strict;
|
||||
|
||||
require 'x86/x86features.ph';
|
||||
|
||||
our @cpufeatures;
|
||||
our %cpufeature;
|
||||
our $cpufeature_words;
|
||||
|
||||
my %cpu;
|
||||
my @cpus;
|
||||
|
||||
sub empty_mask() {
|
||||
return [(0) x $cpufeature_words];
|
||||
}
|
||||
|
||||
sub or_mask($$) {
|
||||
my($a, $b) = @_;
|
||||
my @c;
|
||||
|
||||
die if (scalar(@$a) != scalar(@$b));
|
||||
|
||||
for (my $i = 0; $i < scalar(@$a); $i++) {
|
||||
$a->[$i] |= $b->[$i];
|
||||
}
|
||||
|
||||
return $a;
|
||||
}
|
||||
|
||||
sub clear_bit($$) {
|
||||
my($mask, $bit) = @_;
|
||||
|
||||
$mask->[$bit >> 5] &= ~(1 << ($bit & 31));
|
||||
return $mask;
|
||||
}
|
||||
|
||||
my $all_vendors = empty_mask();
|
||||
foreach my $feat (@cpufeatures) {
|
||||
if ($feat->{'vendor'}) {
|
||||
or_mask($all_vendors, $feat->{'depmask'});
|
||||
}
|
||||
}
|
||||
|
||||
# CPU definition
|
||||
sub c_($$@) {
|
||||
my($name, $help, @features) = @_;
|
||||
|
||||
$name = lc($name);
|
||||
|
||||
if (defined($cpu{$name})) {
|
||||
die "$0: multiple definitions of cpu $name\n";
|
||||
}
|
||||
|
||||
my $cdef = {
|
||||
'name' => $name,
|
||||
'help' => $help
|
||||
};
|
||||
|
||||
my $fm = empty_mask();
|
||||
|
||||
my $found_vendor = 0;
|
||||
|
||||
foreach my $fn (@features) {
|
||||
my $f = lc($fn);
|
||||
my $feat;
|
||||
my $minus = 0;
|
||||
if ($f =~ s/^\+//) {
|
||||
$feat = $cpu{$f};
|
||||
} else {
|
||||
$minus = ($f =~ s/^\-//);
|
||||
$feat = $cpufeature{$f};
|
||||
}
|
||||
if (!defined($feat)) {
|
||||
die "$0: unknown feature in cpu $name: $fn\n";
|
||||
}
|
||||
|
||||
$found_vendor |= $feat->{'vendor'};
|
||||
|
||||
if ($minus) {
|
||||
clear_bit($fm, $feat->{'num'});
|
||||
} else {
|
||||
or_mask($fm, $feat->{'depmask'});
|
||||
}
|
||||
}
|
||||
|
||||
if (!$found_vendor) {
|
||||
or_mask($fm, $all_vendors);
|
||||
}
|
||||
|
||||
$cdef->{'depmask'} = $fm;
|
||||
push(@cpus, $cdef);
|
||||
$cpu{$name} = $cdef;
|
||||
}
|
||||
|
||||
# CPU alias (implement this later)
|
||||
sub a_($$;$) { }
|
||||
|
||||
require 'x86/cpunames.ph';
|
||||
|
||||
my($outfile) = @ARGV;
|
||||
|
||||
open(my $out, '>', $outfile) or die "$0: $outfile: $!\n";
|
||||
|
||||
print $out "#ifndef X86_CPUNAMES_H\n";
|
||||
print $out "#define X86_CPUNAMES_H 1\n\n";
|
||||
|
||||
print $out "#include \"featureinfo.h\"\n\n";
|
||||
|
||||
printf $out "extern const struct cpu_feature_info known_cpus[%d];\n\n",
|
||||
scalar(@cpus);
|
||||
|
||||
print $out "#endif\n\n";
|
||||
print $out "#ifdef COMPILING_CPUNAMES_C\n\n";
|
||||
|
||||
printf $out "const struct cpu_feature_info known_cpus[%d] = {\n",
|
||||
scalar(@cpus);
|
||||
|
||||
foreach my $cpu (@cpus) {
|
||||
printf $out " { \"%s\", \"%s\", -1U, {%s} },\n",
|
||||
$cpu->{'name'},
|
||||
$cpu->{'help'},
|
||||
join(',', map { sprintf('0x%08x', $_) } @{$cpu->{'depmask'}});
|
||||
}
|
||||
print $out "};\n\n";
|
||||
print $out "#endif\n";
|
||||
2
x86/featureinfo.c
Normal file
2
x86/featureinfo.c
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#define COMPILING_FEATUREINFO_C 1
|
||||
#include "featureinfo.h"
|
||||
51
x86/featureinfo.pl
Executable file
51
x86/featureinfo.pl
Executable file
|
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/perl
|
||||
#
|
||||
# Generate CPU feature dependency bitmasks
|
||||
#
|
||||
|
||||
use integer;
|
||||
use strict;
|
||||
|
||||
require 'x86/x86features.ph';
|
||||
|
||||
our @cpufeatures;
|
||||
our $cpufeature_words;
|
||||
|
||||
my($outfile) = @ARGV;
|
||||
|
||||
open(my $out, '>', $outfile) or die "$0: $outfile: $!\n";
|
||||
|
||||
print $out "#ifndef X86_FEATUREINFO_H\n";
|
||||
print $out "#define X86_FEATUREINFO_H 1\n\n";
|
||||
|
||||
print $out "#include \"compiler.h\"\n\n";
|
||||
|
||||
print $out "struct cpu_feature_info {\n";
|
||||
print $out " const char \*name;\n";
|
||||
print $out " const char \*help;\n";
|
||||
print $out " unsigned int num;\n";
|
||||
print $out " uint32_t deps[$cpufeature_words];\n";
|
||||
print $out "};\n\n";
|
||||
|
||||
printf $out "extern const struct cpu_feature_info cpu_feature_info[%d];\n\n",
|
||||
scalar(@cpufeatures);
|
||||
|
||||
printf $out "#endif\n\n";
|
||||
|
||||
print $out "#ifdef COMPILING_FEATUREINFO_C\n\n";
|
||||
|
||||
printf $out "const struct cpu_feature_info cpu_feature_info[%d] = {\n",
|
||||
scalar(@cpufeatures);
|
||||
|
||||
foreach my $feat (@cpufeatures) {
|
||||
printf $out " { %-15s \"%s\", %d, {%s} },\n",
|
||||
'"'.$feat->{'name'}.'",',
|
||||
$feat->{'help'},
|
||||
$feat->{'num'},
|
||||
join(',', map { sprintf('0x%08x', $_) } @{$feat->{'depmask'}});
|
||||
}
|
||||
print $out "};\n\n";
|
||||
|
||||
print $out "#endif\n";
|
||||
|
||||
close($out);
|
||||
137
x86/features.ph
Normal file
137
x86/features.ph
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
|
||||
f_("VEX", "VEX or XOP encoded instruction");
|
||||
f_("EVEX", "EVEX encoded instruction", qw(PROT));
|
||||
|
||||
#
|
||||
# Encoding formats that can be set with the CPU directive
|
||||
#
|
||||
#
|
||||
# Modes and attributes
|
||||
#
|
||||
f_("OBSOLETE", "Instruction removed from architecture");
|
||||
f_("NEVER", "Instruction never implemented", qw(obsolete));
|
||||
f_("NOP", "Non-explicit noop instructions");
|
||||
f_("PRIV", "Privileged instruction", qw(prot));
|
||||
f_("PROT", "Protected mode only");
|
||||
f_("SMM", "System management mode only");
|
||||
f_("LONG", "Long mode only", qw(x86-64));
|
||||
f_("VIRTUAL", "Virtual instructions");
|
||||
f_("UNDOC", "Undocumented instructions");
|
||||
f_("VENDOR", "Vendor-specific instructions");
|
||||
f_("SUPERCEDED", "Instruction opcode has been reused");
|
||||
f_("APX", "Advanced Performance Extensions", qw(long));
|
||||
f_("APX_F", "Advanced Performance Extensions (APX) base set");
|
||||
|
||||
f_("FPU", "x87 floating-point instructions");
|
||||
f_("MMX", "MMX", qw(FPU));
|
||||
f_("MMXEXT", "MMX extension SSE subset", qw(MMX));
|
||||
f_("3DNOW", "3DNow!", qw(MMXEXT));
|
||||
f_("SSE", "SSE (KNI, MMX2)", qw(MMXEXT));
|
||||
f_("SSE2", "SSE2", qw(SSE));
|
||||
f_("SSE3", "SSE3 (PNI)", qw(SSE2));
|
||||
f_("VMX", "VMX");
|
||||
f_("SSSE3", "SSSE3", qw(SSE3));
|
||||
f_("SSE4A", "AMD SSE4a", qw(SSE3));
|
||||
f_("SSE4.1", "SSE4.1", qw(SSSE3));
|
||||
f_("SSE4.2", "SSE4.2", qw(SSE4.1));
|
||||
f_("SSE5", "SSE5", qw(SSE4.2));
|
||||
f_("LAHF_LM", "LAHF/SAHF in long mode");
|
||||
f_("LOCKREX", "LOCK as REX.R in 16/32-bit mode");
|
||||
f_("CX16", "CMPXCHG16B");
|
||||
f_("AVX", "AVX (256-bit floating point)", qw(VEX SSSE3));
|
||||
f_("AVX2", "AVX2 (256-bit integer)", qw(AVX));
|
||||
f_("FMA", "Fused multiply-add", qw(AVX));
|
||||
f_("BMI1", "Bit manipulation instructions 1");
|
||||
f_("BMI2", "Bit manipulation instructions 2", qw(bmi1));
|
||||
f_("TBM", "");
|
||||
f_("RTM", "");
|
||||
f_("AVX512", "AVX-512 instructions");
|
||||
f_("AVX512F", "AVX-512F (base architecture)", qw(EVEX));
|
||||
f_("AVX512CD", "AVX-512 Conflict Detection", qw(AVX512F));
|
||||
f_("AVX512ER", "AVX-512 Exponential and Reciprocal", qw(AVX512F));
|
||||
f_("AVX512PF", "AVX-512 Prefetch");
|
||||
f_("MPX", "Memory protection extension", qw(obsolete));
|
||||
f_("SHA", "SHA instructions");
|
||||
f_("AVX512VL", "AVX-512 Vector Length Orthogonality", qw(AVX512F));
|
||||
f_("AVX512DQ", "AVX-512 Dword and Qword", qw(AVX512F));
|
||||
f_("AVX512BW", "AVX-512 Byte and Word", qw(AVX512F));
|
||||
f_("AVX512IFMA", "AVX-512 IFMA instructions");
|
||||
f_("AVX512VBMI", "AVX-512 VBMI instructions");
|
||||
f_("AES", "AES instructions");
|
||||
f_("VAES", "AES AVX instructions", qw(AES AVX));
|
||||
f_("VPCLMULQDQ", "AVX Carryless Multiplication");
|
||||
f_("GFNI", "Galois Field instructions");
|
||||
f_("AVX512VBMI2", "AVX-512 VBMI2 instructions");
|
||||
f_("AVX512VNNI", "AVX-512 VNNI instructions");
|
||||
f_("AVX512BITALG", "AVX-512 Bit Algorithm instructions");
|
||||
f_("AVX512VPOPCNTDQ", "AVX-512 VPOPCNTD/VPOPCNTQ");
|
||||
f_("AVX5124FMAPS", "AVX-512 4-iteration multiply-add");
|
||||
f_("AVX5124VNNIW", "AVX-512 4-iteration dot product");
|
||||
f_("AVX512FP16", "AVX-512 FP16 instructions");
|
||||
f_("AVX512FC16", "AVX-512 FC16 instructions");
|
||||
f_("SGX", "Intel Software Guard Extensions (SGX)");
|
||||
f_("CET", "Intel Control-Flow Enforcement Technology (CET)");
|
||||
f_("ENQCMD", "Enqueue command instructions");
|
||||
f_("TSXLDTRK", "TSX suspend load address tracking");
|
||||
f_("AVX512BF16", "AVX-512 bfloat16");
|
||||
f_("AVX512VP2INTERSECT", "AVX-512 VP2INTERSECT instructions");
|
||||
f_("AMXTILE", "AMX tile configuration instructions", qw(AMXTILE));
|
||||
f_("AMXBF16", "AMX bfloat16 multiplication", qw(AMXTILE));
|
||||
f_("AMXINT8", "AMX 8-bit integer multiplication", qw(AMXTILE));
|
||||
f_("FRED", "Flexible Return and Exception Delivery (FRED)", qw(lkgs));
|
||||
f_("RAOINT", "Remote atomic operations (RAO-INT)");
|
||||
f_("UINTR", "User interrupts");
|
||||
f_("CMPCCXADD", "CMPccXADD instructions");
|
||||
f_("PREFETCHI", "PREFETCHI0 and PREFETCHI1 instructions");
|
||||
f_("MSRLIST", "RDMSRLIST and WRMSRLIST instructions");
|
||||
f_("AVXNECONVERT", "AVX exceptionless floating-point conversions");
|
||||
f_("AVXVNNIINT8", "AVX Vector Neural Network 8-bit integer instructions");
|
||||
f_("AVXIFMA", "AVX integer multiply and add");
|
||||
f_("LATEAVX", "Instructions first added as EVEX encoded; VEX added later");
|
||||
f_("HRESET", "History reset");
|
||||
f_("SMAP", "Supervisor Mode Access Prevention (SMAP)");
|
||||
f_("SHA512", "SHA512 instructions");
|
||||
f_("HSM3", "SM3 hash instructions");
|
||||
f_("HSM4", "SM4 hash instructions");
|
||||
f_("AVX10.1", "AVX 10.1 instructions", qw(avx2));
|
||||
f_("AVX10.2", "AVX 10.2 instructions", qw(avx10.1));
|
||||
f_("ADX", "ADCX and ADOX instructions");
|
||||
f_("PKU", "Protection key for user mode");
|
||||
f_("MONITOR", "MONITOR and MWAIT instructions");
|
||||
f_("MONITORX", "MONITORX and MWAITX instructions");
|
||||
f_("WAITPKG", "User wait instructions package");
|
||||
|
||||
#
|
||||
# Single-instruction flags without special help text
|
||||
#
|
||||
map { f_($_) }
|
||||
qw(cpuid invpcid prefetchwt1 pconfig wbnoinvd serialize
|
||||
wrmsrns clflushopt clwb rdrand rdseed rdpid
|
||||
lzcnt ptwrite cldemote movdiri movdir64b clzero
|
||||
movbe fcomi lkgs jmpe);
|
||||
d_('rdseed', 'rdrand');
|
||||
d_('jmpe', 'virtual');
|
||||
|
||||
f_("8086only", "8086/8088 only instructions", qw(8086 obsolete));
|
||||
f_("286only", "80286 only instructions", qw(286 obsolete));
|
||||
f_("386only", "80386 only instructions", qw(386 obsolete));
|
||||
|
||||
f_("8087", "8087 floating-point instructions", qw(8086 fpu));
|
||||
f_("287", "80287 floating-point instructions", qw(286 fpu));
|
||||
f_("387", "80387 floating-point instructions", qw(386 fpu));
|
||||
|
||||
f_("8086", "8086/8088 base features");
|
||||
f_("186", "80186/80188 base features", qw(8086));
|
||||
f_("286", "80286 base features", qw(186));
|
||||
f_("386", "80386 base features", qw(286));
|
||||
f_("486", "486 family base instructions", qw(386));
|
||||
f_("PENT", "Pentium (P5) instructions", qw(486 fpu cpuid));
|
||||
f_("P6", "P6 (Pentium Pro)", qw(pent fcomi));
|
||||
f_("KATMAI", "Katmai (Pentium III) instructions", qw(p6 mmx sse));
|
||||
f_("WILLAMETTE", "Willamette instructions", qw(katmai));
|
||||
f_("PRESCOTT", "Prescott instructions", qw(prescott));
|
||||
f_("X86-64", "x86-64 base feature set", qw(prescott fpu syscall));
|
||||
f_("NEHALEM", "Nehalem instructions", qw(x64));
|
||||
f_("WESTMERE", "Westmere instructions", qw(nehalem));
|
||||
f_("SANDYBRIDGE", "Sandy Bridge instructions", qw(westmere));
|
||||
f_("FUTURE", "Ivy Bridge or newer instructions", qw(sandybridge));
|
||||
143
x86/iflags.ph
143
x86/iflags.ph
|
|
@ -1,7 +1,8 @@
|
|||
# -*- perl -*-
|
||||
|
||||
#
|
||||
# dword bound, index 0 - specific flags
|
||||
# dword bound, index 0 - instruction generation flags;
|
||||
# not part of the instruction feature mask
|
||||
#
|
||||
if_align('IGEN', $NOBREAK);
|
||||
|
||||
|
|
@ -54,7 +55,6 @@ if_("SIB", "SIB encoding required");
|
|||
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");
|
||||
if_("MIB", "split base/index EA");
|
||||
if_("BND", "BND (0xF2) prefix available");
|
||||
|
|
@ -69,143 +69,16 @@ if_("FL", "Instruction modifies the flags");
|
|||
if_("DFV", "Destination flag values");
|
||||
|
||||
#
|
||||
# dword bound - instruction feature filtering flags
|
||||
# dword bound - instruction feature filtering flags (from x86features.ph)
|
||||
#
|
||||
if_align('FEATURE');
|
||||
|
||||
#
|
||||
# Encoding formats that can be set with the CPU directive
|
||||
#
|
||||
if_("VEX", "VEX or XOP encoded instruction");
|
||||
if_("EVEX", "EVEX encoded instruction");
|
||||
require 'x86/x86features.ph';
|
||||
|
||||
#
|
||||
# Feature filtering flags
|
||||
#
|
||||
if_("PRIV", "Privileged instruction");
|
||||
if_("SMM", "Only valid in SMM");
|
||||
if_("PROT", "Protected mode only");
|
||||
if_("UNDOC", "Undocumented");
|
||||
if_("FPU", "FPU");
|
||||
if_("MMX", "MMX");
|
||||
if_("3DNOW", "3DNow!");
|
||||
if_("SSE", "SSE (KNI, MMX2)");
|
||||
if_("SSE2", "SSE2");
|
||||
if_("SSE3", "SSE3 (PNI)");
|
||||
if_("VMX", "VMX");
|
||||
if_("SSSE3", "SSSE3");
|
||||
if_("SSE4A", "AMD SSE4a");
|
||||
if_("SSE41", "SSE4.1");
|
||||
if_("SSE42", "SSE4.2");
|
||||
if_("SSE5", "SSE5");
|
||||
if_("AVX", "AVX (256-bit floating point)");
|
||||
if_("AVX2", "AVX2 (256-bit integer)");
|
||||
if_("FMA", "Fused multiply-add");
|
||||
if_("BMI1", "Bit manipulation instructions 1");
|
||||
if_("BMI2", "Bit manipulation instructions 2");
|
||||
if_("TBM", "");
|
||||
if_("RTM", "");
|
||||
if_("AVX512", "AVX-512");
|
||||
if_("AVX512F", "AVX-512F (base architecture)");
|
||||
if_("AVX512CD", "AVX-512 Conflict Detection");
|
||||
if_("AVX512ER", "AVX-512 Exponential and Reciprocal");
|
||||
if_("AVX512PF", "AVX-512 Prefetch");
|
||||
if_("MPX", "MPX");
|
||||
if_("SHA", "SHA");
|
||||
if_("AVX512VL", "AVX-512 Vector Length Orthogonality");
|
||||
if_("AVX512DQ", "AVX-512 Dword and Qword");
|
||||
if_("AVX512BW", "AVX-512 Byte and Word");
|
||||
if_("AVX512IFMA", "AVX-512 IFMA instructions");
|
||||
if_("AVX512VBMI", "AVX-512 VBMI instructions");
|
||||
if_("AES", "AES instructions");
|
||||
if_("VAES", "AES AVX instructions");
|
||||
if_("VPCLMULQDQ", "AVX Carryless Multiplication");
|
||||
if_("GFNI", "Galois Field instructions");
|
||||
if_("AVX512VBMI2", "AVX-512 VBMI2 instructions");
|
||||
if_("AVX512VNNI", "AVX-512 VNNI instructions");
|
||||
if_("AVX512BITALG", "AVX-512 Bit Algorithm instructions");
|
||||
if_("AVX512VPOPCNTDQ", "AVX-512 VPOPCNTD/VPOPCNTQ");
|
||||
if_("AVX5124FMAPS", "AVX-512 4-iteration multiply-add");
|
||||
if_("AVX5124VNNIW", "AVX-512 4-iteration dot product");
|
||||
if_("AVX512FP16", "AVX-512 FP16 instructions");
|
||||
if_("AVX512FC16", "AVX-512 FC16 instructions");
|
||||
if_("SGX", "Intel Software Guard Extensions (SGX)");
|
||||
if_("CET", "Intel Control-Flow Enforcement Technology (CET)");
|
||||
if_("ENQCMD", "Enqueue command instructions");
|
||||
if_("TSXLDTRK", "TSX suspend load address tracking");
|
||||
if_("AVX512BF16", "AVX-512 bfloat16");
|
||||
if_("AVX512VP2INTERSECT", "AVX-512 VP2INTERSECT instructions");
|
||||
if_("AMXTILE", "AMX tile configuration instructions");
|
||||
if_("AMXBF16", "AMX bfloat16 multiplication");
|
||||
if_("AMXINT8", "AMX 8-bit integer multiplication");
|
||||
if_("FRED", "Flexible Return and Exception Delivery (FRED)");
|
||||
if_("RAOINT", "Remote atomic operations (RAO-INT)");
|
||||
if_("UINTR", "User interrupts");
|
||||
if_("CMPCCXADD", "CMPccXADD instructions");
|
||||
if_("PREFETCHI", "PREFETCHI0 and PREFETCHI1");
|
||||
if_("MSRLIST", "RDMSRLIST and WRMSRLIST");
|
||||
if_("AVXNECONVERT", "AVX exceptionless floating-point conversions");
|
||||
if_("AVXVNNIINT8", "AVX Vector Neural Network 8-bit integer instructions");
|
||||
if_("AVXIFMA", "AVX integer multiply and add");
|
||||
if_("HRESET", "History reset");
|
||||
if_("SMAP", "Supervisor Mode Access Prevention (SMAP)");
|
||||
if_("SHA512", "SHA512 instructions");
|
||||
if_("HSM3", "SM3 hash instructions");
|
||||
if_("HSM4", "SM4 hash instructions");
|
||||
if_("APX", "Advanced Performance Extensions (APX)");
|
||||
if_("AVX10_1", "AVX 10.1 instructions");
|
||||
if_("AVX10_2", "AVX 10.2 instructions");
|
||||
if_("ADX", "ADCX and ADOX instructions");
|
||||
if_("PKU", "Protection key for user mode");
|
||||
if_("MONITOR", "MONITOR and MWAIT");
|
||||
if_("MONITORX", "MONITORX and MWAITX");
|
||||
if_("WAITPKG", "User wait instruction package");
|
||||
our @cpufeatures;
|
||||
|
||||
# Single-instruction CPUID bits without additional help text
|
||||
my @oneins = qw(invpcid prefetchwt1 pconfig wbnoinvd serialize lkgs
|
||||
wrmsrns clflushopt clwb rdrand rdseed rdpid
|
||||
lzcnt ptwrite cldemote movdiri movdir64b clzero
|
||||
movbe);
|
||||
foreach my $ins (@oneins) {
|
||||
if_($ins, "\U$ins\E instruction");
|
||||
foreach my $feat (@cpufeatures) {
|
||||
if_($feat->{'cname'}, $feat->{'help'});
|
||||
}
|
||||
|
||||
# Put these last to minimize their relevance
|
||||
if_("OBSOLETE", "Instruction removed from architecture");
|
||||
if_("NEVER", "Instruction never implemented");
|
||||
if_("NOP", "Instruction is always a (nonintentional) NOP");
|
||||
|
||||
#
|
||||
# dword bound - cpu type flags
|
||||
#
|
||||
# The CYRIX and AMD flags should have the highest bit values; the
|
||||
# disassembler selection algorithm depends on it.
|
||||
#
|
||||
if_align('CPU');
|
||||
|
||||
if_("8086", "8086");
|
||||
if_("186", "186+");
|
||||
if_("286", "286+");
|
||||
if_("386", "386+");
|
||||
if_("486", "486+");
|
||||
if_("PENT", "Pentium");
|
||||
if_("P6", "P6");
|
||||
if_("KATMAI", "Katmai");
|
||||
if_("WILLAMETTE", "Willamette");
|
||||
if_("PRESCOTT", "Prescott");
|
||||
if_("IA64", "IA64 (in x86 mode)");
|
||||
if_("X86_64", "x86-64 (long or legacy mode)");
|
||||
if_("NEHALEM", "Nehalem");
|
||||
if_("WESTMERE", "Westmere");
|
||||
if_("SANDYBRIDGE", "Sandy Bridge");
|
||||
if_("FUTURE", "Ivy Bridge or newer");
|
||||
|
||||
# Default CPU level
|
||||
if_("DEFAULT", "Default CPU level");
|
||||
|
||||
# Must be the last CPU definition
|
||||
if_("ANY", "Allow any known instruction");
|
||||
|
||||
# These must come after the CPU definitions proper
|
||||
if_("CYRIX", "Cyrix-specific");
|
||||
if_("AMD", "AMD-specific");
|
||||
1;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/perl
|
||||
## --------------------------------------------------------------------------
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
|
|
@ -64,6 +64,7 @@
|
|||
# for a set of flags, so be careful moving bits (and
|
||||
# don't forget to update C code generation then).
|
||||
#
|
||||
|
||||
sub dword_align($) {
|
||||
my($n) = @_;
|
||||
|
||||
|
|
@ -71,7 +72,6 @@ sub dword_align($) {
|
|||
return $n;
|
||||
}
|
||||
|
||||
|
||||
my $n_iflags = 0;
|
||||
my %flag_byname;
|
||||
my @flag_bynum;
|
||||
|
|
|
|||
196
x86/insns.dat
196
x86/insns.dat
|
|
@ -73,7 +73,7 @@ EQU imm:imm ignore PSEUDO
|
|||
;# No operation
|
||||
; In 64-bit mode NOP (90) is technically always 64 bits, but allow "o64 nop" to generate 48 90
|
||||
NOP void [ osz norexb nof3 90] 8086
|
||||
NOP2 void [ norexb nof3 66 90] 386,ND
|
||||
NOP2 void [ norexb nof3 66 90] 386,ND,UNDOC
|
||||
$wdq NOP rm# [m: o# 0f 1f /0] P6
|
||||
|
||||
;# Integer data move instructions
|
||||
|
|
@ -237,7 +237,7 @@ $wdq MOVZXD reg#,rm32 [rm: nw o# 8b /r] 8086,OPT,ND
|
|||
;# Atomic operations
|
||||
$bwdq CMPXCHG rm#,reg# [mr: hle 0f b0# /r] PENT,SM,LOCK
|
||||
CMPXCHG8B mem64 [m: hle norexw 0f c7 /1] PENT,LOCK
|
||||
CMPXCHG16B mem128 [m: o64 0f c7 /1] X86_64,LONG,LOCK
|
||||
CMPXCHG16B mem128 [m: o64 0f c7 /1] CX16,LONG,LOCK
|
||||
|
||||
$bwdq XADD rm#,reg# [mr: hle o# 0f c0# /r] 486,SM,LOCK
|
||||
|
||||
|
|
@ -294,12 +294,6 @@ $wdq LOOPNE imm8|near|short,cx# [i-: a# nw e0 rel8] 8086,NOAPX
|
|||
$wdq LOOPZ imm8|near|short,cx# [i-: a# nw e1 rel8] 8086,NOAPX,ND
|
||||
$wdq LOOPNZ imm8|near|short,cx# [i-: a# nw e0 rel8] 8086,NOAPX,ND
|
||||
|
||||
; JMPE is obsolete, but seems to be used by a fair number of virtual environments?
|
||||
$zwdq JMPE imm##|near [i: nw o# 0f b8 rel] IA64
|
||||
; 0f 00 /6 with a prefix has been repurposed in long mode
|
||||
$wdq JMPE rm#|near [m: nw o# np 0f 00 /6] IA64
|
||||
$wd JMPE rm#|near [m: o# 0f 00 /6] IA64,NOLONG
|
||||
|
||||
;# Call and return
|
||||
$wdq CALL imm##|near [i: nw o# e8 rel] 8086,BND,NOAPX,OSIZE
|
||||
$wd CALL imm#|far [i: o# 9a iwd seg] 8086,ND,NOLONG,OSIZE
|
||||
|
|
@ -327,17 +321,22 @@ INT03 void [ cc] 8086,ND
|
|||
BRKPT void [ cc] 8086,ND
|
||||
INTO void [ ce] 8086,NOLONG
|
||||
|
||||
SYSCALL void [ 0f 05] P6,AMD
|
||||
SYSENTER void [ 0f 34] P6,NOAPX
|
||||
|
||||
SYSEXIT void [ 0f 35] P6,PRIV,NOAPX
|
||||
SYSCALL void [ 0f 05] SYSCALL,AMD
|
||||
SYSRET void [ 0f 07] P6,PRIV,AMD
|
||||
SYSENTER void [ 0f 34] SYSENTER,NOAPX
|
||||
SYSEXIT void [ 0f 35] SYSENTER,PRIV,NOAPX
|
||||
|
||||
$zwdq IRET% void [ o# cf] 8086
|
||||
|
||||
ERETS void [ f2 0f 01 ca ] FRED,PRIV,LONG
|
||||
ERETU void [ f3 0f 01 ca ] FRED,PRIV,LONG
|
||||
|
||||
;# Jump to Emulator
|
||||
$zwdq JMPE imm##|near [i: nw o# 0f b8 rel] JMPE
|
||||
; 0f 00 /6 with a prefix has been repurposed in long mode
|
||||
$wdq JMPE rm#|near [m: nw o# np 0f 00 /6] JMPE
|
||||
$wd JMPE rm#|near [m: o# 0f 00 /6] JMPE,NOLONG
|
||||
|
||||
;# Flag register instructions
|
||||
CLC void [ f8] 8086
|
||||
CLD void [ fc] 8086
|
||||
|
|
@ -351,9 +350,11 @@ STAC void [ np 0f 01 cb] SMAP,PRIV
|
|||
|
||||
CMC void [ f5] 8086
|
||||
|
||||
LAHF void [ 9f] 8086
|
||||
SAHF void [ 9e] 8086
|
||||
SALC void [ d6] 8086,UNDOC
|
||||
LAHF void [ 9f] 8086,NOLONG
|
||||
SAHF void [ 9e] 8086,NOLONG
|
||||
LAHF void [ 9f] LONG,LAHF_LM
|
||||
SAHF void [ 9e] LONG,LAHF_LM
|
||||
SALC void [ d6] 8086,NOLONG,UNDOC
|
||||
|
||||
$zwdq PUSHF% void [ nw o# 9c] 8086
|
||||
$zwdq POPF% void [ nw o# 9d] 8086
|
||||
|
|
@ -368,22 +369,22 @@ $bwd INS% void [ o# 6c#] 186
|
|||
$bwd OUTS% void [ o# 6e#] 186
|
||||
|
||||
;# Synchronization and fencing
|
||||
LFENCE void [ np 0f ae e8] X86_64,LONG,AMD
|
||||
MFENCE void [ np 0f ae f0] X86_64,LONG,AMD
|
||||
SFENCE void [ np 0f ae f8] X86_64,LONG,AMD
|
||||
SERIALIZE void [ np 0f 01 e8] SERIALIZE
|
||||
LFENCE void [ np 0f ae e8] SSE2
|
||||
MFENCE void [ np 0f ae f0] SSE2
|
||||
SFENCE void [ np 0f ae f8] KATMAI
|
||||
|
||||
;# Memory management and control
|
||||
CLFLUSH mem [m: np 0f ae /7] WILLAMETTE,SSE2
|
||||
;# Cache and TLB management and control
|
||||
CLFLUSH mem [m: np 0f ae /7] SSE2
|
||||
CLFLUSHOPT mem [m: 66 0f ae /7] CLFLUSHOPT
|
||||
CLWB mem [m: 66 0f ae /6] CLWB
|
||||
|
||||
; This one was killed before it saw the light of day
|
||||
PCOMMIT void [ 66 0f ae f8] NEVER,NOP
|
||||
PCOMMIT void [ 66 0f ae f8] NEVER,OBSOLETE,NOP
|
||||
|
||||
; AMD Zen v1
|
||||
$wdq CLZERO ax# [-: a# 0f 01 fc] AMD,CLZERO
|
||||
CLZERO void [ 0f 01 fc] AMD,CLZERO,ND
|
||||
$wdq CLZERO ax# [-: a# 0f 01 fc] CLZERO
|
||||
CLZERO void [ 0f 01 fc] CLZERO,ND
|
||||
|
||||
INVD void [ 0f 08] 486,PRIV
|
||||
WBINVD void [ np 0f 09] 486,PRIV
|
||||
|
|
@ -436,7 +437,7 @@ CPU_WRITE void [ m1 3c] PENT,NOLONG,CYRIX,OBSOLETE,ND
|
|||
DMINT void [ m1 39] P6,NOLONG,CYRIX,NOAPX,OBSOLETE,ND
|
||||
RDM void [ 0f 3a] P6,CYRIX,ND,NOLONG,OBSOLETE
|
||||
SMINT void [ m1 38] P6,CYRIX,ND,NOLONG,OBSOLETE
|
||||
SMINTOLD void [ m1 7e] 486,CYRIX,ND,NOLONG,,OBSOLETE
|
||||
SMINTOLD void [ m1 7e] 486,CYRIX,ND,NOLONG,OBSOLETE
|
||||
|
||||
;# System management mode
|
||||
RSM void [ 0f aa] PENT,SMM
|
||||
|
|
@ -496,7 +497,7 @@ $wdq LSS reg#,mem# [rm: o# 0f b2 /r] 386,SM
|
|||
PUSH reg_gs [-: 0f a8] 386
|
||||
|
||||
POP reg_es [-: 07] 8086,NOLONG
|
||||
POP reg_cs [-: m0 0f] 8086,NOLONG,UNDOC,ND,OBSOLETE
|
||||
POP reg_cs [-: m0 0f] 8086ONLY,NOLONG,SUPERCEDED
|
||||
POP reg_ss [-: 17] 8086,NOLONG
|
||||
POP reg_ds [-: 1f] 8086,NOLONG
|
||||
POP reg_fs [-: 0f a1] 386
|
||||
|
|
@ -528,8 +529,8 @@ $dq SIDT mem# [m: nw o# 0f 01 /1] 286
|
|||
$zwdq SLDT sel# [m: optd# 0f 00 /0] 286,PROT
|
||||
$zwdq STR sel# [m: optd# 0f 00 /1] 286,PROT
|
||||
|
||||
LOADALL void [ 0f 07] 386,UNDOC,ND,OBSOLETE
|
||||
LOADALL286 void [ 0f 05] 286,UNDOC,ND,OBSOLETE
|
||||
LOADALL void [ 0f 07] 386ONLY,UNDOC,OBSOLETE,SUPERCEDED
|
||||
LOADALL286 void [ 0f 05] 286ONLY,UNDOC,OBSOLETE,SUPERCEDED
|
||||
|
||||
;# x87 floating point
|
||||
F2XM1 void [ d9 f0] 8086,FPU
|
||||
|
|
@ -1048,7 +1049,6 @@ PREFETCHT1 mem8 [m: 0f 18 /2] KATMAI,SB
|
|||
PREFETCHT2 mem8 [m: 0f 18 /3] KATMAI,SB
|
||||
PREFETCHIT0 mem8 [m: 0f 18 /7] PREFETCHI,SB
|
||||
PREFETCHIT1 mem8 [m: 0f 18 /6] PREFETCHI,SB
|
||||
SFENCE void [ np 0f ae f8] KATMAI
|
||||
|
||||
;# New MMX instructions introduced in Katmai
|
||||
MASKMOVQ mmxreg,mmxreg [rm: np 0f f7 /r] KATMAI,MMX
|
||||
|
|
@ -1083,8 +1083,6 @@ MOVNTDQ mem,xmmreg [mr: 66 0f e7 /r] WILLAMETTE,SSE2,SO
|
|||
MOVNTI mem,reg32 [mr: np 0f c3 /r] WILLAMETTE,SD
|
||||
MOVNTI mem,reg64 [mr: o64 np 0f c3 /r] X86_64,LONG,SQ
|
||||
MOVNTPD mem,xmmreg [mr: 66 0f 2b /r] WILLAMETTE,SSE2,SO
|
||||
LFENCE void [ np 0f ae e8] WILLAMETTE,SSE2
|
||||
MFENCE void [ np 0f ae f0] WILLAMETTE,SSE2
|
||||
|
||||
;# Willamette MMX instructions (SSE2 SIMD Integer Instructions)
|
||||
MOVD mem,xmmreg [mr: 66 norexw 0f 7e /r] WILLAMETTE,SSE2,SD
|
||||
|
|
@ -1352,77 +1350,77 @@ MOVNTSS mem32,xmmreg [mr: f3 0f 2b /r] SSE4A,AMD,SD
|
|||
;# New instructions in Barcelona
|
||||
|
||||
;# Penryn New Instructions (SSE4.1)
|
||||
BLENDPD xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 0d /r ib,u] SSE41
|
||||
BLENDPS xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 0c /r ib,u] SSE41
|
||||
BLENDVPD xmmreg,xmmrm128,xmm0 [rm-: 66 0f38 15 /r] SSE41
|
||||
BLENDVPD xmmreg,xmmrm128 [rm: 66 0f38 15 /r] SSE41
|
||||
BLENDVPS xmmreg,xmmrm128,xmm0 [rm-: 66 0f38 14 /r] SSE41
|
||||
BLENDVPS xmmreg,xmmrm128 [rm: 66 0f38 14 /r] SSE41
|
||||
DPPD xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 41 /r ib,u] SSE41
|
||||
DPPS xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 40 /r ib,u] SSE41
|
||||
EXTRACTPS rm32,xmmreg,imm8 [mri: 66 0f3a 17 /r ib,u] SSE41
|
||||
EXTRACTPS reg64,xmmreg,imm8 [mri: o64 66 0f3a 17 /r ib,u] SSE41,X86_64,LONG
|
||||
INSERTPS xmmreg,xmmrm32,imm8 [rmi: 66 0f3a 21 /r ib,u] SSE41
|
||||
MOVNTDQA xmmreg,mem128 [rm: 66 0f38 2a /r] SSE41
|
||||
MPSADBW xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 42 /r ib,u] SSE41
|
||||
PACKUSDW xmmreg,xmmrm128 [rm: 66 0f38 2b /r] SSE41
|
||||
PBLENDVB xmmreg,xmmrm,xmm0 [rm-: 66 0f38 10 /r] SSE41
|
||||
PBLENDVB xmmreg,xmmrm128 [rm: 66 0f38 10 /r] SSE41
|
||||
PBLENDW xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 0e /r ib,u] SSE41
|
||||
PCMPEQQ xmmreg,xmmrm128 [rm: 66 0f38 29 /r] SSE41
|
||||
PEXTRB reg32,xmmreg,imm8 [mri: 66 0f3a 14 /r ib,u] SSE41
|
||||
PEXTRB mem8,xmmreg,imm8 [mri: 66 0f3a 14 /r ib,u] SSE41
|
||||
PEXTRB reg64,xmmreg,imm8 [mri: o64nw 66 0f3a 14 /r ib,u] SSE41,X86_64,LONG
|
||||
PEXTRD rm32,xmmreg,imm8 [mri: norexw 66 0f3a 16 /r ib,u] SSE41
|
||||
PEXTRQ rm64,xmmreg,imm8 [mri: o64 66 0f3a 16 /r ib,u] SSE41,X86_64,LONG
|
||||
PEXTRW reg32,xmmreg,imm8 [mri: 66 0f3a 15 /r ib,u] SSE41
|
||||
PEXTRW mem16,xmmreg,imm8 [mri: 66 0f3a 15 /r ib,u] SSE41
|
||||
PEXTRW reg64,xmmreg,imm8 [mri: o64 66 0f3a 15 /r ib,u] SSE41,X86_64,LONG
|
||||
PHMINPOSUW xmmreg,xmmrm128 [rm: 66 0f38 41 /r] SSE41
|
||||
PINSRB xmmreg,mem,imm8 [rmi: 66 0f3a 20 /r ib,u] SSE41,SB,AR2
|
||||
PINSRB xmmreg,rm8,imm8 [rmi: nohi 66 0f3a 20 /r ib,u] SSE41,SB,AR2
|
||||
PINSRB xmmreg,reg32,imm8 [rmi: 66 0f3a 20 /r ib,u] SSE41,SB,AR2
|
||||
PINSRD xmmreg,rm32,imm8 [rmi: norexw 66 0f3a 22 /r ib,u] SSE41,SB,AR2
|
||||
PINSRQ xmmreg,rm64,imm8 [rmi: o64 66 0f3a 22 /r ib,u] SSE41,X86_64,LONG,SB,AR2
|
||||
PMAXSB xmmreg,xmmrm128 [rm: 66 0f38 3c /r] SSE41
|
||||
PMAXSD xmmreg,xmmrm128 [rm: 66 0f38 3d /r] SSE41
|
||||
PMAXUD xmmreg,xmmrm128 [rm: 66 0f38 3f /r] SSE41
|
||||
PMAXUW xmmreg,xmmrm128 [rm: 66 0f38 3e /r] SSE41
|
||||
PMINSB xmmreg,xmmrm128 [rm: 66 0f38 38 /r] SSE41
|
||||
PMINSD xmmreg,xmmrm128 [rm: 66 0f38 39 /r] SSE41
|
||||
PMINUD xmmreg,xmmrm128 [rm: 66 0f38 3b /r] SSE41
|
||||
PMINUW xmmreg,xmmrm128 [rm: 66 0f38 3a /r] SSE41
|
||||
PMOVSXBW xmmreg,xmmrm64 [rm: 66 0f38 20 /r] SSE41,SQ
|
||||
PMOVSXBD xmmreg,xmmrm32 [rm: 66 0f38 21 /r] SSE41,SD
|
||||
PMOVSXBQ xmmreg,xmmrm16 [rm: 66 0f38 22 /r] SSE41,SW
|
||||
PMOVSXWD xmmreg,xmmrm64 [rm: 66 0f38 23 /r] SSE41,SQ
|
||||
PMOVSXWQ xmmreg,xmmrm32 [rm: 66 0f38 24 /r] SSE41,SD
|
||||
PMOVSXDQ xmmreg,xmmrm64 [rm: 66 0f38 25 /r] SSE41,SQ
|
||||
PMOVZXBW xmmreg,xmmrm64 [rm: 66 0f38 30 /r] SSE41,SQ
|
||||
PMOVZXBD xmmreg,xmmrm32 [rm: 66 0f38 31 /r] SSE41,SD
|
||||
PMOVZXBQ xmmreg,xmmrm16 [rm: 66 0f38 32 /r] SSE41,SW
|
||||
PMOVZXWD xmmreg,xmmrm64 [rm: 66 0f38 33 /r] SSE41,SQ
|
||||
PMOVZXWQ xmmreg,xmmrm32 [rm: 66 0f38 34 /r] SSE41,SD
|
||||
PMOVZXDQ xmmreg,xmmrm64 [rm: 66 0f38 35 /r] SSE41,SQ
|
||||
PMULDQ xmmreg,xmmrm128 [rm: 66 0f38 28 /r] SSE41
|
||||
PMULLD xmmreg,xmmrm128 [rm: 66 0f38 40 /r] SSE41
|
||||
PTEST xmmreg,xmmrm128 [rm: 66 0f38 17 /r] SSE41
|
||||
ROUNDPD xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 09 /r ib,u] SSE41
|
||||
ROUNDPS xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 08 /r ib,u] SSE41
|
||||
ROUNDSD xmmreg,xmmrm64,imm8 [rmi: 66 0f3a 0b /r ib,u] SSE41
|
||||
ROUNDSS xmmreg,xmmrm32,imm8 [rmi: 66 0f3a 0a /r ib,u] SSE41
|
||||
BLENDPD xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 0d /r ib,u] SSE4_1
|
||||
BLENDPS xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 0c /r ib,u] SSE4_1
|
||||
BLENDVPD xmmreg,xmmrm128,xmm0 [rm-: 66 0f38 15 /r] SSE4_1
|
||||
BLENDVPD xmmreg,xmmrm128 [rm: 66 0f38 15 /r] SSE4_1
|
||||
BLENDVPS xmmreg,xmmrm128,xmm0 [rm-: 66 0f38 14 /r] SSE4_1
|
||||
BLENDVPS xmmreg,xmmrm128 [rm: 66 0f38 14 /r] SSE4_1
|
||||
DPPD xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 41 /r ib,u] SSE4_1
|
||||
DPPS xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 40 /r ib,u] SSE4_1
|
||||
EXTRACTPS rm32,xmmreg,imm8 [mri: 66 0f3a 17 /r ib,u] SSE4_1
|
||||
EXTRACTPS reg64,xmmreg,imm8 [mri: o64 66 0f3a 17 /r ib,u] SSE4_1,X86_64,LONG
|
||||
INSERTPS xmmreg,xmmrm32,imm8 [rmi: 66 0f3a 21 /r ib,u] SSE4_1
|
||||
MOVNTDQA xmmreg,mem128 [rm: 66 0f38 2a /r] SSE4_1
|
||||
MPSADBW xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 42 /r ib,u] SSE4_1
|
||||
PACKUSDW xmmreg,xmmrm128 [rm: 66 0f38 2b /r] SSE4_1
|
||||
PBLENDVB xmmreg,xmmrm,xmm0 [rm-: 66 0f38 10 /r] SSE4_1
|
||||
PBLENDVB xmmreg,xmmrm128 [rm: 66 0f38 10 /r] SSE4_1
|
||||
PBLENDW xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 0e /r ib,u] SSE4_1
|
||||
PCMPEQQ xmmreg,xmmrm128 [rm: 66 0f38 29 /r] SSE4_1
|
||||
PEXTRB reg32,xmmreg,imm8 [mri: 66 0f3a 14 /r ib,u] SSE4_1
|
||||
PEXTRB mem8,xmmreg,imm8 [mri: 66 0f3a 14 /r ib,u] SSE4_1
|
||||
PEXTRB reg64,xmmreg,imm8 [mri: o64nw 66 0f3a 14 /r ib,u] SSE4_1,X86_64,LONG
|
||||
PEXTRD rm32,xmmreg,imm8 [mri: norexw 66 0f3a 16 /r ib,u] SSE4_1
|
||||
PEXTRQ rm64,xmmreg,imm8 [mri: o64 66 0f3a 16 /r ib,u] SSE4_1,X86_64,LONG
|
||||
PEXTRW reg32,xmmreg,imm8 [mri: 66 0f3a 15 /r ib,u] SSE4_1
|
||||
PEXTRW mem16,xmmreg,imm8 [mri: 66 0f3a 15 /r ib,u] SSE4_1
|
||||
PEXTRW reg64,xmmreg,imm8 [mri: o64 66 0f3a 15 /r ib,u] SSE4_1,X86_64,LONG
|
||||
PHMINPOSUW xmmreg,xmmrm128 [rm: 66 0f38 41 /r] SSE4_1
|
||||
PINSRB xmmreg,mem,imm8 [rmi: 66 0f3a 20 /r ib,u] SSE4_1,SB,AR2
|
||||
PINSRB xmmreg,rm8,imm8 [rmi: nohi 66 0f3a 20 /r ib,u] SSE4_1,SB,AR2
|
||||
PINSRB xmmreg,reg32,imm8 [rmi: 66 0f3a 20 /r ib,u] SSE4_1,SB,AR2
|
||||
PINSRD xmmreg,rm32,imm8 [rmi: norexw 66 0f3a 22 /r ib,u] SSE4_1,SB,AR2
|
||||
PINSRQ xmmreg,rm64,imm8 [rmi: o64 66 0f3a 22 /r ib,u] SSE4_1,X86_64,LONG,SB,AR2
|
||||
PMAXSB xmmreg,xmmrm128 [rm: 66 0f38 3c /r] SSE4_1
|
||||
PMAXSD xmmreg,xmmrm128 [rm: 66 0f38 3d /r] SSE4_1
|
||||
PMAXUD xmmreg,xmmrm128 [rm: 66 0f38 3f /r] SSE4_1
|
||||
PMAXUW xmmreg,xmmrm128 [rm: 66 0f38 3e /r] SSE4_1
|
||||
PMINSB xmmreg,xmmrm128 [rm: 66 0f38 38 /r] SSE4_1
|
||||
PMINSD xmmreg,xmmrm128 [rm: 66 0f38 39 /r] SSE4_1
|
||||
PMINUD xmmreg,xmmrm128 [rm: 66 0f38 3b /r] SSE4_1
|
||||
PMINUW xmmreg,xmmrm128 [rm: 66 0f38 3a /r] SSE4_1
|
||||
PMOVSXBW xmmreg,xmmrm64 [rm: 66 0f38 20 /r] SSE4_1,SQ
|
||||
PMOVSXBD xmmreg,xmmrm32 [rm: 66 0f38 21 /r] SSE4_1,SD
|
||||
PMOVSXBQ xmmreg,xmmrm16 [rm: 66 0f38 22 /r] SSE4_1,SW
|
||||
PMOVSXWD xmmreg,xmmrm64 [rm: 66 0f38 23 /r] SSE4_1,SQ
|
||||
PMOVSXWQ xmmreg,xmmrm32 [rm: 66 0f38 24 /r] SSE4_1,SD
|
||||
PMOVSXDQ xmmreg,xmmrm64 [rm: 66 0f38 25 /r] SSE4_1,SQ
|
||||
PMOVZXBW xmmreg,xmmrm64 [rm: 66 0f38 30 /r] SSE4_1,SQ
|
||||
PMOVZXBD xmmreg,xmmrm32 [rm: 66 0f38 31 /r] SSE4_1,SD
|
||||
PMOVZXBQ xmmreg,xmmrm16 [rm: 66 0f38 32 /r] SSE4_1,SW
|
||||
PMOVZXWD xmmreg,xmmrm64 [rm: 66 0f38 33 /r] SSE4_1,SQ
|
||||
PMOVZXWQ xmmreg,xmmrm32 [rm: 66 0f38 34 /r] SSE4_1,SD
|
||||
PMOVZXDQ xmmreg,xmmrm64 [rm: 66 0f38 35 /r] SSE4_1,SQ
|
||||
PMULDQ xmmreg,xmmrm128 [rm: 66 0f38 28 /r] SSE4_1
|
||||
PMULLD xmmreg,xmmrm128 [rm: 66 0f38 40 /r] SSE4_1
|
||||
PTEST xmmreg,xmmrm128 [rm: 66 0f38 17 /r] SSE4_1
|
||||
ROUNDPD xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 09 /r ib,u] SSE4_1
|
||||
ROUNDPS xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 08 /r ib,u] SSE4_1
|
||||
ROUNDSD xmmreg,xmmrm64,imm8 [rmi: 66 0f3a 0b /r ib,u] SSE4_1
|
||||
ROUNDSS xmmreg,xmmrm32,imm8 [rmi: 66 0f3a 0a /r ib,u] SSE4_1
|
||||
|
||||
;# Nehalem New Instructions (SSE4.2)
|
||||
CRC32 reg32,rm8 [rm: f2i 0f38 f0 /r] SSE42
|
||||
CRC32 reg32,rm16 [rm: o16 f2i 0f38 f1 /r] SSE42
|
||||
CRC32 reg32,rm32 [rm: o32 f2i 0f38 f1 /r] SSE42
|
||||
CRC32 reg64,rm8 [rm: o64 f2i 0f38 f0 /r] SSE42,X86_64,LONG
|
||||
CRC32 reg64,rm64 [rm: o64 f2i 0f38 f1 /r] SSE42,X86_64,LONG
|
||||
PCMPESTRI xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 61 /r ib,u] SSE42
|
||||
PCMPESTRM xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 60 /r ib,u] SSE42
|
||||
PCMPISTRI xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 63 /r ib,u] SSE42
|
||||
PCMPISTRM xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 62 /r ib,u] SSE42
|
||||
PCMPGTQ xmmreg,xmmrm128 [rm: 66 0f38 37 /r] SSE42
|
||||
CRC32 reg32,rm8 [rm: f2i 0f38 f0 /r] SSE4_2
|
||||
CRC32 reg32,rm16 [rm: o16 f2i 0f38 f1 /r] SSE4_2
|
||||
CRC32 reg32,rm32 [rm: o32 f2i 0f38 f1 /r] SSE4_2
|
||||
CRC32 reg64,rm8 [rm: o64 f2i 0f38 f0 /r] SSE4_2,X86_64,LONG
|
||||
CRC32 reg64,rm64 [rm: o64 f2i 0f38 f1 /r] SSE4_2,X86_64,LONG
|
||||
PCMPESTRI xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 61 /r ib,u] SSE4_2
|
||||
PCMPESTRM xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 60 /r ib,u] SSE4_2
|
||||
PCMPISTRI xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 63 /r ib,u] SSE4_2
|
||||
PCMPISTRM xmmreg,xmmrm128,imm8 [rmi: 66 0f3a 62 /r ib,u] SSE4_2
|
||||
PCMPGTQ xmmreg,xmmrm128 [rm: 66 0f38 37 /r] SSE4_2
|
||||
POPCNT reg16,rm16 [rm: o16 f3i 0f b8 /r] NEHALEM,SW
|
||||
POPCNT reg32,rm32 [rm: o32 f3i 0f b8 /r] NEHALEM,SD
|
||||
POPCNT reg64,rm64 [rm: o64 f3i 0f b8 /r] NEHALEM,SQ,LONG
|
||||
|
|
|
|||
0
x86/rex2.pl
Normal file → Executable file
0
x86/rex2.pl
Normal file → Executable file
183
x86/x86features.ph
Normal file
183
x86/x86features.ph
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
# -*- perl -*-
|
||||
#
|
||||
# CPU feature sets and their dependencies.
|
||||
#
|
||||
|
||||
use integer;
|
||||
use strict;
|
||||
|
||||
our %cpufeature; # cpu features by name
|
||||
our @cpufeatures; # List of cpu features in numeric order
|
||||
our @cpus;
|
||||
|
||||
# Make a name into a valid upper case C identifier suffix
|
||||
sub cname($) {
|
||||
my($n) = @_;
|
||||
$n = uc($n);
|
||||
$n =~ s/[^\w]/_/g;
|
||||
$n =~ s/__+/_/g;
|
||||
return $n;
|
||||
}
|
||||
|
||||
# Create a new CPU feature flag
|
||||
sub f_($;$@) {
|
||||
my($name, $help, @deplist) = @_;
|
||||
|
||||
$name = lc($name);
|
||||
if (!defined($help)) {
|
||||
$help = uc($name)." instruction";
|
||||
}
|
||||
|
||||
my $feat = {
|
||||
'name' => $name,
|
||||
'cname' => cname($name),
|
||||
'help' => $help,
|
||||
'_dep' => {$name => 1}, # All features "depend" on themselves
|
||||
'num' => scalar(@cpufeatures),
|
||||
'vendor' => 0
|
||||
};
|
||||
$cpufeature{$name} = $feat;
|
||||
push(@cpufeatures, $feat);
|
||||
|
||||
d_($name, @deplist);
|
||||
return $feat;
|
||||
}
|
||||
|
||||
# Add dependencies to a CPU feature
|
||||
sub d_($@) {
|
||||
my($name, @deplist) = @_;
|
||||
|
||||
$name = lc($name);
|
||||
my $feat = $cpufeature{$name};
|
||||
if (!defined($feat)) {
|
||||
die "$0: tried to add dependencies to nonexistent cpu feature \U$name\E \n";
|
||||
}
|
||||
|
||||
my $_dep = $feat->{'_dep'};
|
||||
foreach my $d (@deplist) {
|
||||
$_dep->{lc($d)} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
# The actual feature list
|
||||
require 'x86/features.ph'
|
||||
|
||||
#
|
||||
# Vendor flags
|
||||
#
|
||||
foreach my $v (qw(Cyrix AMD Intel)) {
|
||||
my $feat = f_($v, "$v-specific instructions", qw(vendor));
|
||||
$feat->{'vendor'} = 1;
|
||||
}
|
||||
|
||||
#
|
||||
# Some automatically generated dependencies
|
||||
#
|
||||
foreach my $fn (keys(%cpufeature)) {
|
||||
my $feat = $cpufeature{$fn};
|
||||
my $name = $feat->{'name'};
|
||||
|
||||
if ($fn =~ /^avx512.+$/) {
|
||||
d_('avx512', $name);
|
||||
} elsif ($fn =~ /^avx.+$/) {
|
||||
d_($name, 'avx');
|
||||
}
|
||||
|
||||
if ($fn =~ /^apx.+$/) {
|
||||
d_('apx', $name);
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Compute the transitive closure and produce dependencies as a list of
|
||||
# references as opposed to names.
|
||||
#
|
||||
# Although a circular dependency isn't incorrect as such, it also means
|
||||
# that all the CPU features in the circle are in fact identical, and so
|
||||
# they should be merged into one feature bit.
|
||||
#
|
||||
sub _cpufeature_closure($;@) {
|
||||
my($feat, @stack) = @_;
|
||||
my $name = $feat->{'name'};
|
||||
my $dep = $feat->{'_dep'};
|
||||
|
||||
my @_deps = keys(%$dep);
|
||||
|
||||
if (defined($feat->{'deps'})) {
|
||||
return @_deps;
|
||||
} elsif (exists($feat->{'deps'})) {
|
||||
my $list = join(', ', map { $_->{'name'} } ($feat, @stack));
|
||||
die "$0: circular depencency for CPU features $list\n";
|
||||
}
|
||||
|
||||
# Mark this as in progress for loop detection
|
||||
$feat->{'deps'} = undef;
|
||||
|
||||
# For better error messages
|
||||
push(@stack, $feat);
|
||||
|
||||
foreach my $depname (@_deps) {
|
||||
next if ($depname eq $name);
|
||||
my $cfeat = $cpufeature{$depname};
|
||||
if (!defined($cfeat)) {
|
||||
die "$0: feature $name depends on non-existent feature $depname\n";
|
||||
}
|
||||
foreach my $cdep (_cpufeature_closure($cfeat, @stack)) {
|
||||
$dep->{$cdep}++;
|
||||
}
|
||||
}
|
||||
|
||||
@_deps = keys(%$dep); # Update with the closure
|
||||
|
||||
my $deps = [sort { $a->{'num'} <=> $b->{'num'} }
|
||||
map { $cpufeature{$_} } @_deps];
|
||||
|
||||
return $feat->{'deps'} = $deps;
|
||||
}
|
||||
|
||||
foreach my $feat (@cpufeatures) {
|
||||
_cpufeature_closure($feat);
|
||||
}
|
||||
|
||||
#
|
||||
# Create the anti-depency mask, that is, the list of features to be removed
|
||||
# when a certain feature is removed, too.
|
||||
#
|
||||
foreach my $feat (@cpufeatures) {
|
||||
$feat->{'nuke'} = [];
|
||||
}
|
||||
foreach my $feat (@cpufeatures) {
|
||||
foreach my $dep (@{$feat->{'deps'}}) {
|
||||
push(@{$dep->{'nuke'}}, $feat);
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Create bitmasks from lists
|
||||
#
|
||||
our $cpufeature_bits = $cpufeatures[-1]->{'num'} + 1;
|
||||
our $cpufeature_words = ($cpufeature_bits + 31) >> 5;
|
||||
|
||||
sub set_bits(\@@) {
|
||||
my $words = shift(@_);
|
||||
|
||||
foreach my $n (@_) {
|
||||
$words->[$n >> 5] |= 1 << ($n & 31);
|
||||
}
|
||||
|
||||
return $words;
|
||||
}
|
||||
|
||||
sub makemask($$) {
|
||||
my($feat, $field) = @_;
|
||||
my $fw = [(0) x $cpufeature_words];
|
||||
set_bits(@$fw, map { $_->{'num'} } @{$feat->{$field}});
|
||||
return $fw;
|
||||
}
|
||||
|
||||
foreach my $feat (@cpufeatures) {
|
||||
$feat->{'depmask'} = makemask($feat, 'deps');
|
||||
$feat->{'badmask'} = makemask($feat, 'nuke');
|
||||
}
|
||||
|
||||
1;
|
||||
Loading…
Add table
Add a link
Reference in a new issue