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
16unsigned 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
30ULong 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
44ULong 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
55ULong 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
66ULong 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
81ULong 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
95ULong 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
106ULong 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
117ULong 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
133ULong 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
147ULong 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
158ULong 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
169ULong 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
185ULong 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
203ULong 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
221ULong 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
239ULong 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
260ULong 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
278ULong 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
296ULong 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
314ULong 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
335ULong 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
353ULong 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
371ULong 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
389ULong 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
412ULong rol1 ( ULong x )
413{
414  return (x << 1) | (x >> 63);
415}
416
417int 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, &reg); break;
477         case  1: c = btrl_reg(reg, bitoff, &reg); break;
478         case  2: c = btcl_reg(reg, bitoff, &reg); break;
479         case  3: c =  btl_reg(reg, bitoff, &reg); break;
480         case  4: c = btsq_reg(reg, bitoff, &reg); break;
481         case  5: c = btrq_reg(reg, bitoff, &reg); break;
482         case  6: c = btcq_reg(reg, bitoff, &reg); break;
483         case  7: c =  btq_reg(reg, bitoff, &reg); break;
484         case  8: c = btsw_reg(reg, bitoff, &reg); break;
485         case  9: c = btrw_reg(reg, bitoff, &reg); break;
486         case 10: c = btcw_reg(reg, bitoff, &reg); break;
487         case 11: c =  btw_reg(reg, bitoff, &reg); 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