aboutsummaryrefslogtreecommitdiff
path: root/modules/arch/x86/x86cpu.gperf
blob: 334ea1c8c1419e9fe4d0e10f804a7728655afa59 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
#
# x86 CPU recognition
#
#  Copyright (C) 2002-2007  Peter Johnson
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
%{
#include <util.h>

#include <ctype.h>
#include <libyasm.h>
#include <libyasm/phash.h>

#include "modules/arch/x86/x86arch.h"

#define PROC_8086	0
#define PROC_186	1
#define PROC_286	2
#define PROC_386	3
#define PROC_486	4
#define PROC_586	5
#define PROC_686	6
#define PROC_p2		7
#define PROC_p3		8
#define PROC_p4		9
#define PROC_prescott	10
#define PROC_conroe	11
#define PROC_penryn	12
#define PROC_nehalem	13
#define PROC_westmere	14
#define PROC_sandybridge	15
#define PROC_ivybridge	16
#define PROC_haswell	17
#define PROC_broadwell	18
#define PROC_skylake	19

static void
x86_cpu_intel(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data)
{
    BitVector_Empty(cpu);

    BitVector_Bit_On(cpu, CPU_Priv);
    if (data >= PROC_286)
        BitVector_Bit_On(cpu, CPU_Prot);
    if (data >= PROC_386)
        BitVector_Bit_On(cpu, CPU_SMM);
    if (data >= PROC_skylake) {
        BitVector_Bit_On(cpu, CPU_SHA);
    }
    if (data >= PROC_broadwell) {
        BitVector_Bit_On(cpu, CPU_RDSEED);
        BitVector_Bit_On(cpu, CPU_ADX);
        BitVector_Bit_On(cpu, CPU_PRFCHW);
    }
    if (data >= PROC_haswell) {
        BitVector_Bit_On(cpu, CPU_FMA);
        BitVector_Bit_On(cpu, CPU_AVX2);
        BitVector_Bit_On(cpu, CPU_BMI1);
        BitVector_Bit_On(cpu, CPU_BMI2);
        BitVector_Bit_On(cpu, CPU_INVPCID);
        BitVector_Bit_On(cpu, CPU_LZCNT);
        BitVector_Bit_On(cpu, CPU_TSX);
        BitVector_Bit_On(cpu, CPU_SMAP);
    }
    if (data >= PROC_ivybridge) {
        BitVector_Bit_On(cpu, CPU_F16C);
        BitVector_Bit_On(cpu, CPU_FSGSBASE);
        BitVector_Bit_On(cpu, CPU_RDRAND);
    }
    if (data >= PROC_sandybridge) {
        BitVector_Bit_On(cpu, CPU_AVX);
        BitVector_Bit_On(cpu, CPU_XSAVEOPT);
        BitVector_Bit_On(cpu, CPU_EPTVPID);
        BitVector_Bit_On(cpu, CPU_SMX);
    }
    if (data >= PROC_westmere) {
        BitVector_Bit_On(cpu, CPU_AES);
        BitVector_Bit_On(cpu, CPU_CLMUL);
    }
    if (data >= PROC_nehalem) {
        BitVector_Bit_On(cpu, CPU_SSE42);
        BitVector_Bit_On(cpu, CPU_XSAVE);
    }
    if (data >= PROC_penryn)
        BitVector_Bit_On(cpu, CPU_SSE41);
    if (data >= PROC_conroe)
        BitVector_Bit_On(cpu, CPU_SSSE3);
    if (data >= PROC_prescott)
        BitVector_Bit_On(cpu, CPU_SSE3);
    if (data >= PROC_p4)
        BitVector_Bit_On(cpu, CPU_SSE2);
    if (data >= PROC_p3)
        BitVector_Bit_On(cpu, CPU_SSE);
    if (data >= PROC_p2)
        BitVector_Bit_On(cpu, CPU_MMX);
    if (data >= PROC_486)
        BitVector_Bit_On(cpu, CPU_FPU);
    if (data >= PROC_prescott)
        BitVector_Bit_On(cpu, CPU_EM64T);

    if (data >= PROC_p4)
        BitVector_Bit_On(cpu, CPU_P4);
    if (data >= PROC_p3)
        BitVector_Bit_On(cpu, CPU_P3);
    if (data >= PROC_686)
        BitVector_Bit_On(cpu, CPU_686);
    if (data >= PROC_586)
        BitVector_Bit_On(cpu, CPU_586);
    if (data >= PROC_486)
        BitVector_Bit_On(cpu, CPU_486);
    if (data >= PROC_386)
        BitVector_Bit_On(cpu, CPU_386);
    if (data >= PROC_286)
        BitVector_Bit_On(cpu, CPU_286);
    if (data >= PROC_186)
        BitVector_Bit_On(cpu, CPU_186);
    BitVector_Bit_On(cpu, CPU_086);

    /* Use Intel long NOPs if 686 or better */
    if (data >= PROC_686)
        arch_x86->nop = X86_NOP_INTEL;
    else
        arch_x86->nop = X86_NOP_BASIC;
}

static void
x86_cpu_ia64(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data)
{
    BitVector_Empty(cpu);
    BitVector_Bit_On(cpu, CPU_Priv);
    BitVector_Bit_On(cpu, CPU_Prot);
    BitVector_Bit_On(cpu, CPU_SMM);
    BitVector_Bit_On(cpu, CPU_SSE2);
    BitVector_Bit_On(cpu, CPU_SSE);
    BitVector_Bit_On(cpu, CPU_MMX);
    BitVector_Bit_On(cpu, CPU_FPU);
    BitVector_Bit_On(cpu, CPU_IA64);
    BitVector_Bit_On(cpu, CPU_P4);
    BitVector_Bit_On(cpu, CPU_P3);
    BitVector_Bit_On(cpu, CPU_686);
    BitVector_Bit_On(cpu, CPU_586);
    BitVector_Bit_On(cpu, CPU_486);
    BitVector_Bit_On(cpu, CPU_386);
    BitVector_Bit_On(cpu, CPU_286);
    BitVector_Bit_On(cpu, CPU_186);
    BitVector_Bit_On(cpu, CPU_086);
}

#define PROC_bulldozer	11
#define PROC_k10    10
#define PROC_venice 9
#define PROC_hammer 8
#define PROC_k7     7
#define PROC_k6     6

static void
x86_cpu_amd(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data)
{
    BitVector_Empty(cpu);

    BitVector_Bit_On(cpu, CPU_Priv);
    BitVector_Bit_On(cpu, CPU_Prot);
    BitVector_Bit_On(cpu, CPU_SMM);
    BitVector_Bit_On(cpu, CPU_3DNow);
    if (data >= PROC_bulldozer) {
        BitVector_Bit_On(cpu, CPU_XOP);
        BitVector_Bit_On(cpu, CPU_FMA4);
    }
    if (data >= PROC_k10)
        BitVector_Bit_On(cpu, CPU_SSE4a);
    if (data >= PROC_venice)
        BitVector_Bit_On(cpu, CPU_SSE3);
    if (data >= PROC_hammer)
        BitVector_Bit_On(cpu, CPU_SSE2);
    if (data >= PROC_k7)
        BitVector_Bit_On(cpu, CPU_SSE);
    if (data >= PROC_k6)
        BitVector_Bit_On(cpu, CPU_MMX);
    BitVector_Bit_On(cpu, CPU_FPU);

    if (data >= PROC_hammer)
        BitVector_Bit_On(cpu, CPU_Hammer);
    if (data >= PROC_k7)
        BitVector_Bit_On(cpu, CPU_Athlon);
    if (data >= PROC_k6)
        BitVector_Bit_On(cpu, CPU_K6);
    BitVector_Bit_On(cpu, CPU_686);
    BitVector_Bit_On(cpu, CPU_586);
    BitVector_Bit_On(cpu, CPU_486);
    BitVector_Bit_On(cpu, CPU_386);
    BitVector_Bit_On(cpu, CPU_286);
    BitVector_Bit_On(cpu, CPU_186);
    BitVector_Bit_On(cpu, CPU_086);

    /* Use AMD long NOPs if k6 or better */
    if (data >= PROC_k6)
        arch_x86->nop = X86_NOP_AMD;
    else
        arch_x86->nop = X86_NOP_BASIC;
}

static void
x86_cpu_set(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data)
{
    BitVector_Bit_On(cpu, data);
}

static void
x86_cpu_clear(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data)
{
    BitVector_Bit_Off(cpu, data);
}

static void
x86_cpu_set_sse4(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data)
{
    BitVector_Bit_On(cpu, CPU_SSE41);
    BitVector_Bit_On(cpu, CPU_SSE42);
}

static void
x86_cpu_clear_sse4(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data)
{
    BitVector_Bit_Off(cpu, CPU_SSE41);
    BitVector_Bit_Off(cpu, CPU_SSE42);
}

static void
x86_nop(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data)
{
    arch_x86->nop = data;
}

%}
%ignore-case
%language=ANSI-C
%compare-strncmp
%readonly-tables
%enum
%struct-type
%define hash-function-name cpu_hash
%define lookup-function-name cpu_find
struct cpu_parse_data {
    const char *name;
    void (*handler) (wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data);
    unsigned int data;
};
%%
8086,		x86_cpu_intel,	PROC_8086
186,		x86_cpu_intel,	PROC_186
80186,		x86_cpu_intel,	PROC_186
i186,		x86_cpu_intel,	PROC_186
286,		x86_cpu_intel,	PROC_286
80286,		x86_cpu_intel,	PROC_286
i286,		x86_cpu_intel,	PROC_286
386,		x86_cpu_intel,	PROC_386
80386,		x86_cpu_intel,	PROC_386
i386,		x86_cpu_intel,	PROC_386
486,		x86_cpu_intel,	PROC_486
80486,		x86_cpu_intel,	PROC_486
i486,		x86_cpu_intel,	PROC_486
586,		x86_cpu_intel,	PROC_586
i586,		x86_cpu_intel,	PROC_586
pentium,	x86_cpu_intel,	PROC_586
p5,		x86_cpu_intel,	PROC_586
686,		x86_cpu_intel,	PROC_686
i686,		x86_cpu_intel,	PROC_686
p6,		x86_cpu_intel,	PROC_686
ppro,		x86_cpu_intel,	PROC_686
pentiumpro,	x86_cpu_intel,	PROC_686
p2,		x86_cpu_intel,	PROC_p2
pentium2,	x86_cpu_intel,	PROC_p2
pentium-2,	x86_cpu_intel,	PROC_p2
pentiumii,	x86_cpu_intel,	PROC_p2
pentium-ii,	x86_cpu_intel,	PROC_p2
p3,		x86_cpu_intel,	PROC_p3
pentium3,	x86_cpu_intel,	PROC_p3
pentium-3,	x86_cpu_intel,	PROC_p3
pentiumiii,	x86_cpu_intel,	PROC_p3
pentium-iii,	x86_cpu_intel,	PROC_p3
katmai,		x86_cpu_intel,	PROC_p3
p4,		x86_cpu_intel,	PROC_p4
pentium4,	x86_cpu_intel,	PROC_p4
pentium-4,	x86_cpu_intel,	PROC_p4
pentiumiv,	x86_cpu_intel,	PROC_p4
pentium-iv,	x86_cpu_intel,	PROC_p4
williamette,	x86_cpu_intel,	PROC_p4
ia64,		x86_cpu_ia64,	0
ia-64,		x86_cpu_ia64,	0
itanium,	x86_cpu_ia64,	0
k6,		x86_cpu_amd,	PROC_k6
k7,		x86_cpu_amd,	PROC_k7
athlon,		x86_cpu_amd,	PROC_k7
k8,		x86_cpu_amd,	PROC_hammer
hammer,		x86_cpu_amd,	PROC_hammer
clawhammer,	x86_cpu_amd,	PROC_hammer
opteron,	x86_cpu_amd,	PROC_hammer
athlon64,	x86_cpu_amd,	PROC_hammer
athlon-64,	x86_cpu_amd,	PROC_hammer
venice,		x86_cpu_amd,	PROC_venice
k10,		x86_cpu_amd,	PROC_k10
phenom,		x86_cpu_amd,	PROC_k10
family10h,	x86_cpu_amd,	PROC_k10
bulldozer,	x86_cpu_amd,	PROC_bulldozer
prescott,	x86_cpu_intel,	PROC_prescott
conroe,		x86_cpu_intel,	PROC_conroe
core2,		x86_cpu_intel,	PROC_conroe
penryn,		x86_cpu_intel,	PROC_penryn
nehalem,	x86_cpu_intel,	PROC_nehalem
corei7,		x86_cpu_intel,	PROC_nehalem
westmere,	x86_cpu_intel,	PROC_westmere
sandybridge,	x86_cpu_intel,	PROC_sandybridge
ivybridge,	x86_cpu_intel,	PROC_ivybridge
haswell,	x86_cpu_intel,	PROC_haswell
broadwell,	x86_cpu_intel,	PROC_broadwell
skylake,	x86_cpu_intel,	PROC_skylake
#
# Features have "no" versions to disable them, and only set/reset the
# specific feature being changed.  All other bits are left alone.
#
fpu,		x86_cpu_set,	CPU_FPU
nofpu,		x86_cpu_clear,	CPU_FPU
mmx,		x86_cpu_set,	CPU_MMX
nommx,		x86_cpu_clear,	CPU_MMX
sse,		x86_cpu_set,	CPU_SSE
nosse,		x86_cpu_clear,	CPU_SSE
sse2,		x86_cpu_set,	CPU_SSE2
nosse2,		x86_cpu_clear,	CPU_SSE2
sse3,		x86_cpu_set,	CPU_SSE3
nosse3,		x86_cpu_clear,	CPU_SSE3
#pni,		x86_cpu_set,	CPU_PNI
#nopni,		x86_cpu_clear,	CPU_PNI
3dnow,		x86_cpu_set,	CPU_3DNow
no3dnow,	x86_cpu_clear,	CPU_3DNow
cyrix,		x86_cpu_set,	CPU_Cyrix
nocyrix,	x86_cpu_clear,	CPU_Cyrix
amd,		x86_cpu_set,	CPU_AMD
noamd,		x86_cpu_clear,	CPU_AMD
smm,		x86_cpu_set,	CPU_SMM
nosmm,		x86_cpu_clear,	CPU_SMM
prot,		x86_cpu_set,	CPU_Prot
noprot,		x86_cpu_clear,	CPU_Prot
protected,	x86_cpu_set,	CPU_Prot
noprotected,	x86_cpu_clear,	CPU_Prot
undoc,		x86_cpu_set,	CPU_Undoc
noundoc,	x86_cpu_clear,	CPU_Undoc
undocumented,	x86_cpu_set,	CPU_Undoc
noundocumented,	x86_cpu_clear,	CPU_Undoc
obs,		x86_cpu_set,	CPU_Obs
noobs,		x86_cpu_clear,	CPU_Obs
obsolete,	x86_cpu_set,	CPU_Obs
noobsolete,	x86_cpu_clear,	CPU_Obs
priv,		x86_cpu_set,	CPU_Priv
nopriv,		x86_cpu_clear,	CPU_Priv
privileged,	x86_cpu_set,	CPU_Priv
noprivileged,	x86_cpu_clear,	CPU_Priv
svm,		x86_cpu_set,	CPU_SVM
nosvm,		x86_cpu_clear,	CPU_SVM
padlock,	x86_cpu_set,	CPU_PadLock
nopadlock,	x86_cpu_clear,	CPU_PadLock
em64t,		x86_cpu_set,	CPU_EM64T
noem64t,	x86_cpu_clear,	CPU_EM64T
ssse3,		x86_cpu_set,	CPU_SSSE3
nossse3,	x86_cpu_clear,	CPU_SSSE3
sse4.1,		x86_cpu_set,	CPU_SSE41
nosse4.1,	x86_cpu_clear,	CPU_SSE41
sse41,		x86_cpu_set,	CPU_SSE41
nosse41,	x86_cpu_clear,	CPU_SSE41
sse4.2,		x86_cpu_set,	CPU_SSE42
nosse4.2,	x86_cpu_clear,	CPU_SSE42
sse42,		x86_cpu_set,	CPU_SSE42
nosse42,	x86_cpu_clear,	CPU_SSE42
sse4a,		x86_cpu_set,	CPU_SSE4a
nosse4a,	x86_cpu_clear,	CPU_SSE4a
sse4,		x86_cpu_set_sse4,	0
nosse4,		x86_cpu_clear_sse4,	0
xsave,		x86_cpu_set,	CPU_XSAVE
noxsave,	x86_cpu_clear,	CPU_XSAVE
avx,		x86_cpu_set,	CPU_AVX
noavx,		x86_cpu_clear,	CPU_AVX
fma,		x86_cpu_set,	CPU_FMA
nofma,		x86_cpu_clear,	CPU_FMA
aes,		x86_cpu_set,	CPU_AES
noaes,		x86_cpu_clear,	CPU_AES
clmul,		x86_cpu_set,	CPU_CLMUL
noclmul,	x86_cpu_clear,	CPU_CLMUL
pclmulqdq,	x86_cpu_set,	CPU_CLMUL
nopclmulqdq,	x86_cpu_clear,	CPU_CLMUL
movbe,		x86_cpu_set,	CPU_MOVBE
nomovbe,	x86_cpu_clear,	CPU_MOVBE
xop,		x86_cpu_set,	CPU_XOP
noxop,		x86_cpu_clear,	CPU_XOP
fma4,		x86_cpu_set,	CPU_FMA4
nofma4,		x86_cpu_clear,	CPU_FMA4
f16c,		x86_cpu_set,	CPU_F16C
nof16c,		x86_cpu_clear,	CPU_F16C
fsgsbase,	x86_cpu_set,	CPU_FSGSBASE
nofsgsbase,	x86_cpu_clear,	CPU_FSGSBASE
rdrand,		x86_cpu_set,	CPU_RDRAND
nordrand,	x86_cpu_clear,	CPU_RDRAND
xsaveopt,	x86_cpu_set,	CPU_XSAVEOPT
noxsaveopt,	x86_cpu_clear,	CPU_XSAVEOPT
eptvpid,	x86_cpu_set,	CPU_EPTVPID
noeptvpid,	x86_cpu_clear,	CPU_EPTVPID
smx,		x86_cpu_set,	CPU_SMX
nosmx,		x86_cpu_clear,	CPU_SMX
avx2,		x86_cpu_set,	CPU_AVX2
noavx2,		x86_cpu_clear,	CPU_AVX2
tsx,		x86_cpu_set,	CPU_TSX
notsx,		x86_cpu_clear,	CPU_TSX
bmi1,		x86_cpu_set,	CPU_BMI1
nobmi1,		x86_cpu_clear,	CPU_BMI1
bmi2,		x86_cpu_set,	CPU_BMI2
nobmi2,		x86_cpu_clear,	CPU_BMI2
invpcid,	x86_cpu_set,	CPU_INVPCID
noinvpcid,	x86_cpu_clear,	CPU_INVPCID
lzcnt,		x86_cpu_set,	CPU_LZCNT
nolzcnt,	x86_cpu_clear,	CPU_LZCNT
tbm,		x86_cpu_set,	CPU_TBM
notbm,	x86_cpu_clear,	CPU_TBM
sha,		x86_cpu_set,	CPU_SHA
nosha,		x86_cpu_clear,	CPU_SHA
smap,		x86_cpu_set,	CPU_SMAP
nosmap,		x86_cpu_clear,	CPU_SMAP
rdseed,		x86_cpu_set,	CPU_RDSEED
nordseed,	x86_cpu_clear,	CPU_RDSEED
adx,		x86_cpu_set,	CPU_ADX
noadx,		x86_cpu_clear,	CPU_ADX
prfchw,		x86_cpu_set,	CPU_PRFCHW
noprfchw,	x86_cpu_clear,	CPU_PRFCHW
# Change NOP patterns
basicnop,	x86_nop,	X86_NOP_BASIC
intelnop,	x86_nop,	X86_NOP_INTEL
amdnop,		x86_nop,	X86_NOP_AMD
%%

