1#ifndef NASM_IFLAG_H
2#define NASM_IFLAG_H
3
4#include "compiler.h"
5#include "ilog2.h"
6
7#include <string.h>
8
9#include "iflaggen.h"
10
11#define IF_GENBIT(bit) (UINT32_C(1) << (bit))
12
13static inline bool iflag_test(const iflag_t *f, unsigned int bit)
14{
15 return !!(f->field[bit >> 5] & IF_GENBIT(bit & 31));
16}
17
18static inline void iflag_set(iflag_t *f, unsigned int bit)
19{
20 f->field[bit >> 5] |= IF_GENBIT(bit & 31);
21}
22
23static inline void iflag_clear(iflag_t *f, unsigned int bit)
24{
25 f->field[bit >> 5] &= ~IF_GENBIT(bit & 31);
26}
27
28static inline void iflag_clear_all(iflag_t *f)
29{
30 memset(f, 0, sizeof(*f));
31}
32
33static inline void iflag_set_all(iflag_t *f)
34{
35 memset(f, ~0, sizeof(*f));
36}
37
38#define iflag_for_each_field(v) for ((v) = 0; (v) < IF_FIELD_COUNT; (v)++)
39
40static inline int iflag_cmp(const iflag_t *a, const iflag_t *b)
41{
42 int i;
43
44 /* This is intentionally a reverse loop! */
45 for (i = IF_FIELD_COUNT-1; i >= 0; i--) {
46 if (a->field[i] == b->field[i])
47 continue;
48
49 return (int)(a->field[i] - b->field[i]);
50 }
51
52 return 0;
53}
54
55#define IF_GEN_HELPER(name, op) \
56 static inline iflag_t iflag_##name(const iflag_t *a, const iflag_t *b) \
57 { \
58 unsigned int i; \
59 iflag_t res; \
60 \
61 iflag_for_each_field(i) \
62 res.field[i] = a->field[i] op b->field[i]; \
63 \
64 return res; \
65 }
66
67IF_GEN_HELPER(xor, ^)
68
69/* Some helpers which are to work with predefined masks */
70#define IF_SMASK \
71 (IF_GENBIT(IF_SB) |\
72 IF_GENBIT(IF_SW) |\
73 IF_GENBIT(IF_SD) |\
74 IF_GENBIT(IF_SQ) |\
75 IF_GENBIT(IF_SO) |\
76 IF_GENBIT(IF_SY) |\
77 IF_GENBIT(IF_SZ) |\
78 IF_GENBIT(IF_SIZE))
79#define IF_ARMASK \
80 (IF_GENBIT(IF_AR0) |\
81 IF_GENBIT(IF_AR1) |\
82 IF_GENBIT(IF_AR2) |\
83 IF_GENBIT(IF_AR3) |\
84 IF_GENBIT(IF_AR4))
85
86#define _itemp_smask(idx) (insns_flags[(idx)].field[0] & IF_SMASK)
87#define _itemp_armask(idx) (insns_flags[(idx)].field[0] & IF_ARMASK)
88#define _itemp_arg(idx) ((_itemp_armask(idx) >> IF_AR0) - 1)
89
90#define itemp_smask(itemp) _itemp_smask((itemp)->iflag_idx)
91#define itemp_arg(itemp) _itemp_arg((itemp)->iflag_idx)
92#define itemp_armask(itemp) _itemp_armask((itemp)->iflag_idx)
93
94/*
95 * IF_8086 is the first CPU level flag and IF_PLEVEL the last
96 */
97#if IF_8086 & 31
98#error "IF_8086 must be on a uint32_t boundary"
99#endif
100#define IF_PLEVEL IF_IA64
101#define IF_CPU_FIELD (IF_8086 >> 5)
102#define IF_CPU_LEVEL_MASK ((IF_GENBIT(IF_PLEVEL & 31) << 1) - 1)
103
104/*
105 * IF_PRIV is the firstr instruction filtering flag
106 */
107#if IF_PRIV & 31
108#error "IF_PRIV must be on a uint32_t boundary"
109#endif
110#define IF_FEATURE_FIELD (IF_PRIV >> 5)
111
112static inline int iflag_cmp_cpu(const iflag_t *a, const iflag_t *b)
113{
114 return (int)(a->field[IF_CPU_FIELD] - b->field[IF_CPU_FIELD]);
115}
116
117static inline uint32_t _iflag_cpu_level(const iflag_t *a)
118{
119 return a->field[IF_CPU_FIELD] & IF_CPU_LEVEL_MASK;
120}
121
122static inline int iflag_cmp_cpu_level(const iflag_t *a, const iflag_t *b)
123{
124 uint32_t aa = _iflag_cpu_level(a);
125 uint32_t bb = _iflag_cpu_level(b);
126
127 return (int)(aa - bb);
128}
129
130/* Returns true if the CPU level is at least a certain value */
131static inline bool iflag_cpu_level_ok(const iflag_t *a, unsigned int bit)
132{
133 return _iflag_cpu_level(a) >= IF_GENBIT(bit & 31);
134}
135
136static inline void iflag_set_all_features(iflag_t *a)
137{
138 size_t i;
139
140 for (i = IF_FEATURE_FIELD; i < IF_CPU_FIELD; i++)
141 a->field[i] = ~UINT32_C(0);
142}
143
144static inline void iflag_set_cpu(iflag_t *a, unsigned int cpu)
145{
146 a->field[0] = 0; /* Not applicable to the CPU type */
147 iflag_set_all_features(a); /* All feature masking bits set for now */
148 a->field[IF_CPU_FIELD] &= ~IF_CPU_LEVEL_MASK;
149 iflag_set(a, cpu);
150}
151
152static inline void iflag_set_default_cpu(iflag_t *a)
153{
154 iflag_set_cpu(a, IF_PLEVEL);
155}
156
157static inline iflag_t _iflag_pfmask(const iflag_t *a)
158{
159 iflag_t r;
160
161 iflag_clear_all(&r);
162
163 if (iflag_test(a, IF_CYRIX))
164 iflag_set(&r, IF_CYRIX);
165 if (iflag_test(a, IF_AMD))
166 iflag_set(&r, IF_AMD);
167
168 return r;
169}
170
171#define iflag_pfmask(itemp) _iflag_pfmask(&insns_flags[(itemp)->iflag_idx])
172
173#endif /* NASM_IFLAG_H */
174