Fixture 122
compound assignment
C · 3 functions · 4 lanes · 11 of 12 function-lanes behave identically
One lane has a function that returns a different result after decompilation: clang-O2 (2/3).
In E1 op= E2 the lvalue E1 is evaluated exactly once, which matters when the subscript itself has a side effect. Compound assignment also converts back to the left operand's type, so a narrow target truncates each step.
#include <stdint.h>
/* In `E1 op= E2` the lvalue E1 is evaluated exactly once, which matters when
* the subscript itself has a side effect. Compound assignment also converts
* back to the left operand's type, so a narrow target truncates each step. */
__attribute__((noinline)) int32_t
subscript_evaluated_once(int32_t *values, int32_t count, int32_t *cursor) {
if (values == 0 || cursor == 0 || count < 1 || count > 16) {
return -1;
}
*cursor = 0;
/* The postincrement happens once, not twice. */
values[(*cursor)++] += 100;
return *cursor;
}
__attribute__((noinline)) int32_t
narrow_compound_truncates(int32_t seed, int32_t steps) {
uint8_t narrow = (uint8_t)seed;
int32_t step;
if (steps < 0 || steps > 16) {
return -1;
}
for (step = 0; step < steps; ++step) {
narrow += 50; /* wraps at 256 every time, not once at the end */
}
return (int32_t)narrow;
}
__attribute__((noinline)) int32_t
mixed_compound_operators(int32_t seed) {
int32_t value = seed;
value += 7;
value *= 3;
value ^= 0x55;
value >>= 1;
value |= 1;
value -= 2;
return value;
} 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 -O2
2/3mixed_compound_operators pass 5 lines
// glaurung: mixed_compound_operators @ 0x1240
int32_t mixed_compound_operators(int32_t arg0) {
int value;
return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((int)(((unsigned long)((unsigned int)((arg0 + (arg0 * 2)))) + 21)) >> 1))) | 1))) ^ 42))) - 2));
} narrow_compound_truncates fail 91 lines
// glaurung: narrow_compound_truncates @ 0x1130
int32_t narrow_compound_truncates(int32_t arg0, int32_t arg1) {
extern long __unknown(long, ...);
int step;
long ret;
long var0;
long var2;
int var3;
int var30;
int var34;
long var39;
int var40;
long var5;
int var6;
int var62;
int var72;
int var79;
long var86;
long var87;
int var89;
int var91;
ret = 0xffffffff;
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return ret;
}
var0 = (unsigned long)((unsigned int)(arg0));
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
return (unsigned int)((unsigned char)((var0 & 255)));
}
var2 = 0;
var3 = arg0;
if (((unsigned long)((unsigned long)((unsigned int)(arg1))) < (unsigned long)(8))) {
goto L_1214;
}
var5 = 0;
var6 = arg0;
if (((unsigned long)(16) <= (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
var5 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & -16)));
ret = ((unsigned long)((unsigned int)(arg0)) & 255);
/* asm: packuswb */
/* asm: packuswb */
/* asm: paddb */
/* asm: paddb */
/* asm: psadbw */
var6 = 0;
var0 = 0;
if (((unsigned int)(var5) == (unsigned int)(arg1))) {
return (unsigned int)((unsigned char)((var0 & 255)));
}
var2 = var5;
var3 = 0;
if (((unsigned long)((unsigned char)((arg1 & 8))) == 0)) {
goto L_1214;
}
}
var2 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & -8)));
var30 = var6;
ret = 0;
var34 = 0;
var39 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var5)) - var2)));
var40 = 255;
do {
/* asm: packuswb */
/* asm: packuswb */
var62 = (var30 & var40);
/* asm: paddb */
var72 = __unknown(0);
/* asm: punpckhwd */
var30 = ((unsigned int)((unsigned short)(var72)) | ((unsigned int)((unsigned short)(var34)) << 16));
var79 = (var39 + 8);
var39 = (unsigned long)((unsigned int)(var79));
} while (((unsigned long)((unsigned int)(var79)) != 0));
ret = 0;
/* asm: psadbw */
var3 = (unsigned int)((unsigned char)(((unsigned long)((unsigned int)(var62)) & 255)));
var0 = (unsigned long)((unsigned int)(var3));
if (((unsigned int)(var2) == (unsigned int)(arg1))) {
return (unsigned int)((unsigned char)((var0 & 255)));
}
L_1214: ;
var86 = (unsigned long)((unsigned int)((arg1 - var2)));
var87 = (unsigned long)((unsigned int)(var3));
do {
var89 = ((unsigned int)((unsigned char)((var87 & 255))) + 50);
var91 = (var86 - 1);
var86 = (unsigned long)((unsigned int)(var91));
var87 = (unsigned long)((unsigned int)(var89));
var0 = (unsigned long)((unsigned int)(var89));
} while (((unsigned long)((unsigned int)(var91)) != 0));
return (unsigned int)((unsigned char)((var0 & 255)));
} subscript_evaluated_once pass 16 lines
// glaurung: subscript_evaluated_once @ 0x1100
int32_t subscript_evaluated_once(int32_t * arg0, int32_t arg1, int32_t * arg2) {
long ret;
ret = 0xffffffff;
if (((unsigned long)(0xfffffff0) <= (unsigned long)((unsigned long)((unsigned int)((arg1 - 17)))))) {
if ((arg0 == 0)) {
return ret;
}
if ((arg2 != 0)) {
*(int *)(((long)arg2)) = 1;
*(int *)(((long)arg0)) = (*(int *)(((long)arg0)) + 100);
ret = (unsigned long)((unsigned int)(*(int *)(((long)arg2))));
}
}
return ret;
} clang -O0
3/3mixed_compound_operators pass 14 lines
// glaurung: mixed_compound_operators @ 0x11f0
int32_t mixed_compound_operators(int32_t arg0) {
int value;
// x86-64 prologue: save rbp
value = arg0;
value = ((unsigned int)(value) + 7);
value = (value * 3);
value = ((unsigned int)(value) ^ 85);
value = ((int)(value) >> 1);
value = ((unsigned int)(value) | 1);
value = ((unsigned int)(value) - 2);
// x86-64 epilogue: restore rbp
return (unsigned int)(value);
} narrow_compound_truncates pass 23 lines
// glaurung: narrow_compound_truncates @ 0x1180
int32_t narrow_compound_truncates(int32_t arg0, int32_t arg1) {
unsigned char narrow;
int step;
int local_4;
// x86-64 prologue: save rbp
narrow = arg0;
if (((long)(arg1) < 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
for (step = 0; (step < arg1); step++) {
narrow = (narrow + 50);
}
// x86-64 epilogue: restore rbp
return (unsigned int)(narrow);
} subscript_evaluated_once pass 33 lines
// glaurung: subscript_evaluated_once @ 0x1100
int32_t subscript_evaluated_once(int32_t * arg0, int32_t arg1, int32_t * arg2) {
int local_4;
long var3;
// x86-64 prologue: save rbp
if ((arg0 == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if ((arg2 == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if (((long)(arg1) < 1)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
*(int *)((long)arg2) = 0;
var3 = (unsigned long)((unsigned int)(*(int *)((long)arg2)));
*(int *)((long)arg2) = ((unsigned long)((unsigned int)(var3)) + 1);
arg0[(long)((int)(var3))] = ((unsigned long)((unsigned int)(arg0[(long)((int)(var3))])) + 100);
local_4 = *(int *)((long)arg2);
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} gcc -O0
3/3mixed_compound_operators pass 14 lines
// glaurung: mixed_compound_operators @ 0x11be
int32_t mixed_compound_operators(int32_t arg0) {
int value;
// x86-64 prologue: save rbp
value = arg0;
value = (value + 7);
value = ((unsigned int)(((unsigned long)((unsigned int)(value)) + (unsigned long)((unsigned int)(value)))) + (unsigned int)(value));
value = (value ^ 85);
value = ((int)(value) >> 1);
value = (value | 1);
value = (value - 2);
// x86-64 epilogue: restore rbp
return (unsigned int)(value);
} narrow_compound_truncates pass 20 lines
// glaurung: narrow_compound_truncates @ 0x1178
int32_t narrow_compound_truncates(int32_t arg0, int32_t arg1) {
unsigned char narrow;
int step;
// x86-64 prologue: save rbp
narrow = arg0;
if (((long)(arg1) < 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
for (step = 0; (step < arg1); step++) {
narrow = (narrow + 50);
}
// x86-64 epilogue: restore rbp
return (unsigned int)(narrow);
} subscript_evaluated_once pass 27 lines
// glaurung: subscript_evaluated_once @ 0x10f9
int32_t subscript_evaluated_once(int32_t * arg0, int32_t arg1, int32_t * arg2) {
long var2;
// x86-64 prologue: save rbp
if ((arg0 == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if ((arg2 == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if ((((unsigned long)((unsigned int)(arg1)) == 0) | ((long)(arg1) < 0))) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
*(int *)((long)arg2) = 0;
var2 = (unsigned long)((unsigned int)(*(int *)((long)arg2)));
*(int *)((long)arg2) = (var2 + 1);
arg0[(long)((int)(var2))] = ((unsigned long)((unsigned int)(arg0[(long)((int)(var2))])) + 100);
// x86-64 epilogue: restore rbp
return (unsigned int)(*(int *)((long)arg2));
} gcc -O2
3/3mixed_compound_operators pass 5 lines
// glaurung: mixed_compound_operators @ 0x1160
int32_t mixed_compound_operators(int32_t arg0) {
int value;
return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((int)(((arg0 + (arg0 * 2)) + 21)) >> 1))) ^ 42))) | 1))) - 2));
} narrow_compound_truncates pass 14 lines
// glaurung: narrow_compound_truncates @ 0x1130
int32_t narrow_compound_truncates(int32_t arg0, int32_t arg1) {
unsigned char narrow;
int step;
long var0;
var0 = (unsigned long)((unsigned int)(arg0));
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return 0xffffffff;
}
if (((unsigned long)((unsigned int)(arg1)) != 0)) {
var0 = (unsigned long)((unsigned int)((((unsigned long)((unsigned int)(((unsigned long)((unsigned int)((arg1 - 1))) * 50))) + arg0) + 50)));
}
return (unsigned int)((unsigned char)((var0 & 255)));
} subscript_evaluated_once pass 14 lines
// glaurung: subscript_evaluated_once @ 0x1100
int32_t subscript_evaluated_once(int32_t * arg0, int32_t arg1, int32_t * arg2) {
if ((arg0 != 0)) {
if ((arg2 == 0)) {
return 0xffffffff;
}
if (((unsigned long)((unsigned long)((unsigned int)((arg1 - 1)))) <= (unsigned long)(15))) {
*(int *)(((long)arg2)) = 1;
*(int *)(((long)arg0)) = (*(int *)(((long)arg0)) + 100);
return (unsigned int)(*(int *)(((long)arg2)));
}
}
return 0xffffffff;
}