1
2#include <stdio.h>
3#include <stdlib.h>
4#include <assert.h>
5
6typedef unsigned long long int ULong;
7typedef unsigned int   UInt;
8typedef unsigned short UShort;
9typedef unsigned char  UChar;
10
11typedef signed int    Int;
12typedef signed short  Short;
13
14typedef signed long int  Word;
15
16/* ------------ MEM, Q ------------ */
17
18ULong 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
32ULong 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
43ULong 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
54ULong 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
69ULong 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
83ULong 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
94ULong 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
105ULong 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
121ULong 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
135ULong 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
146ULong 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
157ULong 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
173ULong 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
191ULong 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
209ULong 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
227ULong 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
248ULong 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
266ULong 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
284ULong 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
302ULong 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
323ULong 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
341ULong 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
359ULong 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
377ULong 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
400ULong rol1 ( ULong x )
401{
402  return (x << 1) | (x >> 63);
403}
404
405int 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, &reg); break;
465         case  1: c = btrl_reg(reg, bitoff, &reg); break;
466         case  2: c = btcl_reg(reg, bitoff, &reg); break;
467         case  3: c =  btl_reg(reg, bitoff, &reg); break;
468         case  4: c = btsq_reg(reg, bitoff, &reg); break;
469         case  5: c = btrq_reg(reg, bitoff, &reg); break;
470         case  6: c = btcq_reg(reg, bitoff, &reg); break;
471         case  7: c =  btq_reg(reg, bitoff, &reg); break;
472         case  8: c = btsw_reg(reg, bitoff, &reg); break;
473         case  9: c = btrw_reg(reg, bitoff, &reg); break;
474         case 10: c = btcw_reg(reg, bitoff, &reg); break;
475         case 11: c =  btw_reg(reg, bitoff, &reg); 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