Fixture 50

varint

C · 4 functions · 4 lanes · 16 of 16 function-lanes behave identically

All 4 lanes recompile and return the same results as the original.

LEB128 varint encode/decode with zigzag mapping for signed values. The continuation-bit loop mixes a 64-bit accumulator with a 7-bit shift, so the recovered shift amount and the accumulator width both matter.

tests/decompiler_fixtures/src/50_varint.c source
#include <stdint.h>

/* LEB128 varint encode/decode with zigzag mapping for signed values.  The
 * continuation-bit loop mixes a 64-bit accumulator with a 7-bit shift, so the
 * recovered shift amount and the accumulator width both matter. */

#define VARINT_MAX 16

__attribute__((noinline)) uint32_t zigzag_encode(int32_t value) {
    return ((uint32_t)value << 1) ^ (uint32_t)(value >> 31);
}

__attribute__((noinline)) int32_t zigzag_decode(uint32_t encoded) {
    return (int32_t)((encoded >> 1) ^ (uint32_t)(-(int32_t)(encoded & 1u)));
}

__attribute__((noinline)) int32_t
varint_encode(uint32_t value, uint8_t *output, int32_t capacity) {
    int32_t produced = 0;
    if (output == 0 || capacity < 1 || capacity > VARINT_MAX) {
        return -1;
    }
    do {
        uint8_t chunk = (uint8_t)(value & 0x7Fu);
        value >>= 7;
        if (value != 0u) {
            chunk |= 0x80u;
        }
        if (produced >= capacity) {
            return -2;
        }
        output[produced] = chunk;
        produced += 1;
    } while (value != 0u);
    return produced;
}

__attribute__((noinline)) int32_t
varint_decode(const uint8_t *input, int32_t length, uint32_t *value) {
    uint64_t accumulator = 0;
    int32_t shift = 0;
    int32_t index;
    if (input == 0 || value == 0 || length < 0 || length > VARINT_MAX) {
        return -1;
    }
    for (index = 0; index < length; ++index) {
        uint8_t chunk = input[index];
        if (shift > 28) {
            return -2;
        }
        accumulator |= (uint64_t)(chunk & 0x7Fu) << (uint32_t)shift;
        shift += 7;
        if ((chunk & 0x80u) == 0u) {
            if (accumulator > 0xFFFFFFFFULL) {
                return -3;
            }
            *value = (uint32_t)accumulator;
            return index + 1;
        }
    }
    return -4;
}

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 -O0

4/4
varint_decode pass 55 lines
// glaurung: varint_decode @ 0x1200
int32_t varint_decode(const uint8_t * arg0, int32_t arg1, uint32_t * arg2) {
    unsigned long accumulator;
    int shift;
    int index;
    unsigned char chunk;
    int local_4;
    accumulator = 0;
    shift = 0;
    if ((arg0 != 0)) {
        if ((arg2 != 0)) {
            if ((0 <= (long)(arg1))) {
                if ((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16))) {
                    goto L_1254;
                }
            }
        }
    }
    local_4 = -1;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
    L_1254: ;
    index = 0;
    L_125b: ;
    if ((arg1 <= index)) {
        goto L_1305;
    }
    chunk = arg0[index];
    if (((((unsigned long)((unsigned int)(shift)) == 28) | ((long)(shift) < 28)) == 0)) {
        local_4 = -2;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    accumulator = (((unsigned long)((unsigned int)(((unsigned int)(chunk) & 127))) << ((unsigned long)((unsigned int)(shift)) & 63)) | accumulator);
    shift = ((unsigned int)(shift) + 7);
    if (((unsigned long)((unsigned int)(((unsigned int)(chunk) & 128))) == 0)) {
        if (((unsigned long)(0xffffffff) < (unsigned long)(accumulator))) {
            local_4 = -3;
            // x86-64 epilogue: restore rbp
            return (unsigned int)(local_4);
        }
        *(int *)((long)arg2) = accumulator;
        local_4 = ((unsigned int)(index) + 1);
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    goto L_12f7;
    L_12f7: ;
    index = ((unsigned int)(index) + 1);
    goto L_125b;
    L_1305: ;
    local_4 = -4;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
varint_encode pass 38 lines
// glaurung: varint_encode @ 0x1140
int32_t varint_encode(uint32_t arg0, uint8_t * arg1, int32_t arg2) {
    int produced;
    unsigned char chunk;
    int local_4;
    produced = 0;
    if ((arg1 != 0)) {
        if ((1 <= (long)(arg2))) {
            if ((((unsigned long)((unsigned int)(arg2)) == 16) | ((long)(arg2) < 16))) {
                goto L_1180;
            }
        }
    }
    local_4 = -1;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
    L_1180: ;
    goto L_1185;
    L_1185: ;
    chunk = (arg0 & 127);
    arg0 = ((unsigned int)(arg0) >> 7);
    if ((arg0 != 0)) {
        chunk = (chunk | 128);
    }
    if ((arg2 <= produced)) {
        local_4 = -2;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    arg1[produced] = chunk;
    produced = ((unsigned int)(produced) + 1);
    if ((arg0 != 0)) {
        goto L_1185;
    }
    local_4 = produced;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
zigzag_decode pass 6 lines
// glaurung: zigzag_decode @ 0x1120
int32_t zigzag_decode(uint32_t arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) >> 1))) ^ (unsigned long)((unsigned int)((0 - (unsigned long)((unsigned int)(((unsigned long)(arg0) & 1))))))));
}
zigzag_encode pass 6 lines
// glaurung: zigzag_encode @ 0x1100
uint32_t zigzag_encode(int32_t arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) << 1))) ^ (unsigned long)((unsigned int)(((int)(arg0) >> 31)))));
}

