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.
#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/3comma_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/3comma_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/3comma_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/3comma_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);
}