Fixture 78

ring buffer

C · 3 functions · 4 lanes · 12 of 12 function-lanes behave identically

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

A power-of-two circular buffer with separate head and tail indices. The wrap is a mask rather than a modulo, and fullness is derived from the unsigned difference of two monotonically increasing counters.

tests/decompiler_fixtures/src/78_ring_buffer.c source
#include <stdint.h>

/* A power-of-two circular buffer with separate head and tail indices.  The
 * wrap is a mask rather than a modulo, and fullness is derived from the
 * unsigned difference of two monotonically increasing counters. */

#define RING_CAPACITY 8
#define RING_MASK (RING_CAPACITY - 1)

__attribute__((noinline)) int32_t
ring_push(int32_t *storage, uint32_t *head, uint32_t *tail, int32_t value) {
    if (storage == 0 || head == 0 || tail == 0) {
        return -1;
    }
    if ((*head - *tail) >= (uint32_t)RING_CAPACITY) {
        return 0;
    }
    storage[*head & (uint32_t)RING_MASK] = value;
    *head = *head + 1u;
    return 1;
}

__attribute__((noinline)) int32_t
ring_pop(int32_t *storage, uint32_t *head, uint32_t *tail, int32_t *value) {
    if (storage == 0 || head == 0 || tail == 0 || value == 0) {
        return -1;
    }
    if (*head == *tail) {
        return 0;
    }
    *value = storage[*tail & (uint32_t)RING_MASK];
    *tail = *tail + 1u;
    return 1;
}

__attribute__((noinline)) int32_t
ring_occupancy(uint32_t head, uint32_t tail) {
    uint32_t used = head - tail;
    if (used > (uint32_t)RING_CAPACITY) {
        return -1;
    }
    return (int32_t)used;
}

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

3/3
ring_occupancy pass 11 lines
// glaurung: ring_occupancy @ 0x1240
int32_t ring_occupancy(uint32_t arg0, uint32_t arg1) {
    unsigned int used;
    // x86-64 prologue: save rbp
    used = (arg0 - arg1);
    if (((unsigned long)(used) <= (unsigned long)(8))) {
        return used;
    } else {
        return (unsigned int)(-1);
    }
}
ring_pop pass 32 lines
// glaurung: ring_pop @ 0x11a0
int32_t ring_pop(int32_t * arg0, uint32_t * arg1, uint32_t * arg2, int32_t * arg3) {
    int local_4;
    // x86-64 prologue: save rbp
    if ((arg0 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if ((arg1 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if ((arg2 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if ((arg3 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((unsigned int)(*(int *)((long)arg1)) != (unsigned int)(*(int *)((long)arg2)))) {
        *(int *)((long)arg3) = arg0[(unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)((long)arg2))) & 7)))];
        *(int *)((long)arg2) = ((unsigned long)((unsigned int)(*(int *)((long)arg2))) + 1);
        return 1;
    } else {
        return 0;
    }
}
ring_push pass 27 lines
// glaurung: ring_push @ 0x1100
int32_t ring_push(int32_t * arg0, uint32_t * arg1, uint32_t * arg2, int32_t arg3) {
    int local_4;
    // x86-64 prologue: save rbp
    if ((arg0 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if ((arg1 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if ((arg2 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((unsigned long)((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)((long)arg1))) - *(int *)((long)arg2))))) < (unsigned long)(8))) {
        arg0[(unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)((long)arg1))) & 7)))] = arg3;
        *(int *)((long)arg1) = ((unsigned long)((unsigned int)(*(int *)((long)arg1))) + 1);
        return 1;
    } else {
        return 0;
    }
}

clang -O2

3/3
ring_occupancy pass 6 lines
// glaurung: ring_occupancy @ 0x1180
int32_t ring_occupancy(uint32_t arg0, uint32_t arg1) {
    unsigned int used;
    used = (unsigned long)((unsigned int)((arg0 - arg1)));
    return (((unsigned long)((unsigned long)(used)) < (unsigned long)(9)) ? used : 0xffffffff);
}
ring_pop pass 25 lines
// glaurung: ring_pop @ 0x1140
int32_t ring_pop(int32_t * arg0, uint32_t * arg1, uint32_t * arg2, int32_t * arg3) {
    long ret;
    long var0;
    ret = 0xffffffff;
    if ((arg0 != 0)) {
        if ((arg1 == 0)) {
            return ret;
        }
        if ((arg2 == 0)) {
            return ret;
        }
        if ((arg3 == 0)) {
            return ret;
        }
        var0 = (unsigned long)((unsigned int)(*(int *)(((long)arg2))));
        ret = 0;
        if (((unsigned int)(*(int *)(((long)arg1))) != (unsigned int)(var0))) {
            *(int *)(((long)arg3)) = arg0[(unsigned long)((unsigned int)((var0 & 7)))];
            *(int *)(((long)arg2)) = (*(int *)(((long)arg2)) + 1);
            ret = 1;
        }
    }
    return ret;
}
ring_push pass 22 lines
// glaurung: ring_push @ 0x1100
int32_t ring_push(int32_t * arg0, uint32_t * arg1, uint32_t * arg2, int32_t arg3) {
    long ret;
    long var0;
    ret = 0xffffffff;
    if ((arg0 != 0)) {
        if ((arg1 == 0)) {
            return ret;
        }
        if ((arg2 == 0)) {
            return ret;
        }
        var0 = (unsigned long)((unsigned int)(*(int *)(((long)arg1))));
        ret = 0;
        if (((unsigned long)((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var0)) - (unsigned long)((unsigned int)(*(int *)(((long)arg2)))))))) <= (unsigned long)(7))) {
            arg0[(unsigned long)((unsigned int)((var0 & 7)))] = arg3;
            *(int *)(((long)arg1)) = (*(int *)(((long)arg1)) + 1);
            ret = 1;
        }
    }
    return ret;
}

