1
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <assert.h>
5
6 typedef unsigned long long int ULong;
7 typedef unsigned int UInt;
8 typedef unsigned short UShort;
9 typedef unsigned char UChar;
10
11 typedef signed int Int;
12 typedef signed short Short;
13
14 typedef signed long int Word;
15
myrandom(void)16 unsigned long myrandom(void)
17 {
18 /* Simple multiply-with-carry random generator. */
19 static unsigned long m_w = 11;
20 static unsigned long m_z = 13;
21
22 m_z = 36969 * (m_z & 65535) + (m_z >> 16);
23 m_w = 18000 * (m_w & 65535) + (m_w >> 16);
24
25 return (m_z << 16) + m_w;
26 }
27
28 /* ------------ MEM, Q ------------ */
29
btsq_mem(char * base,Word bitno)30 ULong btsq_mem ( char* base, Word bitno )
31 {
32 UChar res;
33 __asm__
34 __volatile__("btsq\t%2, %0\n\t"
35 "setc\t%1"
36 : "=m" (*base), "=q" (res)
37 : "r" (bitno));
38 /* Pretty meaningless to dereference base here, but that's what you
39 have to do to get a btsl insn which refers to memory starting at
40 base. */
41 return res;
42 }
43
btrq_mem(char * base,Word bitno)44 ULong btrq_mem ( char* base, Word bitno )
45 {
46 UChar res;
47 __asm__
48 __volatile__("btrq\t%2, %0\n\t"
49 "setc\t%1"
50 : "=m" (*base), "=q" (res)
51 : "r" (bitno));
52 return res;
53 }
54
btcq_mem(char * base,Word bitno)55 ULong btcq_mem ( char* base, Word bitno )
56 {
57 UChar res;
58 __asm__
59 __volatile__("btcq\t%2, %0\n\t"
60 "setc\t%1"
61 : "=m" (*base), "=q" (res)
62 : "r" (bitno));
63 return res;
64 }
65
btq_mem(char * base,Word bitno)66 ULong btq_mem ( char* base, Word bitno )
67 {
68 UChar res;
69 __asm__
70 __volatile__("btq\t%2, %0\n\t"
71 "setc\t%1"
72 : "=m" (*base), "=q" (res)
73 : "r" (bitno)
74 : "cc", "memory");
75 return res;
76 }
77
78
79 /* ------------ MEM, L ------------ */
80
btsl_mem(char * base,Word bitno)81 ULong btsl_mem ( char* base, Word bitno )
82 {
83 UChar res;
84 __asm__
85 __volatile__("btsl\t%2, %0\n\t"
86 "setc\t%1"
87 : "=m" (*base), "=q" (res)
88 : "r" ((Int)bitno));
89 /* Pretty meaningless to dereference base here, but that's what you
90 have to do to get a btsl insn which refers to memory starting at
91 base. */
92 return res;
93 }
94
btrl_mem(char * base,Word bitno)95 ULong btrl_mem ( char* base, Word bitno )
96 {
97 UChar res;
98 __asm__
99 __volatile__("btrl\t%2, %0\n\t"
100 "setc\t%1"
101 : "=m" (*base), "=q" (res)
102 : "r" ((Int)bitno));
103 return res;
104 }
105
btcl_mem(char * base,Word bitno)106 ULong btcl_mem ( char* base, Word bitno )
107 {
108 UChar res;
109 __asm__
110 __volatile__("btcl\t%2, %0\n\t"
111 "setc\t%1"
112 : "=m" (*base), "=q" (res)
113 : "r" ((Int)bitno));
114 return res;
115 }
116
btl_mem(char * base,Word bitno)117 ULong btl_mem ( char* base, Word bitno )
118 {
119 UChar res;
120 __asm__
121 __volatile__("btl\t%2, %0\n\t"
122 "setc\t%1"
123 : "=m" (*base), "=q" (res)
124 : "r" ((Int)bitno)
125 : "cc", "memory");
126 return res;
127 }
128
129
130
131 /* ------------ MEM, W ------------ */
132
btsw_mem(char * base,Word bitno)133 ULong btsw_mem ( char* base, Word bitno )
134 {
135 UChar res;
136 __asm__
137 __volatile__("btsw\t%2, %0\n\t"
138 "setc\t%1"
139 : "=m" (*base), "=q" (res)
140 : "r" ((Short)bitno));
141 /* Pretty meaningless to dereference base here, but that's what you
142 have to do to get a btsl insn which refers to memory starting at
143 base. */
144 return res;
145 }
146
btrw_mem(char * base,Word bitno)147 ULong btrw_mem ( char* base, Word bitno )
148 {
149 UChar res;
150 __asm__
151 __volatile__("btrw\t%2, %0\n\t"
152 "setc\t%1"
153 : "=m" (*base), "=q" (res)
154 : "r" ((Short)bitno));
155 return res;
156 }
157
btcw_mem(char * base,Word bitno)158 ULong btcw_mem ( char* base, Word bitno )
159 {
160 UChar res;
161 __asm__
162 __volatile__("btcw\t%2, %0\n\t"
163 "setc\t%1"
164 : "=m" (*base), "=q" (res)
165 : "r" ((Short)bitno));
166 return res;
167 }
168
btw_mem(char * base,Word bitno)169 ULong btw_mem ( char* base, Word bitno )
170 {
171 UChar res;
172 __asm__
173 __volatile__("btw\t%2, %0\n\t"
174 "setc\t%1"
175 : "=m" (*base), "=q" (res)
176 : "r" ((Short)bitno)
177 : "cc", "memory");
178 return res;
179 }
180
181
182
183 /* ------------ REG, Q ------------ */
184
btsq_reg(ULong reg_in,Word bitno,ULong * reg_out_p)185 ULong btsq_reg ( ULong reg_in, Word bitno,
186 ULong* reg_out_p )
187 {
188 UChar res;
189 ULong reg_out;
190 __asm__
191 __volatile__("movq\t%3, %%rax\n\t"
192 "btsq\t%2, %%rax\n\t"
193 "movq\t%%rax, %1\n\t"
194 "setc\t%0"
195 : "=q" (res), "=r" (reg_out)
196 : "r" (bitno), "r" (reg_in)
197 : "cc", "eax");
198 *reg_out_p = reg_out;
199 return res;
200 }
201
202
btrq_reg(ULong reg_in,Word bitno,ULong * reg_out_p)203 ULong btrq_reg ( ULong reg_in, Word bitno,
204 ULong* reg_out_p )
205 {
206 UChar res;
207 ULong reg_out;
208 __asm__
209 __volatile__("movq\t%3, %%rax\n\t"
210 "btrq\t%2, %%rax\n\t"
211 "movq\t%%rax, %1\n\t"
212 "setc\t%0"
213 : "=q" (res), "=r" (reg_out)
214 : "r" (bitno), "r" (reg_in)
215 : "cc", "eax");
216 *reg_out_p = reg_out;
217 return res;
218 }
219
220
btcq_reg(ULong reg_in,Word bitno,ULong * reg_out_p)221 ULong btcq_reg ( ULong reg_in, Word bitno,
222 ULong* reg_out_p )
223 {
224 UChar res;
225 ULong reg_out;
226 __asm__
227 __volatile__("movq\t%3, %%rax\n\t"
228 "btcq\t%2, %%rax\n\t"
229 "movq\t%%rax, %1\n\t"
230 "setc\t%0"
231 : "=q" (res), "=r" (reg_out)
232 : "r" (bitno), "r" (reg_in)
233 : "cc", "eax");
234 *reg_out_p = reg_out;
235 return res;
236 }
237
238
btq_reg(ULong reg_in,Word bitno,ULong * reg_out_p)239 ULong btq_reg ( ULong reg_in, Word bitno,
240 ULong* reg_out_p )
241 {
242 UChar res;
243 ULong reg_out;
244 __asm__
245 __volatile__("movq\t%3, %%rax\n\t"
246 "btq\t%2, %%rax\n\t"
247 "movq\t%%rax, %1\n\t"
248 "setc\t%0"
249 : "=q" (res), "=r" (reg_out)
250 : "r" (bitno), "r" (reg_in)
251 : "cc", "eax");
252 *reg_out_p = reg_out;
253 return res;
254 }
255
256
257
258 /* ------------ REG, L ------------ */
259
btsl_reg(ULong reg_in,Word bitno,ULong * reg_out_p)260 ULong btsl_reg ( ULong reg_in, Word bitno,
261 ULong* reg_out_p )
262 {
263 UChar res;
264 ULong reg_out;
265 __asm__
266 __volatile__("movq\t%3, %%rax\n\t"
267 "btsl\t%2, %%eax\n\t"
268 "movq\t%%rax, %1\n\t"
269 "setc\t%0"
270 : "=q" (res), "=r" (reg_out)
271 : "r" ((Int)bitno), "r" (reg_in)
272 : "cc", "eax");
273 *reg_out_p = reg_out;
274 return res;
275 }
276
277
btrl_reg(ULong reg_in,Word bitno,ULong * reg_out_p)278 ULong btrl_reg ( ULong reg_in, Word bitno,
279 ULong* reg_out_p )
280 {
281 UChar res;
282 ULong reg_out;
283 __asm__
284 __volatile__("movq\t%3, %%rax\n\t"
285 "btrl\t%2, %%eax\n\t"
286 "movq\t%%rax, %1\n\t"
287 "setc\t%0"
288 : "=q" (res), "=r" (reg_out)
289 : "r" ((Int)bitno), "r" (reg_in)
290 : "cc", "eax");
291 *reg_out_p = reg_out;
292 return res;
293 }
294
295
btcl_reg(ULong reg_in,Word bitno,ULong * reg_out_p)296 ULong btcl_reg ( ULong reg_in, Word bitno,
297 ULong* reg_out_p )
298 {
299 UChar res;
300 ULong reg_out;
301 __asm__
302 __volatile__("movq\t%3, %%rax\n\t"
303 "btcl\t%2, %%eax\n\t"
304 "movq\t%%rax, %1\n\t"
305 "setc\t%0"
306 : "=q" (res), "=r" (reg_out)
307 : "r" ((Int)bitno), "r" (reg_in)
308 : "cc", "eax");
309 *reg_out_p = reg_out;
310 return res;
311 }
312
313
btl_reg(ULong reg_in,Word bitno,ULong * reg_out_p)314 ULong btl_reg ( ULong reg_in, Word bitno,
315 ULong* reg_out_p )
316 {
317 UChar res;
318 ULong reg_out;
319 __asm__
320 __volatile__("movq\t%3, %%rax\n\t"
321 "btl\t%2, %%eax\n\t"
322 "movq\t%%rax, %1\n\t"
323 "setc\t%0"
324 : "=q" (res), "=r" (reg_out)
325 : "r" ((Int)bitno), "r" (reg_in)
326 : "cc", "eax");
327 *reg_out_p = reg_out;
328 return res;
329 }
330
331
332
333 /* ------------ REG, W ------------ */
334
btsw_reg(ULong reg_in,Word bitno,ULong * reg_out_p)335 ULong btsw_reg ( ULong reg_in, Word bitno,
336 ULong* reg_out_p )
337 {
338 UChar res;
339 ULong reg_out;
340 __asm__
341 __volatile__("movq\t%3, %%rax\n\t"
342 "btsw\t%2, %%ax\n\t"
343 "movq\t%%rax, %1\n\t"
344 "setc\t%0"
345 : "=q" (res), "=r" (reg_out)
346 : "r" ((Short)bitno), "r" (reg_in)
347 : "cc", "eax");
348 *reg_out_p = reg_out;
349 return res;
350 }
351
352
btrw_reg(ULong reg_in,Word bitno,ULong * reg_out_p)353 ULong btrw_reg ( ULong reg_in, Word bitno,
354 ULong* reg_out_p )
355 {
356 UChar res;
357 ULong reg_out;
358 __asm__
359 __volatile__("movq\t%3, %%rax\n\t"
360 "btrw\t%2, %%ax\n\t"
361 "movq\t%%rax, %1\n\t"
362 "setc\t%0"
363 : "=q" (res), "=r" (reg_out)
364 : "r" ((Short)bitno), "r" (reg_in)
365 : "cc", "eax");
366 *reg_out_p = reg_out;
367 return res;
368 }
369
370
btcw_reg(ULong reg_in,Word bitno,ULong * reg_out_p)371 ULong btcw_reg ( ULong reg_in, Word bitno,
372 ULong* reg_out_p )
373 {
374 UChar res;
375 ULong reg_out;
376 __asm__
377 __volatile__("movq\t%3, %%rax\n\t"
378 "btcw\t%2, %%ax\n\t"
379 "movq\t%%rax, %1\n\t"
380 "setc\t%0"
381 : "=q" (res), "=r" (reg_out)
382 : "r" ((Short)bitno), "r" (reg_in)
383 : "cc", "eax");
384 *reg_out_p = reg_out;
385 return res;
386 }
387
388
btw_reg(ULong reg_in,Word bitno,ULong * reg_out_p)389 ULong btw_reg ( ULong reg_in, Word bitno,
390 ULong* reg_out_p )
391 {
392 UChar res;
393 ULong reg_out;
394 __asm__
395 __volatile__("movq\t%3, %%rax\n\t"
396 "btw\t%2, %%ax\n\t"
397 "movq\t%%rax, %1\n\t"
398 "setc\t%0"
399 : "=q" (res), "=r" (reg_out)
400 : "r" ((Short)bitno), "r" (reg_in)
401 : "cc", "eax");
402 *reg_out_p = reg_out;
403 return res;
404 }
405
406
407
408
409
410
411
rol1(ULong x)412 ULong rol1 ( ULong x )
413 {
414 return (x << 1) | (x >> 63);
415 }
416
main(void)417 int main ( void )
418 {
419 UInt n, op;
420 ULong carrydep, c, res;
421 char* block;
422 ULong reg;
423 Word bitoff;
424
425 /*------------------------ MEM-L -----------------------*/
426
427 carrydep = 0;
428 block = calloc(200,1);
429 block += 100;
430 /* Valid bit offsets are -800 .. 799 inclusive. */
431
432 for (n = 0; n < 10000; n++) {
433 bitoff = (myrandom() % 1600) - 800;
434 op = myrandom() % 12;
435 c = 2;
436 switch (op) {
437 case 0: c = btsl_mem(block, bitoff); break;
438 case 1: c = btrl_mem(block, bitoff); break;
439 case 2: c = btcl_mem(block, bitoff); break;
440 case 3: c = btl_mem(block, bitoff); break;
441 case 4: c = btsq_mem(block, bitoff); break;
442 case 5: c = btrq_mem(block, bitoff); break;
443 case 6: c = btcq_mem(block, bitoff); break;
444 case 7: c = btq_mem(block, bitoff); break;
445 case 8: c = btsw_mem(block, bitoff); break;
446 case 9: c = btrw_mem(block, bitoff); break;
447 case 10: c = btcw_mem(block, bitoff); break;
448 case 11: c = btw_mem(block, bitoff); break;
449 default: assert(0);
450 }
451 assert(c == 0 || c == 1);
452 carrydep = c ? (rol1(carrydep) ^ bitoff) : carrydep;
453 }
454
455 /* Compute final result */
456 block -= 100;
457 res = 0;
458 for (n = 0; n < 200; n++) {
459 UChar ch = block[n];
460 /* printf("%d ", (int)block[n]); */
461 res = rol1(res) ^ (UInt)ch;
462 }
463
464 printf("MEM-L: final res 0x%llx, carrydep 0x%llx\n", res, carrydep);
465
466 /*------------------------ REG-L -----------------------*/
467
468 carrydep = 0;
469 reg = 0;
470
471 for (n = 0; n < 1000; n++) {
472 bitoff = (myrandom() % 100) - 50;
473 op = myrandom() % 12;
474 c = 2;
475 switch (op) {
476 case 0: c = btsl_reg(reg, bitoff, ®); break;
477 case 1: c = btrl_reg(reg, bitoff, ®); break;
478 case 2: c = btcl_reg(reg, bitoff, ®); break;
479 case 3: c = btl_reg(reg, bitoff, ®); break;
480 case 4: c = btsq_reg(reg, bitoff, ®); break;
481 case 5: c = btrq_reg(reg, bitoff, ®); break;
482 case 6: c = btcq_reg(reg, bitoff, ®); break;
483 case 7: c = btq_reg(reg, bitoff, ®); break;
484 case 8: c = btsw_reg(reg, bitoff, ®); break;
485 case 9: c = btrw_reg(reg, bitoff, ®); break;
486 case 10: c = btcw_reg(reg, bitoff, ®); break;
487 case 11: c = btw_reg(reg, bitoff, ®); break;
488 default: assert(0);
489 }
490 assert(c == 0 || c == 1);
491 carrydep = c ? (rol1(carrydep) ^ bitoff) : carrydep;
492 }
493
494 printf("REG-L: final res 0x%llx, carrydep 0x%llx\n", reg, carrydep);
495
496 block += 100;
497
498 /* Just try one of these at once; more than one can cause a
499 confusing merging of error messages. */
500 //btsl_mem(block, -800); /* should not complain */
501 //btsl_mem(block, -801); /* should complain */
502 //btsl_mem(block, 799); /* should not complain */
503 //btsl_mem(block, 800); /* should complain */
504
505 block -= 100;
506 free(block);
507
508 return 0;
509 }
510
511