Fixture 88

restrict pointers

C · 2 functions · 4 lanes · 4 of 8 function-lanes behave identically

4 of 4 lanes have a function that returns a different result after decompilation: clang-O0 (1/2), clang-O2 (1/2), gcc-O0 (1/2), gcc-O2 (1/2).

C99 restrict promises no aliasing, which licenses the compiler to keep values in registers across stores it would otherwise have to reload. The aliasing and non-aliasing variants below are deliberately identical apart from the qualifier, so the generated code diverges while the source does not.

tests/decompiler_fixtures/src/88_restrict_pointers.c source
#include <stdint.h>

/* C99 `restrict` promises no aliasing, which licenses the compiler to keep
 * values in registers across stores it would otherwise have to reload. The
 * aliasing and non-aliasing variants below are deliberately identical apart
 * from the qualifier, so the generated code diverges while the source does not. */

__attribute__((noinline)) int32_t
restrict_accumulate(int32_t *restrict destination,
                    const int32_t *restrict source, int32_t count) {
    int32_t index;
    if (destination == 0 || source == 0 || count < 0 || count > 16) {
        return -1;
    }
    for (index = 0; index < count; ++index) {
        destination[0] += source[index];
    }
    return destination[0];
}

__attribute__((noinline)) int32_t
aliasing_accumulate(int32_t *destination, const int32_t *source, int32_t count) {
    int32_t index;
    if (destination == 0 || source == 0 || count < 0 || count > 16) {
        return -1;
    }
    for (index = 0; index < count; ++index) {
        destination[0] += source[index];
    }
    return destination[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

1/2
aliasing_accumulate pass 32 lines
// glaurung: aliasing_accumulate @ 0x1190
int32_t aliasing_accumulate(int32_t * arg0, const int32_t * arg1, int32_t arg2) {
    int index;
    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 (((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);
    }
    for (index = 0; (index < arg2); index++) {
        *(int *)((long)arg0) = ((unsigned long)((unsigned int)(arg1[(long)(index)])) + *(int *)((long)arg0));
    }
    local_4 = *(int *)((long)arg0);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
restrict_accumulate structural 32 lines
// glaurung: restrict_accumulate @ 0x1100
int restrict_accumulate(int * arg0, int * arg1, int arg2) {
    int index;
    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 (((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);
    }
    for (index = 0; (index < arg2); index++) {
        *(int *)((long)arg0) = ((unsigned long)((unsigned int)(arg1[(long)(index)])) + *(int *)((long)arg0));
    }
    local_4 = *(int *)((long)arg0);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}

clang -O2

1/2
aliasing_accumulate pass 67 lines
// glaurung: aliasing_accumulate @ 0x1190
int32_t aliasing_accumulate(int32_t * arg0, const int32_t * arg1, int32_t arg2) {
    int index;
    long ret;
    long var0;
    long var1;
    int var11;
    int var13;
    int var15;
    long var16;
    long var17;
    long var20;
    long var22;
    int var23;
    long var5;
    int var9;
    ret = 0xffffffff;
    if (((unsigned long)((unsigned long)((unsigned int)(arg2))) <= (unsigned long)(16))) {
        if ((arg0 == 0)) {
            return ret;
        }
        if ((arg1 == 0)) {
            return ret;
        }
        if (((unsigned long)((unsigned int)(arg2)) == 0)) {
            return (unsigned int)(*(int *)(((long)arg0)));
        }
        var0 = (unsigned long)((unsigned int)(arg2));
        var1 = (unsigned long)((unsigned int)(*(int *)(((long)arg0))));
        var5 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) & 3)));
        if (((unsigned long)(3) <= (unsigned long)(((unsigned long)((unsigned int)(arg2)) - 1)))) {
            var0 = (unsigned long)((unsigned int)((var0 & -4)));
            index = 0;
            do {
                var9 = (var1 + *(int *)(((long)arg1 + index * 4)));
                *(int *)(((long)arg0)) = var9;
                var11 = ((unsigned int)(var9) + *(int *)(((long)arg1 + index * 4 + 0x4)));
                *(int *)(((long)arg0)) = var11;
                var13 = ((unsigned int)(var11) + *(int *)(((long)arg1 + index * 4 + 0x8)));
                *(int *)(((long)arg0)) = var13;
                var15 = ((unsigned int)(var13) + *(int *)(((long)arg1 + index * 4 + 0xc)));
                var1 = (unsigned long)((unsigned int)(var15));
                *(int *)(((long)arg0)) = var15;
                index = (index + 4);
                var16 = (unsigned long)((unsigned int)(var15));
                var17 = (unsigned long)((unsigned int)(index));
            } while ((var0 != index));
        } else {
            var16 = var1;
            var17 = 0;
        }
        ret = var16;
        if ((var5 == 0)) {
            return ret;
        }
        var20 = (long)(((long)arg1 + (var17 * 4)));
        var22 = 0;
        do {
            var23 = (var16 + *(int *)((var20 + var22 * 4)));
            var16 = (unsigned long)((unsigned int)(var23));
            *(int *)(((long)arg0)) = var23;
            var22 = (var22 + 1);
            ret = (unsigned long)((unsigned int)(var23));
        } while ((var5 != var22));
    }
    return ret;
}
restrict_accumulate structural 74 lines
// glaurung: restrict_accumulate @ 0x1100
int restrict_accumulate(int * arg0, int * arg1, int arg2) {
    int index;
    long ret;
    long var0;
    int var15;
    int var16;
    int var17;
    int var18;
    long var3;
    long var50;
    int var51;
    long var6;
    ret = 0xffffffff;
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg2))))) {
        return ret;
    }
    if ((arg0 == 0)) {
        return ret;
    }
    if ((arg1 == 0)) {
        return ret;
    }
    ret = (unsigned long)((unsigned int)(*(int *)(((long)arg0))));
    if (((unsigned long)((unsigned int)(arg2)) == 0)) {
        return ret;
    }
    var0 = (unsigned long)((unsigned int)(arg2));
    if (((unsigned long)((unsigned long)((unsigned int)(arg2))) < (unsigned long)(4))) {
        var3 = 0;
        goto L_1180;
    }
    var6 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var0)) & -4)));
    var15 = (*(int *)(((long)arg1)) + ret);
    var16 = *(int *)(((long)arg1 + 0x4));
    var17 = *(int *)(((long)arg1 + 0x8));
    var18 = *(int *)(((long)arg1 + 0xc));
    if ((var6 != 4)) {
        var15 = (var15 + *(int *)(((long)arg1 + 0x10)));
        var16 = (var16 + *(int *)(((long)arg1 + 0x14)));
        var17 = (var17 + *(int *)(((long)arg1 + 0x18)));
        var18 = (var18 + *(int *)(((long)arg1 + 0x1c)));
        if (((unsigned long)((unsigned int)(var6)) != 8)) {
            var15 = (var15 + *(int *)(((long)arg1 + 0x20)));
            var16 = (var16 + *(int *)(((long)arg1 + 0x24)));
            var17 = (var17 + *(int *)(((long)arg1 + 0x28)));
            var18 = (var18 + *(int *)(((long)arg1 + 0x2c)));
            if (((unsigned long)((unsigned int)(var6)) != 12)) {
                var15 = (var15 + *(int *)(((long)arg1 + 0x30)));
                var16 = (var16 + *(int *)(((long)arg1 + 0x34)));
                var17 = (var17 + *(int *)(((long)arg1 + 0x38)));
                var18 = (var18 + *(int *)(((long)arg1 + 0x3c)));
            }
        }
    }
    ret = (unsigned long)((unsigned int)(((var18 + var16) + (var17 + var15))));
    var3 = var6;
    var50 = ret;
    if ((var6 == var0)) {
        goto L_118c;
    }
    L_1180: ;
    var51 = (ret + *(int *)(((long)arg1 + var3 * 4)));
    ret = (unsigned long)((unsigned int)(var51));
    index = (var3 + 1);
    var3 = (unsigned long)((unsigned int)(index));
    var50 = (unsigned long)((unsigned int)(var51));
    if ((var0 != index)) {
        goto L_1180;
    }
    L_118c: ;
    *(int *)(((long)arg0)) = var50;
    return var50;
}

