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.
#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/3ring_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/3ring_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/3ring_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/3ring_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);
}