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, ®); break; 477 case 1: c = btrl_reg(reg, bitoff, ®); break; 478 case 2: c = btcl_reg(reg, bitoff, ®); break; 479 case 3: c = btl_reg(reg, bitoff, ®); break; 480 case 4: c = btsq_reg(reg, bitoff, ®); break; 481 case 5: c = btrq_reg(reg, bitoff, ®); break; 482 case 6: c = btcq_reg(reg, bitoff, ®); break; 483 case 7: c = btq_reg(reg, bitoff, ®); break; 484 case 8: c = btsw_reg(reg, bitoff, ®); break; 485 case 9: c = btrw_reg(reg, bitoff, ®); break; 486 case 10: c = btcw_reg(reg, bitoff, ®); break; 487 case 11: c = btw_reg(reg, bitoff, ®); 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