summaryrefslogtreecommitdiff
path: root/iflag.h
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2013-11-24 11:13:10 -0800
committerH. Peter Anvin <hpa@zytor.com>2013-11-24 11:13:10 -0800
commit45a22d9a6147c320b6754679de54a8290de3c5e3 (patch)
treeba4fe7f527010f2b6d76895a3bce0715bde224f5 /iflag.h
parent015774dc3fee2aa1a96718e5097fb8045ef020a3 (diff)
downloadnasm-45a22d9a6147c320b6754679de54a8290de3c5e3.tar.gz
nasm-45a22d9a6147c320b6754679de54a8290de3c5e3.tar.bz2
nasm-45a22d9a6147c320b6754679de54a8290de3c5e3.zip
iflag: Fix dependencies, factor out static components of iflag.h
Multi-dependencies don't work as expected, especially not across Make versions, this is why we don't use them and read the instructions list multiple times. iflag.h has a lot of static content, so factor out the static content. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'iflag.h')
-rw-r--r--iflag.h193
1 files changed, 193 insertions, 0 deletions
diff --git a/iflag.h b/iflag.h
new file mode 100644
index 0000000..d08249e
--- /dev/null
+++ b/iflag.h
@@ -0,0 +1,193 @@
+#ifndef NASM_IFLAG_H
+#define NASM_IFLAG_H
+
+#include <inttypes.h>
+
+#include <string.h>
+
+#include "compiler.h"
+
+int ilog2_32(uint32_t v);
+
+/*
+ * Instruction template flags. These specify which processor
+ * targets the instruction is eligible for, whether it is
+ * privileged or undocumented, and also specify extra error
+ * checking on the matching of the instruction.
+ *
+ * IF_SM stands for Size Match: any operand whose size is not
+ * explicitly specified by the template is `really' intended to be
+ * the same size as the first size-specified operand.
+ * Non-specification is tolerated in the input instruction, but
+ * _wrong_ specification is not.
+ *
+ * IF_SM2 invokes Size Match on only the first _two_ operands, for
+ * three-operand instructions such as SHLD: it implies that the
+ * first two operands must match in size, but that the third is
+ * required to be _unspecified_.
+ *
+ * IF_SB invokes Size Byte: operands with unspecified size in the
+ * template are really bytes, and so no non-byte specification in
+ * the input instruction will be tolerated. IF_SW similarly invokes
+ * Size Word, and IF_SD invokes Size Doubleword.
+ *
+ * (The default state if neither IF_SM nor IF_SM2 is specified is
+ * that any operand with unspecified size in the template is
+ * required to have unspecified size in the instruction too...)
+ *
+ * iflag_t is defined to store these flags.
+ */
+typedef struct {
+ uint32_t field[4];
+} iflag_t;
+
+#include "iflaggen.h"
+
+#define IF_GENBIT(bit) (UINT32_C(1) << (bit))
+
+static inline unsigned int iflag_test(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(iflag_t *a, iflag_t *b)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof(a->field) / sizeof(a->field[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(iflag_t *a, 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(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(iflag_t *a, 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(iflag_t *a, 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(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__ */