Home | History | Annotate | Download | only in amd64
      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 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 
     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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    412 ULong rol1 ( ULong x )
    413 {
    414   return (x << 1) | (x >> 63);
    415 }
    416 
    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, &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