Fixture 82

comma operator

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

All 4 lanes recompile and return the same results as the original.

The comma operator: each left operand is evaluated and discarded, with a sequence point between. Recovering this correctly means keeping the discarded side effects AND their order, which a value-only view of the code loses.

tests/decompiler_fixtures/src/82_comma_operator.c source
#include <stdint.h>

/* The comma operator: each left operand is evaluated and discarded, with a
 * sequence point between. Recovering this correctly means keeping the discarded
 * side effects AND their order, which a value-only view of the code loses. */

__attribute__((noinline)) int32_t
comma_chain(int32_t seed, int32_t *trace) {
    int32_t a = 0;
    int32_t b = 0;
    int32_t c = 0;
    if (trace == 0) {
        return -1;
    }
    /* Every assignment happens; only the last value is the result. */
    c = (a = seed + 1, b = a * 2, a + b);
    trace[0] = a;
    trace[1] = b;
    return c;
}

__attribute__((noinline)) int32_t
comma_in_for(int32_t count, int32_t *trace) {
    int32_t head;
    int32_t tail;
    int32_t steps = 0;
    if (trace == 0 || count < 0 || count > 16) {
        return -1;
    }
    for (head = 0, tail = count - 1; head < tail; ++head, --tail) {
        steps += 1;
    }
    trace[0] = head;
    trace[1] = tail;
    return steps;
}

