Fixture 104

statement expression

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

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

Statement expressions ({ ... }): a block used where an expression is expected, yielding its last statement's value. Both compilers support them, and they let a macro evaluate its argument exactly once.

tests/decompiler_fixtures/src/104_statement_expression.c source
#include <stdint.h>

/* Statement expressions `({ ... })`: a block used where an expression is
 * expected, yielding its last statement's value. Both compilers support them,
 * and they let a macro evaluate its argument exactly once. */

#define SAFE_MAX(a, b) ({ \
    int32_t _a = (a); \
    int32_t _b = (b); \
    _a > _b ? _a : _b; \
})

#define COUNTED_SQUARE(v, counter) ({ \
    int32_t _v = (v); \
    (counter) += 1; \
    _v * _v; \
})

__attribute__((noinline)) int32_t
statement_expression_max(int32_t a, int32_t b, int32_t c) {
    return SAFE_MAX(SAFE_MAX(a, b), c);
}

__attribute__((noinline)) int32_t
single_evaluation(int32_t seed, int32_t *evaluations) {
    int32_t count = 0;
    int32_t total;
    if (evaluations == 0) {
        return -1;
    }
    /* The argument has a side effect; it must be evaluated exactly once. */
    total = COUNTED_SQUARE(seed + 1, count);
    total += COUNTED_SQUARE(seed + 2, count);
    *evaluations = count;
    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

2/2
single_evaluation pass 25 lines
// glaurung: single_evaluation @ 0x1170
int32_t single_evaluation(int32_t arg0, int32_t * arg1) {
    int count;
    int local_1c;
    int total;
    int _v;
    int local_20;
    int local_28;
    // x86-64 prologue: save rbp
    count = 0;
    if ((arg1 != 0)) {
        local_1c = ((unsigned int)(arg0) + 1);
        count = ((unsigned int)(count) + 1);
        local_20 = ((unsigned int)(local_1c) * local_1c);
        total = local_20;
        _v = ((unsigned int)(arg0) + 2);
        count = ((unsigned int)(count) + 1);
        local_28 = ((unsigned int)(_v) * _v);
        total = ((unsigned int)(local_28) + total);
        *(int *)((long)arg1) = count;
        return (unsigned int)(total);
    } else {
        return (unsigned int)(-1);
    }
}
statement_expression_max pass 20 lines
// glaurung: statement_expression_max @ 0x1100
int32_t statement_expression_max(int32_t arg0, int32_t arg1, int32_t arg2) {
    int _a;
    int local_10;
    int _b;
    int local_1c;
    int local_24;
    int local_28;
    int local_2c;
    // x86-64 prologue: save rbp
    _a = arg0;
    local_28 = ((((unsigned int)(_a) == (unsigned int)(arg1)) | (_a < arg1)) ? (unsigned long)((unsigned int)(arg1)) : (unsigned long)((unsigned int)(_a)));
    local_1c = local_28;
    local_10 = local_1c;
    _b = arg2;
    local_2c = ((((unsigned int)(local_10) == (unsigned int)(_b)) | (local_10 < _b)) ? (unsigned long)((unsigned int)(_b)) : (unsigned long)((unsigned int)(local_10)));
    local_24 = local_2c;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_24);
}

clang -O2

2/2
single_evaluation pass 14 lines
// glaurung: single_evaluation @ 0x1110
int32_t single_evaluation(int32_t arg0, int32_t * arg1) {
    int _v;
    int count;
    int total;
    int var4;
    if ((arg1 == 0)) {
        return 0xffffffff;
    }
    _v = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) + 1)));
    var4 = ((unsigned int)(arg0) + 2);
    *(int *)(((long)arg1)) = 2;
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var4)) * (unsigned long)((unsigned int)(var4))))) + (unsigned long)((unsigned int)((_v * _v)))));
}
statement_expression_max pass 6 lines
// glaurung: statement_expression_max @ 0x1100
int32_t statement_expression_max(int32_t arg0, int32_t arg1, int32_t arg2) {
    int _a;
    _a = (((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) == 0) ? arg0 : (unsigned long)((unsigned int)(arg1)));
    return ((((unsigned int)(_a) == (unsigned int)(arg2)) | (_a < arg2)) ? arg2 : _a);
}

gcc -O0

2/2
single_evaluation pass 21 lines
// glaurung: single_evaluation @ 0x1137
int32_t single_evaluation(int32_t arg0, int32_t * arg1) {
    int count;
    int _v;
    int total;
    int local_4;
    // x86-64 prologue: save rbp
    count = 0;
    if ((arg1 != 0)) {
        _v = ((unsigned int)(arg0) + 1);
        count = (count + 1);
        total = ((unsigned int)(_v) * (unsigned int)(_v));
        local_4 = ((unsigned int)(arg0) + 2);
        count = (count + 1);
        total = (total + (unsigned int)(((unsigned long)((unsigned int)(local_4)) * (unsigned long)((unsigned int)(local_4)))));
        *(int *)((long)arg1) = count;
        return (unsigned int)(total);
    } else {
        return 0xffffffff;
    }
}
statement_expression_max pass 12 lines
// glaurung: statement_expression_max @ 0x10f9
int32_t statement_expression_max(int32_t arg0, int32_t arg1, int32_t arg2) {
    int _a;
    int _b;
    int local_8;
    // x86-64 prologue: save rbp
    _a = arg0;
    _b = arg1;
    local_8 = ((_a <= _b) ? (unsigned long)((unsigned int)(_b)) : (unsigned long)((unsigned int)(_a)));
    // x86-64 epilogue: restore rbp
    return ((local_8 <= arg2) ? (unsigned long)((unsigned int)(arg2)) : (unsigned long)((unsigned int)(local_8)));
}

gcc -O2

2/2
single_evaluation pass 14 lines
// glaurung: single_evaluation @ 0x1120
int32_t single_evaluation(int32_t arg0, int32_t * arg1) {
    int _v;
    int count;
    int total;
    int var1;
    if ((arg1 == 0)) {
        return 0xffffffff;
    }
    _v = (unsigned long)((unsigned int)((arg0 + 1)));
    var1 = (arg0 + 2);
    *(int *)(((long)arg1)) = 2;
    return (unsigned int)(((unsigned long)((unsigned int)((_v * _v))) + (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var1)) * (unsigned long)((unsigned int)(var1)))))));
}
statement_expression_max pass 6 lines
// glaurung: statement_expression_max @ 0x1100
int32_t statement_expression_max(int32_t arg0, int32_t arg1, int32_t arg2) {
    int var1;
    var1 = ((arg1 < arg2) ? arg2 : arg1);
    return ((arg0 <= var1) ? var1 : (unsigned long)((unsigned int)(arg0)));
}

← 213 fixtures