#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef unsigned long long int ULong;
typedef unsigned int UInt;
typedef unsigned short UShort;
typedef unsigned char UChar;
typedef signed int Int;
typedef signed short Short;
typedef signed long int Word;
unsigned long myrandom(void)
{
/* Simple multiply-with-carry random generator. */
static unsigned long m_w = 11;
static unsigned long m_z = 13;
m_z = 36969 * (m_z & 65535) + (m_z >> 16);
m_w = 18000 * (m_w & 65535) + (m_w >> 16);
return (m_z << 16) + m_w;
}
/* ------------ MEM, Q ------------ */
ULong btsq_mem ( char* base, Word bitno )
{
UChar res;
__asm__
__volatile__("btsq\t%2, %0\n\t"
"setc\t%1"
: "=m" (*base), "=q" (res)
: "r" (bitno));
/* Pretty meaningless to dereference base here, but that's what you
have to do to get a btsl insn which refers to memory starting at
base. */
return res;
}
ULong btrq_mem ( char* base, Word bitno )
{
UChar res;
__asm__
__volatile__("btrq\t%2, %0\n\t"
"setc\t%1"
: "=m" (*base), "=q" (res)
: "r" (bitno));
return res;
}
ULong btcq_mem ( char* base, Word bitno )
{
UChar res;
__asm__
__volatile__("btcq\t%2, %0\n\t"
"setc\t%1"
: "=m" (*base), "=q" (res)
: "r" (bitno));
return res;
}
ULong btq_mem ( char* base, Word bitno )
{
UChar res;
__asm__
__volatile__("btq\t%2, %0\n\t"
"setc\t%1"
: "=m" (*base), "=q" (res)
: "r" (bitno)
: "cc", "memory");
return res;
}
/* ------------ MEM, L ------------ */
ULong btsl_mem ( char* base, Word bitno )
{
UChar res;
__asm__
__volatile__("btsl\t%2, %0\n\t"
"setc\t%1"
: "=m" (*base), "=q" (res)
: "r" ((Int)bitno));
/* Pretty meaningless to dereference base here, but that's what you
have to do to get a btsl insn which refers to memory starting at
base. */
return res;
}
ULong btrl_mem ( char* base, Word bitno )
{
UChar res;
__asm__
__volatile__("btrl\t%2, %0\n\t"
"setc\t%1"
: "=m" (*base), "=q" (res)
: "r" ((Int)bitno));
return res;
}
ULong btcl_mem ( char* base, Word bitno )
{
UChar res;
__asm__
__volatile__("btcl\t%2, %0\n\t"
"setc\t%1"
: "=m" (*base), "=q" (res)
: "r" ((Int)bitno));
return res;
}
ULong btl_mem ( char* base, Word bitno )
{
UChar res;
__asm__
__volatile__("btl\t%2, %0\n\t"
"setc\t%1"
: "=m" (*base), "=q" (res)
: "r" ((Int)bitno)
: "cc", "memory");
return res;
}
/* ------------ MEM, W ------------ */
ULong btsw_mem ( char* base, Word bitno )
{
UChar res;
__asm__
__volatile__("btsw\t%2, %0\n\t"
"setc\t%1"
: "=m" (*base), "=q" (res)
: "r" ((Short)bitno));
/* Pretty meaningless to dereference base here, but that's what you
have to do to get a btsl insn which refers to memory starting at
base. */
return res;
}
ULong btrw_mem ( char* base, Word bitno )
{
UChar res;
__asm__
__volatile__("btrw\t%2, %0\n\t"
"setc\t%1"
: "=m" (*base), "=q" (res)
: "r" ((Short)bitno));
return res;
}
ULong btcw_mem ( char* base, Word bitno )
{
UChar res;
__asm__
__volatile__("btcw\t%2, %0\n\t"
"setc\t%1"
: "=m" (*base), "=q" (res)
: "r" ((Short)bitno));
return res;
}
ULong btw_mem ( char* base, Word bitno )
{
UChar res;
__asm__
__volatile__("btw\t%2, %0\n\t"
"setc\t%1"
: "=m" (*base), "=q" (res)
: "r" ((Short)bitno)
: "cc", "memory");
return res;
}
/* ------------ REG, Q ------------ */
ULong btsq_reg ( ULong reg_in, Word bitno,
ULong* reg_out_p )
{
UChar res;
ULong reg_out;
__asm__
__volatile__("movq\t%3, %%rax\n\t"
"btsq\t%2, %%rax\n\t"
"movq\t%%rax, %1\n\t"
"setc\t%0"
: "=q" (res), "=r" (reg_out)
: "r" (bitno), "r" (reg_in)
: "cc", "eax");
*reg_out_p = reg_out;
return res;
}
ULong btrq_reg ( ULong reg_in, Word bitno,
ULong* reg_out_p )
{
UChar res;
ULong reg_out;
__asm__
__volatile__("movq\t%3, %%rax\n\t"
"btrq\t%2, %%rax\n\t"
"movq\t%%rax, %1\n\t"
"setc\t%0"
: "=q" (res), "=r" (reg_out)
: "r" (bitno), "r" (reg_in)
: "cc", "eax");
*reg_out_p = reg_out;
return res;
}
ULong btcq_reg ( ULong reg_in, Word bitno,
ULong* reg_out_p )
{
UChar res;
ULong reg_out;
__asm__
__volatile__("movq\t%3, %%rax\n\t"
"btcq\t%2, %%rax\n\t"
"movq\t%%rax, %1\n\t"
"setc\t%0"
: "=q" (res), "=r" (reg_out)
: "r" (bitno), "r" (reg_in)
: "cc", "eax");
*reg_out_p = reg_out;
return res;
}
ULong btq_reg ( ULong reg_in, Word bitno,
ULong* reg_out_p )
{
UChar res;
ULong reg_out;
__asm__
__volatile__("movq\t%3, %%rax\n\t"
"btq\t%2, %%rax\n\t"
"movq\t%%rax, %1\n\t"
"setc\t%0"
: "=q" (res), "=r" (reg_out)
: "r" (bitno), "r" (reg_in)
: "cc", "eax");
*reg_out_p = reg_out;
return res;
}
/* ------------ REG, L ------------ */
ULong btsl_reg ( ULong reg_in, Word bitno,
ULong* reg_out_p )
{
UChar res;
ULong reg_out;
__asm__
__volatile__("movq\t%3, %%rax\n\t"
"btsl\t%2, %%eax\n\t"
"movq\t%%rax, %1\n\t"
"setc\t%0"
: "=q" (res), "=r" (reg_out)
: "r" ((Int)bitno), "r" (reg_in)
: "cc", "eax");
*reg_out_p = reg_out;
return res;
}
ULong btrl_reg ( ULong reg_in, Word bitno,
ULong* reg_out_p )
{
UChar res;
ULong reg_out;
__asm__
__volatile__("movq\t%3, %%rax\n\t"
"btrl\t%2, %%eax\n\t"
"movq\t%%rax, %1\n\t"
"setc\t%0"
: "=q" (res), "=r" (reg_out)
: "r" ((Int)bitno), "r" (reg_in)
: "cc", "eax");
*reg_out_p = reg_out;
return res;
}
ULong btcl_reg ( ULong reg_in, Word bitno,
ULong* reg_out_p )
{
UChar res;
ULong reg_out;
__asm__
__volatile__("movq\t%3, %%rax\n\t"
"btcl\t%2, %%eax\n\t"
"movq\t%%rax, %1\n\t"
"setc\t%0"
: "=q" (res), "=r" (reg_out)
: "r" ((Int)bitno), "r" (reg_in)
: "cc", "eax");
*reg_out_p = reg_out;
return res;
}
ULong btl_reg ( ULong reg_in, Word bitno,
ULong* reg_out_p )
{
UChar res;
ULong reg_out;
__asm__
__volatile__("movq\t%3, %%rax\n\t"
"btl\t%2, %%eax\n\t"
"movq\t%%rax, %1\n\t"
"setc\t%0"
: "=q" (res), "=r" (reg_out)
: "r" ((Int)bitno), "r" (reg_in)
: "cc", "eax");
*reg_out_p = reg_out;
return res;
}
/* ------------ REG, W ------------ */
ULong btsw_reg ( ULong reg_in, Word bitno,
ULong* reg_out_p )
{
UChar res;
ULong reg_out;
__asm__
__volatile__("movq\t%3, %%rax\n\t"
"btsw\t%2, %%ax\n\t"
"movq\t%%rax, %1\n\t"
"setc\t%0"
: "=q" (res), "=r" (reg_out)
: "r" ((Short)bitno), "r" (reg_in)
: "cc", "eax");
*reg_out_p = reg_out;
return res;
}
ULong btrw_reg ( ULong reg_in, Word bitno,
ULong* reg_out_p )
{
UChar res;
ULong reg_out;
__asm__
__volatile__("movq\t%3, %%rax\n\t"
"btrw\t%2, %%ax\n\t"
"movq\t%%rax, %1\n\t"
"setc\t%0"
: "=q" (res), "=r" (reg_out)
: "r" ((Short)bitno), "r" (reg_in)
: "cc", "eax");
*reg_out_p = reg_out;
return res;
}
ULong btcw_reg ( ULong reg_in, Word bitno,
ULong* reg_out_p )
{
UChar res;
ULong reg_out;
__asm__
__volatile__("movq\t%3, %%rax\n\t"
"btcw\t%2, %%ax\n\t"
"movq\t%%rax, %1\n\t"
"setc\t%0"
: "=q" (res), "=r" (reg_out)
: "r" ((Short)bitno), "r" (reg_in)
: "cc", "eax");
*reg_out_p = reg_out;
return res;
}
ULong btw_reg ( ULong reg_in, Word bitno,
ULong* reg_out_p )
{
UChar res;
ULong reg_out;
__asm__
__volatile__("movq\t%3, %%rax\n\t"
"btw\t%2, %%ax\n\t"
"movq\t%%rax, %1\n\t"
"setc\t%0"
: "=q" (res), "=r" (reg_out)
: "r" ((Short)bitno), "r" (reg_in)
: "cc", "eax");
*reg_out_p = reg_out;
return res;
}
ULong rol1 ( ULong x )
{
return (x << 1) | (x >> 63);
}
int main ( void )
{
UInt n, op;
ULong carrydep, c, res;
char* block;
ULong reg;
Word bitoff;
/*------------------------ MEM-L -----------------------*/
carrydep = 0;
block = calloc(200,1);
block += 100;
/* Valid bit offsets are -800 .. 799 inclusive. */
for (n = 0; n < 10000; n++) {
bitoff = (myrandom() % 1600) - 800;
op = myrandom() % 12;
c = 2;
switch (op) {
case 0: c = btsl_mem(block, bitoff); break;
case 1: c = btrl_mem(block, bitoff); break;
case 2: c = btcl_mem(block, bitoff); break;
case 3: c = btl_mem(block, bitoff); break;
case 4: c = btsq_mem(block, bitoff); break;
case 5: c = btrq_mem(block, bitoff); break;
case 6: c = btcq_mem(block, bitoff); break;
case 7: c = btq_mem(block, bitoff); break;
case 8: c = btsw_mem(block, bitoff); break;
case 9: c = btrw_mem(block, bitoff); break;
case 10: c = btcw_mem(block, bitoff); break;
case 11: c = btw_mem(block, bitoff); break;
default: assert(0);
}
assert(c == 0 || c == 1);
carrydep = c ? (rol1(carrydep) ^ bitoff) : carrydep;
}
/* Compute final result */
block -= 100;
res = 0;
for (n = 0; n < 200; n++) {
UChar ch = block[n];
/* printf("%d ", (int)block[n]); */
res = rol1(res) ^ (UInt)ch;
}
printf("MEM-L: final res 0x%llx, carrydep 0x%llx\n", res, carrydep);
/*------------------------ REG-L -----------------------*/
carrydep = 0;
reg = 0;
for (n = 0; n < 1000; n++) {
bitoff = (myrandom() % 100) - 50;
op = myrandom() % 12;
c = 2;
switch (op) {
case 0: c = btsl_reg(reg, bitoff, ®); break;
case 1: c = btrl_reg(reg, bitoff, ®); break;
case 2: c = btcl_reg(reg, bitoff, ®); break;
case 3: c = btl_reg(reg, bitoff, ®); break;
case 4: c = btsq_reg(reg, bitoff, ®); break;
case 5: c = btrq_reg(reg, bitoff, ®); break;
case 6: c = btcq_reg(reg, bitoff, ®); break;
case 7: c = btq_reg(reg, bitoff, ®); break;
case 8: c = btsw_reg(reg, bitoff, ®); break;
case 9: c = btrw_reg(reg, bitoff, ®); break;
case 10: c = btcw_reg(reg, bitoff, ®); break;
case 11: c = btw_reg(reg, bitoff, ®); break;
default: assert(0);
}
assert(c == 0 || c == 1);
carrydep = c ? (rol1(carrydep) ^ bitoff) : carrydep;
}
printf("REG-L: final res 0x%llx, carrydep 0x%llx\n", reg, carrydep);
block += 100;
/* Just try one of these at once; more than one can cause a
confusing merging of error messages. */
//btsl_mem(block, -800); /* should not complain */
//btsl_mem(block, -801); /* should complain */
//btsl_mem(block, 799); /* should not complain */
//btsl_mem(block, 800); /* should complain */
block -= 100;
free(block);
return 0;
}