clang -O2

4/4
varint_decode pass 80 lines
// glaurung: varint_decode @ 0x1180
int32_t varint_decode(const uint8_t * arg0, int32_t arg1, uint32_t * arg2) {
    unsigned long accumulator;
    int index;
    int shift;
    long ret;
    int var0;
    int var11;
    int var17;
    int var23;
    long var32;
    int var4;
    int var5;
    ret = 0xffffffff;
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        return ret;
    }
    if ((arg0 == 0)) {
        return ret;
    }
    if ((arg2 == 0)) {
        return ret;
    }
    ret = 0xfffffffc;
    if (((unsigned long)((unsigned int)(arg1)) == 0)) {
        return ret;
    }
    var0 = (unsigned int)((unsigned char)(*(char *)(((long)arg0))));
    accumulator = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var0)) & 127)));
    var4 = 1;
    if (((unsigned long)((unsigned char)((var0 & 128))) == 0)) {
        goto L_123c;
    }
    if (((unsigned long)((unsigned int)(arg1)) == 1)) {
        return ret;
    }
    var5 = (unsigned int)((unsigned char)(*(char *)(((long)arg0 + 0x1))));
    accumulator = ((unsigned long)((unsigned int)(accumulator)) | ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var5)) & 127))) << 7));
    var4 = 2;
    if (((unsigned long)((unsigned char)((var5 & 128))) == 0)) {
        goto L_123c;
    }
    if (((unsigned long)((unsigned int)(arg1)) == 2)) {
        return ret;
    }
    var11 = (unsigned int)((unsigned char)(*(char *)(((long)arg0 + 0x2))));
    accumulator = ((unsigned long)((unsigned int)(accumulator)) | ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var11)) & 127))) << 14));
    var4 = 3;
    if (((unsigned long)((unsigned char)((var11 & 128))) == 0)) {
        goto L_123c;
    }
    if (((unsigned long)((unsigned int)(arg1)) == 3)) {
        return ret;
    }
    var17 = (unsigned int)((unsigned char)(*(char *)(((long)arg0 + 0x3))));
    accumulator = ((unsigned long)((unsigned int)(accumulator)) | ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var17)) & 127))) << 21));
    var4 = 4;
    if (((unsigned long)((unsigned char)((var17 & 128))) != 0)) {
        goto L_1243;
    }
    L_123c: ;
    *(int *)(((long)arg2)) = accumulator;
    return (unsigned int)(var4);
    L_1243: ;
    if (((unsigned long)((unsigned int)(arg1)) == 4)) {
        return ret;
    }
    var23 = (unsigned int)((unsigned char)(*(char *)(((long)arg0 + 0x4))));
    if (((unsigned long)((unsigned char)((var23 & 128))) != 0)) {
        var32 = ((unsigned long)((unsigned int)(arg1)) != 5);
        return (unsigned int)(((unsigned long)((unsigned int)((var32 + var32))) | -4));
    }
    accumulator = (accumulator | ((unsigned long)((unsigned int)((var23 & 127))) << 28));
    var4 = 5;
    ret = 0xfffffffd;
    if ((((unsigned long)(accumulator) >> 32) == 0)) {
        goto L_123c;
    }
    return ret;
}
varint_encode pass 36 lines
// glaurung: varint_encode @ 0x1120
int32_t varint_encode(uint32_t arg0, uint8_t * arg1, int32_t arg2) {
    int produced;
    unsigned char chunk;
    long cf_12;
    long ret;
    long var2;
    long var5;
    long zf_12;
    ret = 0xffffffff;
    if ((arg1 == 0)) {
        return ret;
    }
    ret = 0xffffffff;
    if (((unsigned long)((unsigned long)((unsigned int)((arg2 - 17)))) < (unsigned long)(0xfffffff0))) {
        return ret;
    }
    var2 = (unsigned long)((unsigned int)(arg2));
    produced = 0;
    var5 = (unsigned long)(arg0);
    while (((unsigned long)((unsigned int)(arg2)) != produced)) {
        ret = ((unsigned long)((unsigned int)(produced)) + 1);
        *(signed char *)(((long)arg1 + produced)) = (((((unsigned long)(127) < (unsigned long)((unsigned long)((unsigned int)(var5)))) << 7) & 255) | ((unsigned long)((unsigned int)(var5)) & 127));
        if (((unsigned long)(var2) <= (unsigned long)(produced))) {
            return ret;
        }
        zf_12 = ((unsigned long)((unsigned int)(var5)) == 127);
        cf_12 = ((unsigned long)((unsigned long)((unsigned int)(var5))) < (unsigned long)(127));
        var5 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var5)) >> 7)));
        produced = ret;
        if (((cf_12 | zf_12) != 0)) {
            return ret;
        }
    }
    return 0xfffffffe;
}
zigzag_decode pass 4 lines
// glaurung: zigzag_decode @ 0x1110
int32_t zigzag_decode(uint32_t arg0) {
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) >> 1))) ^ (-(unsigned long)((unsigned int)((arg0 & 1))))));
}
zigzag_encode pass 4 lines
// glaurung: zigzag_encode @ 0x1100
uint32_t zigzag_encode(int32_t arg0) {
    return (unsigned int)(((unsigned long)((unsigned int)((arg0 + arg0))) ^ (unsigned long)((unsigned int)(((int)(arg0) >> 31)))));
}