__attribute__((noinline)) int32_t
comma_in_condition(int32_t limit, int32_t *counter) {
    int32_t total = 0;
    int32_t probe = 0;
    if (counter == 0 || limit < 0 || limit > 32) {
        return -1;
    }
    while (probe += 1, probe <= limit) {
        total += probe;
    }
    *counter = probe;
    return total;
}

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
comma_chain pass 20 lines
// glaurung: comma_chain @ 0x1100
int32_t comma_chain(int32_t arg0, int32_t * arg1) {
    int a;
    int b;
    int c;
    // x86-64 prologue: save rbp
    a = 0;
    b = 0;
    c = 0;
    if ((arg1 != 0)) {
        a = ((unsigned int)(arg0) + 1);
        b = ((unsigned long)((unsigned int)(a)) << 1);
        c = ((unsigned int)(a) + b);
        *(int *)((long)arg1) = a;
        *(int *)(((long)arg1 + 0x4)) = b;
        return (unsigned int)(c);
    } else {
        return (unsigned int)(-1);
    }
}
comma_in_condition pass 35 lines
// glaurung: comma_in_condition @ 0x1210
int32_t comma_in_condition(int32_t arg0, int32_t * arg1) {
    int total;
    int probe;
    int local_4;
    // x86-64 prologue: save rbp
    total = 0;
    probe = 0;
    if ((arg1 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((long)(arg0) < 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((((unsigned long)((unsigned int)(arg0)) == 32) | ((long)(arg0) < 32)) == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    while (1) {
        probe = ((unsigned int)(probe) + 1);
        if (((((unsigned int)(probe) == (unsigned int)(arg0)) | (probe < arg0)) == 0)) {
            break;
        }
        total = ((unsigned int)(probe) + total);
    }
    *(int *)((long)arg1) = probe;
    local_4 = total;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
comma_in_for pass 36 lines
// glaurung: comma_in_for @ 0x1170
int32_t comma_in_for(int32_t arg0, int32_t * arg1) {
    int steps;
    int head;
    int tail;
    int local_4;
    // x86-64 prologue: save rbp
    steps = 0;
    if ((arg1 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((long)(arg0) < 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((((unsigned long)((unsigned int)(arg0)) == 16) | ((long)(arg0) < 16)) == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    head = 0;
    tail = ((unsigned int)(arg0) - 1);
    while ((head < tail)) {
        steps = ((unsigned int)(steps) + 1);
        head = ((unsigned int)(head) + 1);
        tail = ((unsigned int)(tail) - 1);
    }
    *(int *)((long)arg1) = head;
    *(int *)(((long)arg1 + 0x4)) = tail;
    local_4 = steps;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}

clang -O2

3/3
comma_chain pass 14 lines
// glaurung: comma_chain @ 0x1100
int32_t comma_chain(int32_t arg0, int32_t * arg1) {
    int a;
    int b;
    int c;
    int var1;
    if ((arg1 == 0)) {
        return 0xffffffff;
    }
    var1 = ((unsigned int)(arg0) + 1);
    *(int *)(((long)arg1)) = var1;
    *(int *)(((long)arg1 + 0x4)) = ((unsigned long)((unsigned int)((arg0 + arg0))) + 2);
    return (unsigned int)(((unsigned long)((unsigned int)(var1)) + ((unsigned long)((unsigned int)(var1)) * 2)));
}
comma_in_condition pass 14 lines
// glaurung: comma_in_condition @ 0x1150
int32_t comma_in_condition(int32_t arg0, int32_t * arg1) {
    int probe;
    int total;
    long ret;
    ret = 0xffffffff;
    if (((unsigned long)((unsigned long)((unsigned int)(arg0))) <= (unsigned long)(32))) {
        if ((arg1 != 0)) {
            ret = (unsigned long)((unsigned int)((((unsigned long)(((unsigned long)((unsigned int)((arg0 - 1))) * (unsigned long)((unsigned int)(arg0)))) >> 1) + arg0)));
            *(int *)(((long)arg1)) = (arg0 + 1);
        }
    }
    return ret;
}
comma_in_for pass 35 lines
// glaurung: comma_in_for @ 0x1120
int32_t comma_in_for(int32_t arg0, int32_t * arg1) {
    int head;
    int tail;
    long var2;
    long var3;
    long var6;
    int var7;
    int var8;
    head = 0xffffffff;
    if (((unsigned long)((unsigned long)((unsigned int)(arg0))) <= (unsigned long)(16))) {
        if ((arg1 == 0)) {
            return head;
        }
        tail = (unsigned long)((unsigned int)((arg0 - 1)));
        head = 0;
        var2 = 0;
        var3 = (unsigned long)((unsigned int)(tail));
        if (((unsigned long)(2) <= (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
            var6 = 0;
            do {
                var7 = (var6 + 1);
                head = (unsigned long)((unsigned int)(var7));
                var8 = (tail - 1);
                tail = (unsigned long)((unsigned int)(var8));
                var6 = (unsigned long)((unsigned int)(var7));
                var2 = (unsigned long)((unsigned int)(var7));
                var3 = (unsigned long)((unsigned int)(var8));
            } while ((var7 < var8));
        }
        *(int *)(((long)arg1)) = var2;
        *(int *)(((long)arg1 + 0x4)) = var3;
    }
    return head;
}

gcc -O0

3/3
comma_chain pass 20 lines
// glaurung: comma_chain @ 0x10f9
int32_t comma_chain(int32_t arg0, int32_t * arg1) {
    int a;
    int b;
    int c;
    // x86-64 prologue: save rbp
    a = 0;
    b = 0;
    c = 0;
    if ((arg1 != 0)) {
        a = ((unsigned int)(arg0) + 1);
        b = ((unsigned int)(a) + (unsigned int)(a));
        c = ((unsigned int)(b) + (unsigned int)(a));
        *(int *)((long)arg1) = a;
        *(int *)((arg1 + 1)) = b;
        return (unsigned int)(c);
    } else {
        return 0xffffffff;
    }
}
comma_in_condition pass 30 lines
// glaurung: comma_in_condition @ 0x11d3
int32_t comma_in_condition(int32_t arg0, int32_t * arg1) {
    int total;
    int probe;
    // x86-64 prologue: save rbp
    total = 0;
    probe = 0;
    if ((arg1 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((long)(arg0) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((((unsigned long)((unsigned int)(arg0)) == 32) | ((long)(arg0) < 32)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    while (1) {
        probe = (probe + 1);
        if (((((unsigned int)(probe) == (unsigned int)(arg0)) | (probe < arg0)) == 0)) {
            break;
        }
        total = (total + (unsigned int)(probe));
    }
    *(int *)((long)arg1) = probe;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(total);
}
comma_in_for pass 31 lines
// glaurung: comma_in_for @ 0x1162
int32_t comma_in_for(int32_t arg0, int32_t * arg1) {
    int steps;
    int head;
    int tail;
    // x86-64 prologue: save rbp
    steps = 0;
    if ((arg1 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((long)(arg0) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((((unsigned long)((unsigned int)(arg0)) == 16) | ((long)(arg0) < 16)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    head = 0;
    tail = ((unsigned int)(arg0) - 1);
    while ((head < tail)) {
        steps = (steps + 1);
        head = (head + 1);
        tail = (tail - 1);
    }
    *(int *)((long)arg1) = head;
    *(int *)((arg1 + 1)) = tail;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(steps);
}

gcc -O2

3/3
comma_chain pass 16 lines
// glaurung: comma_chain @ 0x1100
int32_t comma_chain(int32_t arg0, int32_t * arg1) {
    int b;
    int a;
    int c;
    int var1;
    if ((arg1 == 0)) {
        return 0xffffffff;
    } else {
        var1 = (arg0 + 1);
        b = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var1)) + (unsigned long)((unsigned int)(var1)))));
        *(int *)(((long)arg1)) = var1;
        *(int *)(((long)arg1 + 0x4)) = b;
        return (unsigned int)(((unsigned long)((unsigned int)(var1)) + b));
    }
}
comma_in_condition pass 32 lines
// glaurung: comma_in_condition @ 0x1170
int32_t comma_in_condition(int32_t arg0, int32_t * arg1) {
    int probe;
    int total;
    int var12;
    long var3;
    long var4;
    long var9;
    if ((arg1 == 0)) {
        return 0xffffffff;
    }
    if (((unsigned long)(32) < (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
        return 0xffffffff;
    }
    if (((unsigned long)((unsigned int)(arg0)) == 0)) {
        var3 = 1;
        var4 = 0;
    } else {
        var3 = (unsigned long)((unsigned int)((arg0 + 1)));
        var9 = 0;
        probe = 1;
        do {
            total = (var9 + probe);
            var9 = (unsigned long)((unsigned int)(total));
            var12 = (probe + 1);
            probe = (unsigned long)((unsigned int)(var12));
            var4 = (unsigned long)((unsigned int)(total));
        } while (((unsigned int)(var12) != (unsigned int)(var3)));
    }
    *(int *)(((long)arg1)) = var3;
    return (unsigned int)(var4);
}
comma_in_for pass 29 lines
// glaurung: comma_in_for @ 0x1130
int32_t comma_in_for(int32_t arg0, int32_t * arg1) {
    int tail;
    int head;
    int steps;
    long var0;
    long var3;
    long var7;
    if ((arg1 == 0)) {
        var0 = 0xffffffff;
        return 0xffffffff;
    }
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
        var0 = 0xffffffff;
        return 0xffffffff;
    }
    tail = (unsigned long)((unsigned int)((arg0 - 1)));
    if ((((unsigned long)((unsigned int)(tail)) == 0) | ((long)(tail) < 0))) {
        var0 = 0;
    } else {
        var3 = (unsigned long)((unsigned int)((arg0 - 2)));
        var7 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var3)) >> 1)));
        var0 = (unsigned long)((unsigned int)((var7 + 1)));
        tail = (unsigned long)((unsigned int)((var3 - var7)));
    }
    *(int *)(((long)arg1)) = var0;
    *(int *)(((long)arg1 + 0x4)) = tail;
    return (unsigned int)(var0);
}

← 213 fixtures