Fixture 109

subscript commutativity

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

One lane has a function that returns a different result after decompilation: clang-O0 (2/3).

a[i] is defined as *(a + i), so i[a] is the same object. The IOCCC leans on this; the point here is that the recovered code should express the addressing plainly regardless of which spelling produced it.

tests/decompiler_fixtures/src/109_subscript_commutativity.c source
#include <stdint.h>

/* a[i] is defined as *(a + i), so i[a] is the same object. The IOCCC leans on
 * this; the point here is that the recovered code should express the addressing
 * plainly regardless of which spelling produced it. */

__attribute__((noinline)) int32_t
reversed_subscript(const int32_t *values, int32_t index, int32_t bound) {
    if (values == 0 || index < 0 || bound < 0 || bound > 16 || index >= bound) {
        return -1;
    }
    return index[values]; /* identical to values[index] */
}

__attribute__((noinline)) int32_t
mixed_subscript_sum(const int32_t *values, int32_t count) {
    int32_t total = 0;
    int32_t index;
    if (values == 0 || count < 0 || count > 16) {
        return -1;
    }
    for (index = 0; index < count; ++index) {
        total += (index & 1) ? index[values] : values[index];
    }
    return total;
}

__attribute__((noinline)) int32_t
negative_offset_from_interior(const int32_t *values, int32_t count) {
    const int32_t *interior;
    if (values == 0 || count < 2 || count > 16) {
        return -1;
    }
    interior = values + count - 1;
    /* A negative subscript on an interior pointer is ordinary arithmetic. */
    return interior[-1] + interior[0];
}

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

2/3
mixed_subscript_sum pass 31 lines
// glaurung: mixed_subscript_sum @ 0x1170
int32_t mixed_subscript_sum(const int32_t * arg0, int32_t arg1) {
    int total;
    int index;
    int local_20;
    int local_4;
    // x86-64 prologue: save rbp
    total = 0;
    if ((arg0 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((long)(arg1) < 0)) {
        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);
    }
    for (index = 0; (index < arg1); index++) {
        local_20 = (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(index)) & 1))) == 0) ? arg0[(long)(index)] : arg0[(long)(index)]);
        total = ((unsigned int)(local_20) + total);
    }
    local_4 = total;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
negative_offset_from_interior fail 25 lines
// glaurung: negative_offset_from_interior @ 0x1220
int32_t negative_offset_from_interior(const int32_t * arg0, int32_t arg1) {
    int * interior;
    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) < 2)) {
        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);
    }
    interior = (int *)((((long)arg0 + ((long)(arg1) << 2)) - 4));
    local_4 = ((unsigned int)(*(int *)((interior - 0x4))) + *(int *)(interior));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
reversed_subscript pass 33 lines
// glaurung: reversed_subscript @ 0x1100
int32_t reversed_subscript(const int32_t * arg0, int32_t arg1, int32_t arg2) {
    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) < 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((long)(arg2) < 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((((unsigned long)((unsigned int)(arg2)) == 16) | ((long)(arg2) < 16)) == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if ((arg2 <= arg1)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    local_4 = arg0[(long)(arg1)];
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}

clang -O2

3/3
mixed_subscript_sum pass 68 lines
// glaurung: mixed_subscript_sum @ 0x1120
int32_t mixed_subscript_sum(const int32_t * arg0, int32_t arg1) {
    int total;
    int index;
    long ret;
    long var2;
    long var41;
    long var5;
    int var6;
    int var7;
    int var8;
    int var9;
    ret = 0xffffffff;
    if ((arg0 == 0)) {
        return ret;
    }
    ret = 0xffffffff;
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        return ret;
    }
    if (((unsigned long)((unsigned int)(arg1)) == 0)) {
        return 0;
    }
    var2 = (unsigned long)((unsigned int)(arg1));
    if (((unsigned long)(4) <= (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        var5 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var2)) & -4)));
        var6 = *(int *)(((long)arg0));
        var7 = *(int *)(((long)arg0 + 0x4));
        var8 = *(int *)(((long)arg0 + 0x8));
        var9 = *(int *)(((long)arg0 + 0xc));
        if ((var5 != 4)) {
            var6 = (var6 + *(int *)(((long)arg0 + 0x10)));
            var7 = (var7 + *(int *)(((long)arg0 + 0x14)));
            var8 = (var8 + *(int *)(((long)arg0 + 0x18)));
            var9 = (var9 + *(int *)(((long)arg0 + 0x1c)));
            if (((unsigned long)((unsigned int)(var5)) != 8)) {
                var6 = (var6 + *(int *)(((long)arg0 + 0x20)));
                var7 = (var7 + *(int *)(((long)arg0 + 0x24)));
                var8 = (var8 + *(int *)(((long)arg0 + 0x28)));
                var9 = (var9 + *(int *)(((long)arg0 + 0x2c)));
                if (((unsigned long)((unsigned int)(var5)) != 12)) {
                    var6 = (var6 + *(int *)(((long)arg0 + 0x30)));
                    var7 = (var7 + *(int *)(((long)arg0 + 0x34)));
                    var8 = (var8 + *(int *)(((long)arg0 + 0x38)));
                    var9 = (var9 + *(int *)(((long)arg0 + 0x3c)));
                }
            }
        }
        var41 = (unsigned long)((unsigned int)(((var9 + var7) + (var8 + var6))));
        ret = var41;
        if ((var5 == var2)) {
            return ret;
        }
        L_11a0: ;
        do {
            total = (var41 + *(int *)(((long)arg0 + var5 * 4)));
            index = (var5 + 1);
            var41 = (unsigned long)((unsigned int)(total));
            var5 = (unsigned long)((unsigned int)(index));
            ret = (unsigned long)((unsigned int)(total));
        } while ((var2 != index));
    } else {
        var41 = 0;
        var5 = 0;
        goto L_11a0;
    }
    return ret;
}
negative_offset_from_interior pass 11 lines
// glaurung: negative_offset_from_interior @ 0x11b0
int32_t negative_offset_from_interior(const int32_t * arg0, int32_t arg1) {
    long ret;
    ret = 0xffffffff;
    if ((arg0 != 0)) {
        if (((unsigned long)(0xfffffff1) <= (unsigned long)((unsigned long)((unsigned int)((arg1 - 17)))))) {
            ret = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)((((long)arg0 + ((unsigned long)((unsigned int)(arg1)) * 4)) - 4)))) + *(int *)((((long)arg0 + ((unsigned long)((unsigned int)(arg1)) * 4)) - 8)))));
        }
    }
    return ret;
}
reversed_subscript pass 17 lines
// glaurung: reversed_subscript @ 0x1100
int32_t reversed_subscript(const int32_t * arg0, int32_t arg1, int32_t arg2) {
    long ret;
    ret = 0xffffffff;
    if ((arg1 < arg2)) {
        if (((((unsigned long)((unsigned int)(arg2)) == 16) | ((long)(arg2) < 16)) == 0)) {
            return ret;
        }
        if ((arg0 == 0)) {
            return ret;
        }
        if ((0 <= (long)((int)((arg2 | arg1))))) {
            ret = (unsigned long)((unsigned int)(arg0[(long)(arg1)]));
        }
    }
    return ret;
}

