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.
#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/2single_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/2single_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/2single_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/2single_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)));
}