void
yasm_x86__parse_cpu(yasm_arch_x86 *arch_x86, const char *cpuid,
                    size_t cpuid_len)
{
    /*@null@*/ const struct cpu_parse_data *pdata;
    wordptr new_cpu;
    size_t i;
    static char lcaseid[16];

    if (cpuid_len > 15)
        return;
    for (i=0; i<cpuid_len; i++)
        lcaseid[i] = tolower(cpuid[i]);
    lcaseid[cpuid_len] = '\0';

    pdata = cpu_find(lcaseid, cpuid_len);
    if (!pdata) {
        yasm_warn_set(YASM_WARN_GENERAL,
                      N_("unrecognized CPU identifier `%s'"), cpuid);
        return;
    }

    new_cpu = BitVector_Clone(arch_x86->cpu_enables[arch_x86->active_cpu]);
    pdata->handler(new_cpu, arch_x86, pdata->data);

    /* try to find an existing match in the CPU table first */
    for (i=0; i<arch_x86->cpu_enables_size; i++) {
        if (BitVector_equal(arch_x86->cpu_enables[i], new_cpu)) {
            arch_x86->active_cpu = i;
            BitVector_Destroy(new_cpu);
            return;
        }
    }

    /* not found, need to add a new entry */
    arch_x86->active_cpu = arch_x86->cpu_enables_size++;
    arch_x86->cpu_enables =
        yasm_xrealloc(arch_x86->cpu_enables,
                      arch_x86->cpu_enables_size*sizeof(wordptr));
    arch_x86->cpu_enables[arch_x86->active_cpu] = new_cpu;
}