Fixture 110
pointer arithmetic
C · 3 functions · 4 lanes · 12 of 12 function-lanes behave identically
All 4 lanes recompile and return the same results as the original.
Pointer differences are in elements, not bytes; a one-past-the-end pointer is valid to form and compare but not to dereference.
#include <stdint.h>
#include <stddef.h>
/* Pointer differences are in elements, not bytes; a one-past-the-end pointer is
* valid to form and compare but not to dereference. */
__attribute__((noinline)) int32_t
element_distance(const int32_t *values, int32_t count) {
const int32_t *first;
const int32_t *last;
if (values == 0 || count < 1 || count > 16) {
return -1;
}
first = values;
last = values + count; /* one past the end: legal to form */
return (int32_t)(ptrdiff_t)(last - first);
}
__attribute__((noinline)) int32_t
byte_versus_element_step(const int32_t *values, int32_t count) {
const uint8_t *bytes;
if (values == 0 || count < 1 || count > 16) {
return -1;
}
bytes = (const uint8_t *)values;
/* values + 1 advances four bytes; bytes + 1 advances one. */
return (int32_t)(bytes[4] == (uint8_t)(values[1] & 0xFF));
}
__attribute__((noinline)) int32_t
walk_until_sentinel(const int32_t *values, int32_t count, int32_t sentinel) {
const int32_t *cursor;
const int32_t *end;
if (values == 0 || count < 0 || count > 16) {
return -1;
}
end = values + count;
for (cursor = values; cursor != end; ++cursor) {
if (*cursor == sentinel) {
return (int32_t)(cursor - values);
}
}
return count;
} 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/3byte_versus_element_step pass 25 lines
// glaurung: byte_versus_element_step @ 0x1170
int32_t byte_versus_element_step(const int32_t * arg0, int32_t arg1) {
char * bytes;
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 (((long)(arg1) < 1)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
bytes = (char *)arg0;
local_4 = ((unsigned int)((unsigned char)(*(char *)((bytes + 0x4)))) == (unsigned int)((unsigned char)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)(((long)arg0 + 0x4)))) & 255))) & 255))));
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} element_distance pass 27 lines
// glaurung: element_distance @ 0x1100
int32_t element_distance(const int32_t * arg0, int32_t arg1) {
int * first;
int * last;
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 (((long)(arg1) < 1)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
first = (int *)arg0;
last = (int *)(((long)arg0 + ((long)(arg1) << 2)));
local_4 = ((long)(((long)last - (long)first)) >> 2);
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} walk_until_sentinel pass 36 lines
// glaurung: walk_until_sentinel @ 0x11e0
int32_t walk_until_sentinel(const int32_t * arg0, int32_t arg1, int32_t arg2) {
int * end;
int * cursor;
int local_4;
if ((arg0 != 0)) {
if ((0 <= (long)(arg1))) {
if ((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16))) {
goto L_1219;
}
}
}
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
L_1219: ;
end = (int *)(((long)arg0 + ((long)(arg1) << 2)));
cursor = (int *)arg0;
L_1234: ;
if ((cursor == end)) {
goto L_127e;
}
if (((unsigned int)(*(int *)(cursor)) == (unsigned int)(arg2))) {
local_4 = ((long)(((long)cursor - (long)arg0)) >> 2);
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
goto L_126d;
L_126d: ;
cursor = (int *)((cursor + 1));
goto L_1234;
L_127e: ;
local_4 = arg1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} clang -O2
3/3byte_versus_element_step pass 11 lines
// glaurung: byte_versus_element_step @ 0x1120
int32_t byte_versus_element_step(const int32_t * arg0, int32_t arg1) {
long ret;
ret = 0xffffffff;
if ((arg0 != 0)) {
if (((unsigned long)(0xfffffff0) <= (unsigned long)((unsigned long)((unsigned int)((arg1 - 17)))))) {
ret = 1;
}
}
return ret;
} element_distance pass 4 lines
// glaurung: element_distance @ 0x1100
int32_t element_distance(const int32_t * arg0, int32_t arg1) {
return (unsigned int)(((unsigned int)((0 - ((unsigned long)((long)arg0) < (unsigned long)(1)))) | (((unsigned long)(0xfffffff0) <= (unsigned long)((unsigned long)((unsigned int)((arg1 - 17))))) ? arg1 : 0xffffffff)));
} walk_until_sentinel pass 26 lines
// glaurung: walk_until_sentinel @ 0x1140
int32_t walk_until_sentinel(const int32_t * arg0, int32_t arg1, int32_t arg2) {
int * cursor;
long ret;
long var1;
ret = 0xffffffff;
if ((arg0 == 0)) {
return ret;
}
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return ret;
}
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
return 0;
}
var1 = ((unsigned long)((unsigned int)(arg1)) << 2);
ret = 0;
do {
if (((unsigned int)(*(int *)(((long)arg0 + ret * 4))) == (unsigned int)(arg2))) {
return ret;
}
ret = (ret + 1);
var1 = (var1 - 4);
} while ((var1 != 0));
return (unsigned int)(arg1);
} gcc -O0
3/3byte_versus_element_step pass 20 lines
// glaurung: byte_versus_element_step @ 0x1150
int32_t byte_versus_element_step(const int32_t * arg0, int32_t arg1) {
char * bytes;
// x86-64 prologue: save rbp
if ((arg0 == 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)) == 16) | ((long)(arg1) < 16)) == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
bytes = (char *)arg0;
// x86-64 epilogue: restore rbp
return ((unsigned char)(((unsigned int)((unsigned char)(bytes[4])) & 255)) == (unsigned char)(((unsigned long)((unsigned int)(*(int *)((arg0 + 1)))) & 255)));
} element_distance pass 22 lines
// glaurung: element_distance @ 0x10f9
int32_t element_distance(const int32_t * arg0, int32_t arg1) {
int * first;
int * last;
// x86-64 prologue: save rbp
if ((arg0 == 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)) == 16) | ((long)(arg1) < 16)) == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
first = (int *)arg0;
last = (int *)(((long)arg0 + ((long)(arg1) * 4)));
// x86-64 epilogue: restore rbp
return ((long)(((long)last - (long)first)) >> 2);
} walk_until_sentinel pass 30 lines
// glaurung: walk_until_sentinel @ 0x11a0
int32_t walk_until_sentinel(const int32_t * arg0, int32_t arg1, int32_t arg2) {
int * end;
int * cursor;
if ((arg0 != 0)) {
if ((0 <= (long)(arg1))) {
if ((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16))) {
goto L_11cc;
}
}
}
// x86-64 epilogue: restore rbp
return 0xffffffff;
L_11cc: ;
end = (int *)(((long)arg0 + ((long)(arg1) * 4)));
cursor = (int *)arg0;
goto L_120c;
L_11ee: ;
if (((unsigned int)(arg2) == (unsigned int)(*(int *)(cursor)))) {
// x86-64 epilogue: restore rbp
return ((long)(((long)cursor - (long)arg0)) >> 2);
}
cursor = (int *)((cursor + 1));
L_120c: ;
if ((cursor != end)) {
goto L_11ee;
}
// x86-64 epilogue: restore rbp
return (unsigned int)(arg1);
} gcc -O2
3/3byte_versus_element_step pass 7 lines
// glaurung: byte_versus_element_step @ 0x1120
int32_t byte_versus_element_step(const int32_t * arg0, int32_t arg1) {
if ((((unsigned long)(15) < (unsigned long)((unsigned long)((unsigned int)((arg1 - 1))))) || (arg0 == 0))) {
return 0xffffffff;
}
return 1;
} element_distance pass 8 lines
// glaurung: element_distance @ 0x1100
int32_t element_distance(const int32_t * arg0, int32_t arg1) {
int * first;
if ((((unsigned long)(15) < (unsigned long)((unsigned long)((unsigned int)((arg1 - 1))))) || (arg0 == 0))) {
return 0xffffffff;
}
return (unsigned int)(arg1);
} walk_until_sentinel pass 27 lines
// glaurung: walk_until_sentinel @ 0x1150
int32_t walk_until_sentinel(const int32_t * arg0, int32_t arg1, int32_t arg2) {
int * end;
int * cursor;
long ret;
long var3;
ret = (unsigned long)((unsigned int)(arg1));
if ((arg0 == 0)) {
return 0xffffffff;
}
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return 0xffffffff;
}
end = (int *)(((long)arg0 + ((long)(arg1) * 4)));
if (((long)arg0 == end)) {
return ret;
}
var3 = (long)arg0;
while (((unsigned int)(*(int *)((var3))) != (unsigned int)(arg2))) {
cursor = (int *)((var3 + 4));
var3 = (long)cursor;
if ((end == cursor)) {
return ret;
}
}
return (unsigned int)(((long)((var3 - (long)arg0)) >> 2));
}