/* Inverse of compress (right). */ #include /* Inverse of compress2 (HD page 151). This version has no branches in the loop. Eight insns in the loop, giving 8*32 + 2 = 258 insns worst case. */ unsigned expand2(unsigned x, unsigned m) { unsigned r, s, b; // Result, shift, mask bit. r = 0; s = 0; do { b = m & 1; r = r | ((x & b) << s); s = s + 1; x = x >> b; m = m >> 1; } while (m != 0); return r; } /* Inverse of compress4 (HD page 153). I don't know a good way to do this. Seems like you have to move the bits that go a long distance first, to avoid overwriting. Maybe that problem could be solved by moving a bit by first subtracting it where it came from, and then adding it into the target location, with both subtraction and addition done with xor. Not sure. But we also have the problem of figuring out which bits move an odd number of positions, which an odd multiple of 2, etc. I don't know how to do that. A solution from Joseph Allen first does part of the compress right operation, to compute the five "move" quantities mv, and saves them in an array. Then it applies them to the data x in the reverse of the order in which they were computed. Can one do better (mainly, avoid saving lg(n) values)? Allen's solution did not work if the irrelevant bits are nonzero, but below is a modification of his program that does work in that case. The assignment to x in the second for-loop is doing a MUX operation with mv selecting bits from either x or x << (1 << i). I.e., letting y = x << (1 << i), it is computing (x & ~mv) | (y & mv) by means of the equivalent expression (which saves an instruction on a machine that doesn't have "and with complement") x ^ ((x ^ y) & mv). */ // ------------------------------ cut ---------------------------------- unsigned expand4(unsigned x, unsigned m) { unsigned m0, mk, mp, mv, t; unsigned array[5]; int i; m0 = m; // Save original mask. mk = ~m << 1; // We will count 0's to right. for (i = 0; i < 5; i++) { mp = mk ^ (mk << 1); // Parallel suffix. mp = mp ^ (mp << 2); mp = mp ^ (mp << 4); mp = mp ^ (mp << 8); mp = mp ^ (mp << 16); mv = mp & m; // Bits to move. array[i] = mv; m = (m ^ mv) | (mv >> (1 << i)); // Compress m. mk = mk & ~mp; } for (i = 4; i >= 0; i--) { mv = array[i]; t = x << (1 << i); x = (x & ~mv) | (t & mv); // x = ((x ^ t) & mv) ^ x; // Alternative for above line. } return x & m0; // Clear out extraneous bits. } // ---------------------------- end cut -------------------------------- int errors; void error(unsigned x, unsigned m, unsigned got, unsigned shdbe) { errors = errors + 1; printf("Error for x = %08X, m = %08x, got %08X, should be %08X\n", x, m, got, shdbe); } int main(void) { int i, n; unsigned r; static unsigned test[] = { // Data Mask Result 0x00000001, 0x80000000, 0x80000000, // These first 4 cases will 0x0000001F, 0x0010084A, 0x0010084A, // work with Allen's "scatter" 0x0000FFFF, 0x55555555, 0x55555555, // function, because the 0x00001FFF, 0x88E00F55, 0x88E00F55, // irrelevant HO bits are 0. 0xFFFFFFFF, 0x80000000, 0x80000000, 0xFFFFFFFF, 0x0010084A, 0x0010084A, 0xFFFFFFFF, 0x55555555, 0x55555555, 0xFFFFFFFF, 0x88E00F55, 0x88E00F55, 0x01234567, 0x0000FFFF, 0x00004567, 0x01234567, 0xFFFF0000, 0x45670000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0, 0, 0, 0xFFFFFFFF, 0, 0xFFFFFFFF, 0, 0, 0x80000000, 0x80000000, 0, 0x55555555, 0x55555555, 0x11111111, 0x55555555, 0xAAAAAAAA, 0x22222222, 0x789ABCDE, 0x0F0F0F0F, 0x0B0C0D0E, 0x789ABCDE, 0xF0F0F0F0, 0xB0C0D0E0, 0x92345678, 0x80000000, 0, 0x12345678, 0xF0035555, 0x50021540, 0x80000000, 0xF0035555, 0, }; n = sizeof(test)/sizeof(test[0]); printf("expand2:\n"); for (i = 0; i < n; i += 3) { r = expand2(test[i], test[i+1]); if (r != test[i+2]) error(test[i], test[i+1], r, test[i+2]); } printf("expand4:\n"); for (i = 0; i < n; i += 3) { r = expand4(test[i], test[i+1]); if (r != test[i+2]) error(test[i], test[i+1], r, test[i+2]); } if (errors == 0) printf("Passed all %d cases.\n", n/3); return errors; }