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