gcc -O0

4/4
varint_decode pass 47 lines
// glaurung: varint_decode @ 0x11ad
int32_t varint_decode(const uint8_t * arg0, int32_t arg1, uint32_t * arg2) {
    unsigned long accumulator;
    int shift;
    int index;
    unsigned char chunk;
    accumulator = 0;
    shift = 0;
    if ((arg0 != 0)) {
        if ((arg2 != 0)) {
            if ((0 <= (long)(arg1))) {
                if ((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16))) {
                    goto L_11f3;
                }
            }
        }
    }
    // x86-64 epilogue: restore rbp
    return 0xffffffff;
    L_11f3: ;
    index = 0;
    goto L_126b;
    L_11fc: ;
    chunk = arg0[index];
    if (((((unsigned long)((unsigned int)(shift)) == 28) | ((long)(shift) < 28)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xfffffffe;
    }
    accumulator = (accumulator | ((unsigned long)((unsigned int)(((unsigned int)(chunk) & 127))) << ((unsigned long)((unsigned int)(shift)) & 63)));
    shift = (shift + 7);
    if ((0 <= (long)((signed char)((chunk & 255))))) {
        if (((unsigned long)(0xffffffff) < (unsigned long)(accumulator))) {
            // x86-64 epilogue: restore rbp
            return 0xfffffffd;
        }
        *(int *)((long)arg2) = accumulator;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(((unsigned long)((unsigned int)(index)) + 1));
    }
    index = (index + 1);
    L_126b: ;
    if ((index < arg1)) {
        goto L_11fc;
    }
    // x86-64 epilogue: restore rbp
    return 0xfffffffc;
}
varint_encode pass 32 lines
// glaurung: varint_encode @ 0x1132
int32_t varint_encode(uint32_t arg0, uint8_t * arg1, int32_t arg2) {
    int produced;
    unsigned char chunk;
    produced = 0;
    if ((arg1 != 0)) {
        if (((((unsigned long)((unsigned int)(arg2)) == 0) | ((long)(arg2) < 0)) == 0)) {
            if ((((unsigned long)((unsigned int)(arg2)) == 16) | ((long)(arg2) < 16))) {
                goto L_1165;
            }
        }
    }
    // x86-64 epilogue: restore rbp
    return 0xffffffff;
    L_1165: ;
    chunk = (arg0 & 127);
    arg0 = ((unsigned int)(arg0) >> 7);
    if ((arg0 != 0)) {
        chunk = (chunk | -128);
    }
    if ((arg2 <= produced)) {
        // x86-64 epilogue: restore rbp
        return 0xfffffffe;
    }
    arg1[produced] = chunk;
    produced = (produced + 1);
    if ((arg0 != 0)) {
        goto L_1165;
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(produced);
}
zigzag_decode pass 6 lines
// glaurung: zigzag_decode @ 0x1114
int32_t zigzag_decode(uint32_t arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((-(unsigned long)((unsigned int)(((unsigned long)(arg0) & 1)))) ^ (unsigned long)((unsigned int)(((unsigned long)(arg0) >> 1)))));
}
zigzag_encode pass 6 lines
// glaurung: zigzag_encode @ 0x10f9
uint32_t zigzag_encode(int32_t arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(((int)(arg0) >> 31))) ^ (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) + (unsigned long)((unsigned int)(arg0)))))));
}