gcc -O0

3/3
mixed_subscript_sum pass 24 lines
// glaurung: mixed_subscript_sum @ 0x114b
int32_t mixed_subscript_sum(const int32_t * arg0, int32_t arg1) {
    int total;
    int index;
    // x86-64 prologue: save rbp
    total = 0;
    if ((arg0 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((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;
    }
    for (index = 0; (index < arg1); index++) {
        total = (total + (unsigned int)(arg0[(long)(index)]));
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(total);
}
negative_offset_from_interior pass 20 lines
// glaurung: negative_offset_from_interior @ 0x11ae
int32_t negative_offset_from_interior(const int32_t * arg0, int32_t arg1) {
    int * interior;
    // x86-64 prologue: save rbp
    if ((arg0 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if ((((unsigned long)((unsigned int)(arg1)) == 1) | ((long)(arg1) < 1))) {
        // 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;
    }
    interior = (int *)(((long)arg0 + (((long)(arg1) << 2) - 4)));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(*(int *)(interior))) + (unsigned long)((unsigned int)(*(int *)((interior - 1))))));
}
reversed_subscript pass 26 lines
// glaurung: reversed_subscript @ 0x10f9
int32_t reversed_subscript(const int32_t * arg0, int32_t arg1, int32_t arg2) {
    // x86-64 prologue: save rbp
    if ((arg0 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((long)(arg1) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((long)(arg2) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((((unsigned long)((unsigned int)(arg2)) == 16) | ((long)(arg2) < 16)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if ((arg2 <= arg1)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(arg0[(long)(arg1)]);
}

gcc -O2

3/3
mixed_subscript_sum pass 25 lines
// glaurung: mixed_subscript_sum @ 0x1130
int32_t mixed_subscript_sum(const int32_t * arg0, int32_t arg1) {
    int index;
    int total;
    long ret;
    long var2;
    long var5;
    if ((arg0 == 0)) {
        return 0xffffffff;
    }
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        return 0xffffffff;
    }
    if (((unsigned long)((unsigned int)(arg1)) == 0)) {
        return 0;
    }
    var2 = (long)((((long)arg0 + ((unsigned long)((unsigned int)((arg1 - 1))) * 4)) + 4));
    ret = 0;
    var5 = (long)arg0;
    do {
        ret = (unsigned long)((unsigned int)((ret + *(int *)((var5)))));
        var5 = (var5 + 4);
    } while ((var5 != var2));
    return ret;
}
negative_offset_from_interior pass 7 lines
// glaurung: negative_offset_from_interior @ 0x1170
int32_t negative_offset_from_interior(const int32_t * arg0, int32_t arg1) {
    if ((((unsigned long)(14) < (unsigned long)((unsigned long)((unsigned int)((arg1 - 2))))) || (arg0 == 0))) {
        return 0xffffffff;
    }
    return (unsigned int)(((unsigned long)((unsigned int)(*(int *)((((long)arg0 + ((long)(arg1) * 4)) - 8)))) + *(int *)((((long)arg0 + ((long)(arg1) * 4)) - 4))));
}
reversed_subscript pass 13 lines
// glaurung: reversed_subscript @ 0x1100
int32_t reversed_subscript(const int32_t * arg0, int32_t arg1, int32_t arg2) {
    if ((arg0 == 0)) {
        return 0xffffffff;
    }
    if (((long)(arg1) < 0)) {
        return 0xffffffff;
    }
    if ((((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg2)))) || (arg2 <= arg1))) {
        return 0xffffffff;
    }
    return (unsigned int)(arg0[(long)(arg1)]);
}

← 213 fixtures