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.

tests/decompiler_fixtures/src/110_pointer_arithmetic.c source
#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/3
byte_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/3
byte_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/3
byte_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/3
byte_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));
}

← 213 fixtures