nasm/iflag.h
H. Peter Anvin 80d18b5555 iflag: In iflag_cmp() scan from the most significant word down
In order for iflag_cmp() to return an ordering that makes sense, we
need to scan from the most significant word downward.  That way the
bits with the higher index consistently are the more significant.

This fixes the disassembler vendor selection algorithm.  While we are
doing that, make that dependency more explicit in the comments.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2013-11-26 15:21:15 -08:00

162 lines
4.1 KiB
C

#ifndef NASM_IFLAG_H
#define NASM_IFLAG_H
#include <inttypes.h>
#include <string.h>
#include "compiler.h"
int ilog2_32(uint32_t v);
#include "iflaggen.h"
#define IF_GENBIT(bit) (UINT32_C(1) << (bit))
static inline unsigned int iflag_test(const iflag_t *f, unsigned int bit)
{
unsigned int index = bit / 32;
return f->field[index] & (UINT32_C(1) << (bit - (index * 32)));
}
static inline void iflag_set(iflag_t *f, unsigned int bit)
{
unsigned int index = bit / 32;
f->field[index] |= (UINT32_C(1) << (bit - (index * 32)));
}
static inline void iflag_clear(iflag_t *f, unsigned int bit)
{
unsigned int index = bit / 32;
f->field[index] &= ~(UINT32_C(1) << (bit - (index * 32)));
}
static inline void iflag_clear_all(iflag_t *f)
{
memset(f, 0, sizeof(*f));
}
static inline void iflag_set_all(iflag_t *f)
{
memset(f, 0xff, sizeof(*f));
}
static inline int iflag_cmp(const iflag_t *a, const iflag_t *b)
{
int i;
for (i = sizeof(a->field) / sizeof(a->field[0]) - 1; i >= 0; i--) {
if (a->field[i] < b->field[i])
return -1;
else if (a->field[i] > b->field[i])
return 1;
}
return 0;
}
static inline int iflag_cmp_cpu(const iflag_t *a, const iflag_t *b)
{
if (a->field[3] < b->field[3])
return -1;
else if (a->field[3] > b->field[3])
return 1;
return 0;
}
static inline unsigned int iflag_ffs(const iflag_t *a)
{
unsigned int i;
for (i = 0; i < sizeof(a->field) / sizeof(a->field[0]); i++) {
if (a->field[i])
return ilog2_32(a->field[i]) + (i * 32);
}
return 0;
}
#define IF_GEN_HELPER(name, op) \
static inline iflag_t iflag_##name(const iflag_t *a, const iflag_t *b) \
{ \
unsigned int i; \
iflag_t res; \
\
for (i = 0; i < sizeof(a->field) / sizeof(a->field[0]); i++) \
res.field[i] = a->field[i] op b->field[i]; \
\
return res; \
}
IF_GEN_HELPER(xor, ^)
/* Use this helper to test instruction template flags */
#define itemp_has(itemp, bit) iflag_test(&insns_flags[(itemp)->iflag_idx], bit)
/* Maximum processor level at moment */
#define IF_PLEVEL IF_IA64
/* Some helpers which are to work with predefined masks */
#define IF_SMASK \
(IF_GENBIT(IF_SB) |\
IF_GENBIT(IF_SW) |\
IF_GENBIT(IF_SD) |\
IF_GENBIT(IF_SQ) |\
IF_GENBIT(IF_SO) |\
IF_GENBIT(IF_SY) |\
IF_GENBIT(IF_SZ) |\
IF_GENBIT(IF_SIZE))
#define IF_ARMASK \
(IF_GENBIT(IF_AR0) |\
IF_GENBIT(IF_AR1) |\
IF_GENBIT(IF_AR2) |\
IF_GENBIT(IF_AR3) |\
IF_GENBIT(IF_AR4))
#define _itemp_smask(idx) (insns_flags[(idx)].field[0] & IF_SMASK)
#define _itemp_armask(idx) (insns_flags[(idx)].field[0] & IF_ARMASK)
#define _itemp_arg(idx) ((_itemp_armask(idx) >> IF_AR0) - 1)
#define itemp_smask(itemp) _itemp_smask((itemp)->iflag_idx)
#define itemp_arg(itemp) _itemp_arg((itemp)->iflag_idx)
#define itemp_armask(itemp) _itemp_armask((itemp)->iflag_idx)
static inline int iflag_cmp_cpu_level(const iflag_t *a, const iflag_t *b)
{
iflag_t v1 = *a;
iflag_t v2 = *b;
iflag_clear(&v1, IF_CYRIX);
iflag_clear(&v1, IF_AMD);
iflag_clear(&v2, IF_CYRIX);
iflag_clear(&v2, IF_AMD);
if (v1.field[3] < v2.field[3])
return -1;
else if (v1.field[3] > v2.field[3])
return 1;
return 0;
}
static inline iflag_t _iflag_pfmask(const iflag_t *a)
{
iflag_t r = (iflag_t) {
.field[1] = a->field[1],
.field[2] = a->field[2],
};
if (iflag_test(a, IF_CYRIX))
iflag_set(&r, IF_CYRIX);
if (iflag_test(a, IF_AMD))
iflag_set(&r, IF_AMD);
return r;
}
#define iflag_pfmask(itemp) _iflag_pfmask(&insns_flags[(itemp)->iflag_idx])
#endif /* NASM_IFLAG_H */