gcc -O2

4/4
varint_decode pass 54 lines
// glaurung: varint_decode @ 0x1180
int32_t varint_decode(const uint8_t * arg0, int32_t arg1, uint32_t * arg2) {
    unsigned char chunk;
    int shift;
    unsigned long accumulator;
    int index;
    long var0;
    long var10;
    long var11;
    long var13;
    long var15;
    long var8;
    var0 = (long)arg0;
    if ((arg0 == 0)) {
        return 0xffffffff;
    }
    if ((arg2 == 0)) {
        return 0xffffffff;
    }
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        return 0xffffffff;
    }
    if (((unsigned long)((unsigned int)(arg1)) == 0)) {
        return 0xfffffffc;
    }
    var8 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)((arg1 * 8))) - arg1)));
    var10 = 0;
    var11 = 0;
    chunk = (unsigned int)((unsigned char)(*(char *)(((long)arg0))));
    var13 = 0;
    while (1) {
        var15 = (unsigned long)((unsigned int)(var10));
        shift = (unsigned long)((unsigned int)((var13 + 7)));
        accumulator = (var11 | ((unsigned long)((unsigned int)(((unsigned int)(chunk) & 127))) << (var13 & 63)));
        if ((0 <= (long)((signed char)((chunk & 255))))) {
            break;
        }
        if (((unsigned int)(shift) == (unsigned int)(var8))) {
            return 0xfffffffc;
        }
        chunk = (unsigned int)((unsigned char)(*(char *)((var0 + var10 + 0x1))));
        var10 = (var10 + 1);
        var11 = accumulator;
        var13 = (unsigned long)((unsigned int)(shift));
        if (((unsigned long)((unsigned int)(shift)) == 35)) {
            return 0xfffffffe;
        }
    }
    if ((((unsigned long)(accumulator) >> 32) != 0)) {
        return 0xfffffffd;
    }
    *(int *)(((long)arg2)) = accumulator;
    return (unsigned int)((var15 + 1));
}
varint_encode pass 37 lines
// glaurung: varint_encode @ 0x1120
int32_t varint_encode(uint32_t arg0, uint8_t * arg1, int32_t arg2) {
    unsigned char chunk;
    int produced;
    long var2;
    long var3;
    long var5;
    long var7;
    int var9;
    if (((unsigned long)(15) < (unsigned long)((unsigned long)((unsigned int)((arg2 - 1)))))) {
        return 0xffffffff;
    }
    if ((arg1 == 0)) {
        return 0xffffffff;
    }
    var2 = 0;
    var3 = (unsigned long)(arg0);
    while (1) {
        var5 = (unsigned long)((unsigned int)(var2));
        var7 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var3)) & 127)));
        var9 = ((unsigned long)((unsigned int)(var3)) >> 7);
        var3 = (unsigned long)((unsigned int)(var9));
        if (((unsigned long)((unsigned int)(var9)) == 0)) {
            break;
        }
        if ((((unsigned int)(arg2) == (unsigned int)(var2)) | ((long)(arg2) < (long)((int)(var2))))) {
            return 0xfffffffe;
        }
        *(signed char *)(((long)arg1 + var2)) = (var7 | -128);
        var2 = (var2 + 1);
    }
    if (((long)((int)(var2)) < (long)(arg2))) {
        arg1[(long)((int)(var2))] = var7;
        return (unsigned int)((var5 + 1));
    }
    return 0xfffffffe;
}
zigzag_decode pass 4 lines
// glaurung: zigzag_decode @ 0x1110
int32_t zigzag_decode(uint32_t arg0) {
    return (unsigned int)(((-(unsigned long)((unsigned int)(((unsigned long)(arg0) & 1)))) ^ (unsigned long)((unsigned int)(((unsigned long)(arg0) >> 1)))));
}
zigzag_encode pass 4 lines
// glaurung: zigzag_encode @ 0x1100
uint32_t zigzag_encode(int32_t arg0) {
    return (unsigned int)(((unsigned long)((unsigned int)((arg0 + arg0))) ^ (unsigned long)((unsigned int)(((int)(arg0) >> 31)))));
}

← 213 fixtures