Fixture 102
duffs device
C · 1 functions · 4 lanes · 0 of 4 function-lanes behave identically
4 of 4 lanes have a function that returns a different result after decompilation: clang-O0 (0/1), clang-O2 (0/1), gcc-O0 (0/1), gcc-O2 (0/1).
Duff's device: a switch whose cases fall into the middle of a do/while. The loop and the switch share a body, so no structuring that treats them as separate regions can reproduce it.
#include <stdint.h>
/* Duff's device: a switch whose cases fall into the middle of a do/while. The
* loop and the switch share a body, so no structuring that treats them as
* separate regions can reproduce it. */
#define DUFF_MAX 16
__attribute__((noinline)) int32_t
duff_copy(const int32_t *source, int32_t *destination, int32_t count) {
int32_t index = 0;
int32_t blocks;
if (source == 0 || destination == 0 || count < 1 || count > DUFF_MAX) {
return -1;
}
blocks = (count + 7) / 8;
switch (count % 8) {
case 0:
do {
destination[index] = source[index];
index += 1;
__attribute__((fallthrough));
case 7:
destination[index] = source[index];
index += 1;
__attribute__((fallthrough));
case 6:
destination[index] = source[index];
index += 1;
__attribute__((fallthrough));
case 5:
destination[index] = source[index];
index += 1;
__attribute__((fallthrough));
case 4:
destination[index] = source[index];
index += 1;
__attribute__((fallthrough));
case 3:
destination[index] = source[index];
index += 1;
__attribute__((fallthrough));
case 2:
destination[index] = source[index];
index += 1;
__attribute__((fallthrough));
case 1:
destination[index] = source[index];
index += 1;
} while (--blocks > 0);
}
return index;
} 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
0/1duff_copy fail 35 lines
// glaurung: duff_copy @ 0x1100
int32_t duff_copy(const int32_t * arg0, int32_t * arg1, int32_t arg2) {
int index;
int blocks;
long local_30;
int local_4;
long var19;
int var2;
index = 0;
if ((arg0 != 0)) {
if ((arg1 != 0)) {
if ((1 <= (long)(arg2))) {
if ((((unsigned long)((unsigned int)(arg2)) == 16) | ((long)(arg2) < 16))) {
goto L_114c;
}
}
}
}
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
L_114c: ;
var2 = ((unsigned int)(arg2) + 7);
blocks = ((int)((((long)((int)(var2)) < 0) ? (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) + 14))) : (unsigned long)((unsigned int)(var2)))) >> 3);
var19 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) - (unsigned long)((unsigned int)(((((long)(arg2) < 0) ? (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) + 7))) : (unsigned long)((unsigned int)(arg2))) & -8))))));
local_30 = (unsigned int)(var19);
if (((((unsigned long)((unsigned long)((unsigned int)(var19))) < (unsigned long)(7)) | ((unsigned long)((unsigned int)((var19 - 7))) == 0)) == 0)) {
goto L_12ad;
}
/* unrecovered indirect jump through ((long)((int)(*(int *)((0x2000 + (local_30 * 4))))) + 0x2000) */
L_12ad: ;
local_4 = index;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} clang -O2
0/1duff_copy fail 17 lines
// glaurung: duff_copy @ 0x1100
int32_t duff_copy(const int32_t * arg0, int32_t * arg1, int32_t arg2) {
int blocks;
int index;
long ret;
ret = 0xffffffff;
if ((arg0 == 0)) {
return ret;
}
if ((arg1 == 0)) {
return ret;
}
if (((unsigned long)((unsigned long)((unsigned int)((arg2 - 17)))) < (unsigned long)(0xfffffff0))) {
return ret;
}
/* unrecovered indirect jump through ((long)((int)((((unsigned long)((unsigned int)((arg2 & 7))) == 0) ? 0xfffff140 : (((unsigned long)((unsigned int)((arg2 & 7))) == 1) ? 0xfffff18e : (((unsigned long)((unsigned int)((arg2 & 7))) == 2) ? 0xfffff183 : (((unsigned long)((unsigned int)((arg2 & 7))) == 3) ? 0xfffff178 : (((unsigned long)((unsigned int)((arg2 & 7))) == 4) ? 0xfffff16d : (((unsigned long)((unsigned int)((arg2 & 7))) == 5) ? 0xfffff162 : (((unsigned long)((unsigned int)((arg2 & 7))) == 6) ? 0xfffff157 : (((unsigned long)((unsigned int)((arg2 & 7))) == 7) ? 0xfffff14c : *(int *)((0x2000 + ((unsigned long)((unsigned int)((arg2 & 7))) * 4))))))))))))) + 0x2000) */
} gcc -O0
0/1duff_copy fail 30 lines
// glaurung: duff_copy @ 0x10f9
int32_t duff_copy(const int32_t * arg0, int32_t * arg1, int32_t arg2) {
int index;
int blocks;
int var1;
long var12;
long var18;
index = 0;
if ((arg0 != 0)) {
if ((arg1 != 0)) {
if (((((unsigned long)((unsigned int)(arg2)) == 0) | ((long)(arg2) < 0)) == 0)) {
if ((((unsigned long)((unsigned int)(arg2)) == 16) | ((long)(arg2) < 16))) {
goto L_1137;
}
}
}
}
// x86-64 epilogue: restore rbp
return 0xffffffff;
L_1137: ;
var1 = ((unsigned int)(arg2) + 7);
blocks = ((int)((((long)((int)(var1)) < 0) ? (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var1)) + 7))) : (unsigned long)((unsigned int)(var1)))) >> 3);
var12 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)((((unsigned long)((long)(arg2)) >> 32) & 0xffffffff))) >> 29)));
var18 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) + var12))) & 7))) - var12)));
if (((unsigned long)(7) < (unsigned long)((unsigned long)((unsigned int)(var18))))) {
// x86-64 epilogue: restore rbp
return (unsigned int)(index);
}
/* unrecovered indirect jump through ((long)((int)((((unsigned long)((unsigned int)(var18)) == 0) ? 0xfffff186 : (((unsigned long)((unsigned int)(var18)) == 1) ? 0xfffff2dd : (((unsigned long)((unsigned int)(var18)) == 2) ? 0xfffff2ac : (((unsigned long)((unsigned int)(var18)) == 3) ? 0xfffff27b : (((unsigned long)((unsigned int)(var18)) == 4) ? 0xfffff24a : (((unsigned long)((unsigned int)(var18)) == 5) ? 0xfffff219 : (((unsigned long)((unsigned int)(var18)) == 6) ? 0xfffff1e8 : (((unsigned long)((unsigned int)(var18)) == 7) ? 0xfffff1b7 : *(int *)((((unsigned long)((unsigned int)(var18)) * 4) + 0x2000)))))))))))) + 0x2000) */
} gcc -O2
0/1duff_copy fail 54 lines
// glaurung: duff_copy @ 0x1100
int32_t duff_copy(const int32_t * arg0, int32_t * arg1, int32_t arg2) {
int blocks;
int index;
long var1;
long var14;
long var15;
long var16;
long var17;
long var18;
long var19;
long var21;
long var24;
long var27;
long var4;
if ((arg0 == 0)) {
goto L_12e0;
}
if ((arg1 == 0)) {
goto L_12e0;
}
if (((unsigned long)(15) < (unsigned long)((unsigned long)((unsigned int)((arg2 - 1)))))) {
goto L_12e0;
}
var1 = (long)arg0;
var4 = (unsigned long)((unsigned int)((arg2 & 7)));
/* unrecovered indirect jump through ((long)((int)((((unsigned long)((unsigned int)(var4)) == 0) ? 0xfffff2e8 : (((unsigned long)((unsigned int)(var4)) == 1) ? 0xfffff230 : (((unsigned long)((unsigned int)(var4)) == 2) ? 0xfffff240 : (((unsigned long)((unsigned int)(var4)) == 3) ? 0xfffff250 : (((unsigned long)((unsigned int)(var4)) == 4) ? 0xfffff268 : (((unsigned long)((unsigned int)(var4)) == 5) ? 0xfffff288 : (((unsigned long)((unsigned int)(var4)) == 6) ? 0xfffff2b0 : (((unsigned long)((unsigned int)(var4)) == 7) ? 0xfffff150 : *(int *)((0x2000 + ((unsigned long)((unsigned int)(var4)) * 4))))))))))))) + 0x2000) */
L_1180: ;
var21 = (long)((int)(var4));
var4 = (unsigned long)((unsigned int)((var4 + 8)));
var24 = (var21 << 2);
var27 = (var24 + 4);
var19 = (var24 + 8);
var15 = (var24 + 12);
var18 = (var24 + 16);
var17 = (var24 + 20);
var16 = (var24 + 24);
var14 = (var24 + 28);
*(int *)(((long)arg1 + var24)) = *(int *)((var1 + var24));
*(int *)((var27 + (long)arg1)) = *(int *)((var1 + var27));
*(int *)((var19 + (long)arg1)) = *(int *)((var1 + var19));
*(int *)((var15 + (long)arg1)) = *(int *)((var1 + var15));
*(int *)((var18 + (long)arg1)) = *(int *)((var1 + var18));
*(int *)((var17 + (long)arg1)) = *(int *)((var1 + var17));
*(int *)((var16 + (long)arg1)) = *(int *)((var1 + var16));
*(int *)((var14 + (long)arg1)) = *(int *)((var1 + var14));
if (0) {
goto L_1180;
}
// x86-64 epilogue: tear down frame
return (unsigned int)(var4);
L_12e0: ;
return 0xffffffff;
}