gcc -O0

1/2
aliasing_accumulate pass 26 lines
// glaurung: aliasing_accumulate @ 0x116e
int32_t aliasing_accumulate(int32_t * arg0, const int32_t * arg1, int32_t arg2) {
    int index;
    // 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 (((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;
    }
    for (index = 0; (index < arg2); index++) {
        *(int *)((long)arg0) = ((unsigned long)((unsigned int)(*(int *)((long)arg0))) + (unsigned long)((unsigned int)(arg1[(long)(index)])));
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(*(int *)((long)arg0));
}
restrict_accumulate structural 26 lines
// glaurung: restrict_accumulate @ 0x10f9
int restrict_accumulate(int * arg0, int * arg1, int arg2) {
    int index;
    // 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 (((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;
    }
    for (index = 0; (index < arg2); index++) {
        *(int *)((long)arg0) = ((unsigned long)((unsigned int)(*(int *)((long)arg0))) + (unsigned long)((unsigned int)(arg1[(long)(index)])));
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(*(int *)((long)arg0));
}

gcc -O2

1/2
aliasing_accumulate pass 29 lines
// glaurung: aliasing_accumulate @ 0x1140
int32_t aliasing_accumulate(int32_t * arg0, const int32_t * arg1, int32_t arg2) {
    int index;
    long ret;
    long var2;
    long var3;
    int var4;
    if ((arg0 == 0)) {
        return 0xffffffff;
    }
    if ((arg1 == 0)) {
        return 0xffffffff;
    }
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg2))))) {
        return 0xffffffff;
    }
    ret = (unsigned long)((unsigned int)(*(int *)(((long)arg0))));
    if (((unsigned long)((unsigned int)(arg2)) != 0)) {
        var2 = (long)((((long)arg1 + ((unsigned long)((unsigned int)((arg2 - 1))) * 4)) + 4));
        var3 = (long)arg1;
        do {
            var4 = (ret + *(int *)((var3)));
            ret = (unsigned long)((unsigned int)(var4));
            var3 = (var3 + 4);
            *(int *)(((long)arg0)) = var4;
        } while ((var3 != var2));
    }
    return ret;
}
restrict_accumulate structural 27 lines
// glaurung: restrict_accumulate @ 0x1100
int restrict_accumulate(int * arg0, int * arg1, int arg2) {
    int index;
    long ret;
    long var2;
    long var3;
    if ((arg0 == 0)) {
        return 0xffffffff;
    }
    if ((arg1 == 0)) {
        return 0xffffffff;
    }
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg2))))) {
        return 0xffffffff;
    }
    ret = (unsigned long)((unsigned int)(*(int *)(((long)arg0))));
    if (((unsigned long)((unsigned int)(arg2)) != 0)) {
        var2 = (long)((((long)arg1 + ((unsigned long)((unsigned int)((arg2 - 1))) * 4)) + 4));
        var3 = (long)arg1;
        do {
            ret = (unsigned long)((unsigned int)((ret + *(int *)((var3)))));
            var3 = (var3 + 4);
        } while ((var3 != var2));
        *(int *)(((long)arg0)) = ret;
    }
    return ret;
}

← 213 fixtures