Fixture 53
pseudorandom
C · 3 functions · 4 lanes · 10 of 12 function-lanes behave identically
2 of 4 lanes have a function that returns a different result after decompilation: clang-O2 (2/3), gcc-O2 (2/3).
A 32-bit xorshift, a 64-bit linear congruential generator, and rejection sampling into a bounded range. The LCG exercises 64-bit multiply lowering on 32-bit targets; rejection sampling adds a data-dependent retry loop.
#include <stdint.h>
/* A 32-bit xorshift, a 64-bit linear congruential generator, and rejection
* sampling into a bounded range. The LCG exercises 64-bit multiply lowering
* on 32-bit targets; rejection sampling adds a data-dependent retry loop. */
#define PRNG_MAX 16
__attribute__((noinline)) uint32_t xorshift32(uint32_t state) {
if (state == 0u) {
state = 0x1234567u;
}
state ^= state << 13;
state ^= state >> 17;
state ^= state << 5;
return state;
}
__attribute__((noinline)) uint32_t lcg64_next_high(uint32_t seed) {
uint64_t state = (uint64_t)seed * 6364136223846793005ULL + 1442695040888963407ULL;
return (uint32_t)(state >> 33);
}
__attribute__((noinline)) int32_t
bounded_sample(uint32_t seed, int32_t bound, int32_t *output, int32_t count) {
uint32_t state = seed;
int32_t produced = 0;
int32_t guard = 0;
if (output == 0 || bound < 1 || bound > 1024 || count < 0 ||
count > PRNG_MAX) {
return -1;
}
while (produced < count && guard < PRNG_MAX * 64) {
uint32_t limit = 0xFFFFFFFFu - (0xFFFFFFFFu % (uint32_t)bound);
state = xorshift32(state);
guard += 1;
if (state > limit) {
continue;
}
output[produced] = (int32_t)(state % (uint32_t)bound);
produced += 1;
}
return produced;
} Recovered C
Generated by glaurung decompile --style decbench at b47f6b43.
baseline.json records the result after recompiling the C and calling it beside the
original with seeded inputs.
clang -O2
2/3bounded_sample fail 65 lines
// glaurung: bounded_sample @ 0x1160
int32_t bounded_sample(uint32_t arg0, int32_t arg1, int32_t * arg2, int32_t arg3) {
extern unsigned int xorshift32(unsigned int);
int produced;
unsigned int limit;
unsigned int state;
int guard;
long t178;
long var0;
int var12;
long var17;
unsigned int var19;
long var2;
long var4;
long var5;
long var7;
// x86-64 prologue: save callee registers, frame 56 bytes
var0 = 0xffffffff;
produced = 0xffffffff;
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg3))))) {
// x86-64 epilogue: restore callee registers
return (unsigned int)(produced);
}
var2 = (unsigned long)((unsigned int)(arg1));
produced = var0;
if (((unsigned long)((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) - 1025)))) < (unsigned long)(0xfffffc00))) {
// x86-64 epilogue: restore callee registers
return (unsigned int)(produced);
}
var4 = (long)arg2;
produced = var0;
if ((arg2 == 0)) {
// x86-64 epilogue: restore callee registers
return (unsigned int)(produced);
}
var5 = (unsigned long)((unsigned int)(arg3));
if (((unsigned long)((unsigned int)(arg3)) == 0)) {
produced = 0;
// x86-64 epilogue: restore callee registers
return 0;
}
var7 = 0;
var12 = ((unsigned int)(((((unsigned long long)(unsigned int)((unsigned long)((unsigned int)(0))) << 32) | (unsigned int)(0xffffffff)) % (unsigned int)(var2))));
limit = (~(unsigned long)((unsigned int)(var12)));
var17 = 0;
do {
var19 = ((unsigned int (*)(void))xorshift32)();
state = var19;
produced = var17;
if (((unsigned long)(var19) <= (unsigned long)(limit))) {
var12 = ((unsigned int)(((((unsigned long long)(unsigned int)((unsigned long)((unsigned int)(0))) << 32) | (unsigned int)(state)) % (unsigned int)(var2))));
*(int *)((var4 + ((long)((int)(var17)) * 4))) = var12;
produced = (unsigned long)((unsigned int)(((long)((int)(var17)) + 1)));
}
if (((long)((int)(var5)) <= (long)(produced))) {
// x86-64 epilogue: restore callee registers
return (unsigned int)(produced);
}
t178 = (unsigned long)((unsigned int)(var7));
var7 = (unsigned long)((unsigned int)((var7 + 1)));
var17 = (unsigned long)((unsigned int)(produced));
} while (((unsigned long)(t178) < (unsigned long)(1023)));
// x86-64 epilogue: restore callee registers
return (unsigned int)(produced);
} lcg64_next_high pass 5 lines
// glaurung: lcg64_next_high @ 0x1130
uint32_t lcg64_next_high(uint32_t arg0) {
unsigned long state;
return ((unsigned long)((0x14057b7ef767814f + (0x5851f42d4c957f2d * (unsigned long)(arg0)))) >> 33);
} xorshift32 pass 10 lines
// glaurung: xorshift32 @ 0x1110
uint32_t xorshift32(uint32_t arg0) {
int var1;
long var12;
long var6;
var1 = ((arg0 != 0) ? arg0 : 0x1234567);
var6 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var1)) << 13))) ^ var1)));
var12 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var6)) >> 17))) ^ var6)));
return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var12)) << 5))) ^ var12));
} gcc -O2
2/3bounded_sample fail 58 lines
// glaurung: bounded_sample @ 0x1180
int32_t bounded_sample(uint32_t arg0, int32_t arg1, int32_t * arg2, int32_t arg3) {
extern unsigned int xorshift32(unsigned int);
int guard;
unsigned int state;
int produced;
long var1;
int var10;
long var13;
long var14;
unsigned int var18;
long var2;
long var25;
long var6;
if (((unsigned long)(1023) < (unsigned long)((unsigned long)((unsigned int)((arg1 - 1)))))) {
goto L_1215;
}
var1 = (long)arg2;
if ((arg2 == 0)) {
goto L_1215;
}
var2 = (unsigned long)((unsigned int)(arg3));
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg3))))) {
goto L_1215;
}
if (((unsigned long)((unsigned int)(arg3)) == 0)) {
goto L_1210;
}
var6 = (unsigned long)((unsigned int)(arg1));
var10 = ((unsigned int)(((((unsigned long long)(unsigned int)((unsigned long)((unsigned int)(0))) << 32) | (unsigned int)(0xffffffff)) % (unsigned int)(arg1))));
var13 = (unsigned long)((unsigned int)(var10));
var14 = 0;
guard = 0;
do {
var18 = ((unsigned int (*)(void))xorshift32)();
guard = (unsigned long)((unsigned int)((guard + 1)));
state = var18;
var25 = var14;
if (((unsigned long)((unsigned long)((unsigned int)(var13))) <= (unsigned long)((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var13)) + var18)))))) {
var25 = (unsigned long)((unsigned int)((var14 + 1)));
var10 = ((unsigned int)(((((unsigned long long)(unsigned int)((unsigned long)((unsigned int)(0))) << 32) | (unsigned int)(state)) % (unsigned int)(var6))));
*(int *)((var1 + ((long)((int)(var14)) * 4))) = var10;
}
if (((long)((int)(var2)) <= (long)((int)(var25)))) {
goto L_11f8;
}
var14 = var25;
} while ((((unsigned long)((unsigned int)(guard)) == 1023) | ((long)(guard) < 1023)));
L_11f8: ;
// x86-64 epilogue: tear down frame
return (unsigned int)(var25);
L_1210: ;
var25 = 0;
goto L_11f8;
L_1215: ;
var25 = 0xffffffff;
goto L_11f8;
} lcg64_next_high pass 5 lines
// glaurung: lcg64_next_high @ 0x1150
uint32_t lcg64_next_high(uint32_t arg0) {
unsigned long state;
return ((unsigned long)((((unsigned long)(arg0) * 0x5851f42d4c957f2d) + 0x14057b7ef767814f)) >> 33);
} xorshift32 pass 13 lines
// glaurung: xorshift32 @ 0x1120
uint32_t xorshift32(uint32_t arg0) {
long ret;
long var10;
long var4;
ret = 0x587da5a0;
if ((arg0 != 0)) {
var4 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)((arg0 << 13))) ^ arg0)));
var10 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var4)) >> 17))) ^ var4)));
ret = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var10)) << 5))) ^ var10)));
}
return ret;
} clang -O0
3/3bounded_sample pass 68 lines
// glaurung: bounded_sample @ 0x11a0
int32_t bounded_sample(uint32_t arg0, int32_t arg1, int32_t * arg2, int32_t arg3) {
extern unsigned int xorshift32(unsigned int);
unsigned int state;
int produced;
int guard;
unsigned int limit;
signed char local_2d;
int local_4;
int var1;
unsigned int var16;
// x86-64 prologue: save rbp, frame 48 bytes
state = arg0;
produced = 0;
guard = 0;
if ((arg2 == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if (((long)(arg1) < 1)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if (((((unsigned long)((unsigned int)(arg1)) == 1024) | ((long)(arg1) < 1024)) == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if (((long)(arg3) < 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if (((((unsigned long)((unsigned int)(arg3)) == 16) | ((long)(arg3) < 16)) == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
var1 = (int)arg2;
L_1210: ;
while (1) {
local_2d = 0;
if ((produced < arg3)) {
local_2d = ((long)(guard) < 1024);
}
if (((unsigned long)((unsigned char)((local_2d & 1))) == 0)) {
goto L_1239;
}
var1 = ((unsigned int)(((((unsigned long long)(unsigned int)((unsigned long)((unsigned int)(0))) << 32) | (unsigned int)(0xffffffff)) % (unsigned int)(arg1))));
limit = (0xffffffff - var1);
var16 = xorshift32(state);
state = var16;
guard = ((unsigned int)(guard) + 1);
if (((unsigned long)(limit) < (unsigned long)(state))) {
goto L_1210;
}
var1 = ((unsigned int)(((((unsigned long long)(unsigned int)((unsigned long)((unsigned int)(0))) << 32) | (unsigned int)(state)) % (unsigned int)(arg1))));
arg2[(long)(produced)] = var1;
produced = ((unsigned int)(produced) + 1);
goto L_1210;
}
L_1239: ;
local_4 = produced;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} lcg64_next_high pass 8 lines
// glaurung: lcg64_next_high @ 0x1160
uint32_t lcg64_next_high(uint32_t arg0) {
unsigned long state;
// x86-64 prologue: save rbp
state = (((unsigned long)(arg0) * 0x5851f42d4c957f2d) + 0x14057b7ef767814f);
// x86-64 epilogue: restore rbp
return ((unsigned long)(state) >> 33);
} xorshift32 pass 14 lines
// glaurung: xorshift32 @ 0x1110
uint32_t xorshift32(uint32_t arg0) {
int local_4;
// x86-64 prologue: save rbp
local_4 = arg0;
if (((unsigned long)((unsigned int)(local_4)) == 0)) {
local_4 = 0x1234567;
}
local_4 = ((unsigned int)(((unsigned long)((unsigned int)(local_4)) << 13)) ^ local_4);
local_4 = ((unsigned int)(((unsigned long)((unsigned int)(local_4)) >> 17)) ^ local_4);
local_4 = ((unsigned int)(((unsigned long)((unsigned int)(local_4)) << 5)) ^ local_4);
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} gcc -O0
3/3bounded_sample pass 49 lines
// glaurung: bounded_sample @ 0x1188
int32_t bounded_sample(uint32_t arg0, int32_t arg1, int32_t * arg2, int32_t arg3) {
extern unsigned int xorshift32(unsigned int);
unsigned int state;
int produced;
int guard;
unsigned int limit;
unsigned int var10;
// x86-64 prologue: save rbp, frame 48 bytes
state = arg0;
produced = 0;
guard = 0;
if ((arg2 == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if ((((unsigned long)((unsigned int)(arg1)) == 0) | ((long)(arg1) < 0))) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if (((((unsigned long)((unsigned int)(arg1)) == 1024) | ((long)(arg1) < 1024)) == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if (((long)(arg3) < 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if (((((unsigned long)((unsigned int)(arg3)) == 16) | ((long)(arg3) < 16)) == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
while ((produced < arg3)) {
if (((((unsigned long)((unsigned int)(guard)) == 1023) | ((long)(guard) < 1023)) == 0)) {
break;
}
limit = (~(unsigned long)((unsigned int)(((unsigned int)(((((unsigned long long)(unsigned int)(0) << 32) | (unsigned int)(0xffffffff)) % (unsigned int)((unsigned long)((unsigned int)(arg1)))))))));
var10 = xorshift32(state);
state = var10;
guard = (guard + 1);
if (((unsigned long)(state) <= (unsigned long)(limit))) {
arg2[(long)(produced)] = ((unsigned int)(((((unsigned long long)(unsigned int)(0) << 32) | (unsigned int)(state)) % (unsigned int)((unsigned long)((unsigned int)(arg1))))));
produced = (produced + 1);
} else {
}
}
// x86-64 epilogue: restore rbp
return (unsigned int)(produced);
} lcg64_next_high pass 8 lines
// glaurung: lcg64_next_high @ 0x1151
uint32_t lcg64_next_high(uint32_t arg0) {
unsigned long state;
// x86-64 prologue: save rbp
state = (((unsigned long)(arg0) * 0x5851f42d4c957f2d) + 0x14057b7ef767814f);
// x86-64 epilogue: restore rbp
return ((unsigned long)(state) >> 33);
} xorshift32 pass 14 lines
// glaurung: xorshift32 @ 0x1119
uint32_t xorshift32(uint32_t arg0) {
int local_4;
// x86-64 prologue: save rbp
local_4 = arg0;
if (((unsigned long)((unsigned int)(local_4)) == 0)) {
local_4 = 0x1234567;
}
local_4 = (local_4 ^ (unsigned int)(((unsigned long)((unsigned int)(local_4)) << 13)));
local_4 = (local_4 ^ (unsigned int)(((unsigned long)((unsigned int)(local_4)) >> 17)));
local_4 = (local_4 ^ (unsigned int)(((unsigned long)((unsigned int)(local_4)) << 5)));
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}