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.

tests/decompiler_fixtures/src/53_pseudorandom.c source
#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/3
bounded_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/3
bounded_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/3
bounded_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/3
bounded_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);
}

← 213 fixtures