From: Mark Wooding Date: Mon, 6 Jun 2016 10:01:46 +0000 (+0100) Subject: rand/rand.c (rdrand_quick): Improve the loop. X-Git-Tag: 2.2.3~1^2 X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/commitdiff_plain/c6c463ee1a9faac8b1439f62f85033074c18f96f?ds=sidebyside rand/rand.c (rdrand_quick): Improve the loop. The `RDRAND' instruction can fail, leaving carry clear. Previously, I just exposed the carry flag in a register (with `SETC'), and looped around in C. Rewrite the loop in assembler. This is makes the flow cleaner, and (coincidentally) avoids a dependency on the `SETcc' instructions (though if I thought a processor might have `RDRAND' and not `SETcc', I wouldn't have written the original code the way I did). But the main benefit is that I don't have nightmares about seeing ...; setc al; test al, al; ... sequences any more. There's still the issue of `i' being tested for zero twice, but I don't think I can fix that without resorting to `asm goto', and that has its own problems. --- diff --git a/rand/rand.c b/rand/rand.c index 29b180d8..f9f16d5d 100644 --- a/rand/rand.c +++ b/rand/rand.c @@ -165,17 +165,13 @@ static int trivial_quick(rand_pool *r) { return (-1); } static int rdrand_quick(rand_pool *r) { unsigned long rr; - unsigned char w; - int i; - - for (i = 0; i < 16; i++) { - __asm__ ("rdrand %0; setc %1" : "=r" (rr), "=g" (w) : : "cc"); - if (w) { - rand_add(r, &rr, sizeof(rr), 8*sizeof(rr)); - return (0); - } - } - return (-1); + int i = 16; + + __asm__ ("0: rdrand %0; jc 9f; dec %1; jnz 0b; 9:" + : "=r" (rr), "=r" (i) : "1" (i) : "cc"); + if (!i) return (-1); + rand_add(r, &rr, sizeof(rr), 8*sizeof(rr)); + return (0); } #endif