gcc -O0

3/3
ring_occupancy pass 11 lines
// glaurung: ring_occupancy @ 0x1207
int32_t ring_occupancy(uint32_t arg0, uint32_t arg1) {
    unsigned int used;
    // x86-64 prologue: save rbp
    used = (arg0 - arg1);
    if (((unsigned long)(used) <= (unsigned long)(8))) {
        return used;
    } else {
        return 0xffffffff;
    }
}
ring_pop pass 27 lines
// glaurung: ring_pop @ 0x117d
int32_t ring_pop(int32_t * arg0, uint32_t * arg1, uint32_t * arg2, int32_t * arg3) {
    // x86-64 prologue: save rbp
    if ((arg0 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if ((arg1 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if ((arg2 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if ((arg3 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((unsigned int)(*(int *)((long)arg1)) != (unsigned int)(*(int *)((long)arg2)))) {
        *(int *)((long)arg3) = arg0[(unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)((long)arg2))) & 7)))];
        *(int *)((long)arg2) = ((unsigned long)((unsigned int)(*(int *)((long)arg2))) + 1);
        return 1;
    } else {
        return 0;
    }
}
ring_push pass 23 lines
// glaurung: ring_push @ 0x10f9
int32_t ring_push(int32_t * arg0, uint32_t * arg1, uint32_t * arg2, int32_t arg3) {
    // x86-64 prologue: save rbp
    if ((arg0 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if ((arg1 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if ((arg2 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((unsigned long)((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)((long)arg1))) - (unsigned long)((unsigned int)(*(int *)((long)arg2))))))) <= (unsigned long)(7))) {
        arg0[(unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)((long)arg1))) & 7)))] = arg3;
        *(int *)((long)arg1) = ((unsigned long)((unsigned int)(*(int *)((long)arg1))) + 1);
        return 1;
    } else {
        return 0;
    }
}

gcc -O2

3/3
ring_occupancy pass 6 lines
// glaurung: ring_occupancy @ 0x11a0
int32_t ring_occupancy(uint32_t arg0, uint32_t arg1) {
    unsigned int used;
    used = (unsigned long)((unsigned int)((arg0 - arg1)));
    return (((unsigned long)((unsigned long)(used)) <= (unsigned long)(8)) ? used : 0xffffffff);
}
ring_pop pass 26 lines
// glaurung: ring_pop @ 0x1160
int32_t ring_pop(int32_t * arg0, uint32_t * arg1, uint32_t * arg2, int32_t * arg3) {
    long ret;
    long var0;
    if ((arg0 == 0)) {
        return 0xffffffff;
    }
    if ((arg1 == 0)) {
        return 0xffffffff;
    }
    if ((arg2 == 0)) {
        return 0xffffffff;
    }
    if ((arg3 == 0)) {
        return 0xffffffff;
    }
    var0 = (unsigned long)((unsigned int)(*(int *)(((long)arg2))));
    ret = 0;
    if (((unsigned int)(*(int *)(((long)arg1))) != (unsigned int)(var0))) {
        *(int *)(((long)arg3)) = arg0[(unsigned long)((unsigned int)((var0 & 7)))];
        ret = 1;
        *(int *)(((long)arg2)) = (*(int *)(((long)arg2)) + 1);
        return 1;
    }
    return ret;
}
ring_push pass 21 lines
// glaurung: ring_push @ 0x1100
int32_t ring_push(int32_t * arg0, uint32_t * arg1, uint32_t * arg2, int32_t arg3) {
    long var0;
    long var11;
    long var9;
    var0 = (long)arg0;
    if (((arg1 == 0) || (arg2 == 0))) {
        return 0xffffffff;
    }
    if ((arg0 == 0)) {
        return 0xffffffff;
    }
    var9 = (unsigned long)((unsigned int)(*(int *)(((long)arg1))));
    var11 = 0;
    if (((unsigned long)((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var9)) - *(int *)(((long)arg2)))))) <= (unsigned long)(7))) {
        var11 = 1;
        *(int *)((var0 + ((unsigned long)((unsigned int)((var9 & 7))) * 4))) = arg3;
        *(int *)(((long)arg1)) = (*(int *)(((long)arg1)) + 1);
    }
    return (unsigned int)(var11);
}

← 213 fixtures