Fixture 88
restrict pointers
C · 2 functions · 4 lanes · 4 of 8 function-lanes behave identically
4 of 4 lanes have a function that returns a different result after decompilation: clang-O0 (1/2), clang-O2 (1/2), gcc-O0 (1/2), gcc-O2 (1/2).
C99 restrict promises no aliasing, which licenses the compiler to keep values in registers across stores it would otherwise have to reload. The aliasing and non-aliasing variants below are deliberately identical apart from the qualifier, so the generated code diverges while the source does not.
#include <stdint.h>
/* C99 `restrict` promises no aliasing, which licenses the compiler to keep
* values in registers across stores it would otherwise have to reload. The
* aliasing and non-aliasing variants below are deliberately identical apart
* from the qualifier, so the generated code diverges while the source does not. */
__attribute__((noinline)) int32_t
restrict_accumulate(int32_t *restrict destination,
const int32_t *restrict source, int32_t count) {
int32_t index;
if (destination == 0 || source == 0 || count < 0 || count > 16) {
return -1;
}
for (index = 0; index < count; ++index) {
destination[0] += source[index];
}
return destination[0];
}
__attribute__((noinline)) int32_t
aliasing_accumulate(int32_t *destination, const int32_t *source, int32_t count) {
int32_t index;
if (destination == 0 || source == 0 || count < 0 || count > 16) {
return -1;
}
for (index = 0; index < count; ++index) {
destination[0] += source[index];
}
return destination[0];
} 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
1/2aliasing_accumulate pass 32 lines
// glaurung: aliasing_accumulate @ 0x1190
int32_t aliasing_accumulate(int32_t * arg0, const int32_t * arg1, int32_t arg2) {
int index;
int local_4;
// x86-64 prologue: save rbp
if ((arg0 == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if ((arg1 == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if (((long)(arg2) < 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if (((((unsigned long)((unsigned int)(arg2)) == 16) | ((long)(arg2) < 16)) == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
for (index = 0; (index < arg2); index++) {
*(int *)((long)arg0) = ((unsigned long)((unsigned int)(arg1[(long)(index)])) + *(int *)((long)arg0));
}
local_4 = *(int *)((long)arg0);
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} restrict_accumulate structural 32 lines
// glaurung: restrict_accumulate @ 0x1100
int restrict_accumulate(int * arg0, int * arg1, int arg2) {
int index;
int local_4;
// x86-64 prologue: save rbp
if ((arg0 == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if ((arg1 == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if (((long)(arg2) < 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if (((((unsigned long)((unsigned int)(arg2)) == 16) | ((long)(arg2) < 16)) == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
for (index = 0; (index < arg2); index++) {
*(int *)((long)arg0) = ((unsigned long)((unsigned int)(arg1[(long)(index)])) + *(int *)((long)arg0));
}
local_4 = *(int *)((long)arg0);
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} clang -O2
1/2aliasing_accumulate pass 67 lines
// glaurung: aliasing_accumulate @ 0x1190
int32_t aliasing_accumulate(int32_t * arg0, const int32_t * arg1, int32_t arg2) {
int index;
long ret;
long var0;
long var1;
int var11;
int var13;
int var15;
long var16;
long var17;
long var20;
long var22;
int var23;
long var5;
int var9;
ret = 0xffffffff;
if (((unsigned long)((unsigned long)((unsigned int)(arg2))) <= (unsigned long)(16))) {
if ((arg0 == 0)) {
return ret;
}
if ((arg1 == 0)) {
return ret;
}
if (((unsigned long)((unsigned int)(arg2)) == 0)) {
return (unsigned int)(*(int *)(((long)arg0)));
}
var0 = (unsigned long)((unsigned int)(arg2));
var1 = (unsigned long)((unsigned int)(*(int *)(((long)arg0))));
var5 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) & 3)));
if (((unsigned long)(3) <= (unsigned long)(((unsigned long)((unsigned int)(arg2)) - 1)))) {
var0 = (unsigned long)((unsigned int)((var0 & -4)));
index = 0;
do {
var9 = (var1 + *(int *)(((long)arg1 + index * 4)));
*(int *)(((long)arg0)) = var9;
var11 = ((unsigned int)(var9) + *(int *)(((long)arg1 + index * 4 + 0x4)));
*(int *)(((long)arg0)) = var11;
var13 = ((unsigned int)(var11) + *(int *)(((long)arg1 + index * 4 + 0x8)));
*(int *)(((long)arg0)) = var13;
var15 = ((unsigned int)(var13) + *(int *)(((long)arg1 + index * 4 + 0xc)));
var1 = (unsigned long)((unsigned int)(var15));
*(int *)(((long)arg0)) = var15;
index = (index + 4);
var16 = (unsigned long)((unsigned int)(var15));
var17 = (unsigned long)((unsigned int)(index));
} while ((var0 != index));
} else {
var16 = var1;
var17 = 0;
}
ret = var16;
if ((var5 == 0)) {
return ret;
}
var20 = (long)(((long)arg1 + (var17 * 4)));
var22 = 0;
do {
var23 = (var16 + *(int *)((var20 + var22 * 4)));
var16 = (unsigned long)((unsigned int)(var23));
*(int *)(((long)arg0)) = var23;
var22 = (var22 + 1);
ret = (unsigned long)((unsigned int)(var23));
} while ((var5 != var22));
}
return ret;
} restrict_accumulate structural 74 lines
// glaurung: restrict_accumulate @ 0x1100
int restrict_accumulate(int * arg0, int * arg1, int arg2) {
int index;
long ret;
long var0;
int var15;
int var16;
int var17;
int var18;
long var3;
long var50;
int var51;
long var6;
ret = 0xffffffff;
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg2))))) {
return ret;
}
if ((arg0 == 0)) {
return ret;
}
if ((arg1 == 0)) {
return ret;
}
ret = (unsigned long)((unsigned int)(*(int *)(((long)arg0))));
if (((unsigned long)((unsigned int)(arg2)) == 0)) {
return ret;
}
var0 = (unsigned long)((unsigned int)(arg2));
if (((unsigned long)((unsigned long)((unsigned int)(arg2))) < (unsigned long)(4))) {
var3 = 0;
goto L_1180;
}
var6 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var0)) & -4)));
var15 = (*(int *)(((long)arg1)) + ret);
var16 = *(int *)(((long)arg1 + 0x4));
var17 = *(int *)(((long)arg1 + 0x8));
var18 = *(int *)(((long)arg1 + 0xc));
if ((var6 != 4)) {
var15 = (var15 + *(int *)(((long)arg1 + 0x10)));
var16 = (var16 + *(int *)(((long)arg1 + 0x14)));
var17 = (var17 + *(int *)(((long)arg1 + 0x18)));
var18 = (var18 + *(int *)(((long)arg1 + 0x1c)));
if (((unsigned long)((unsigned int)(var6)) != 8)) {
var15 = (var15 + *(int *)(((long)arg1 + 0x20)));
var16 = (var16 + *(int *)(((long)arg1 + 0x24)));
var17 = (var17 + *(int *)(((long)arg1 + 0x28)));
var18 = (var18 + *(int *)(((long)arg1 + 0x2c)));
if (((unsigned long)((unsigned int)(var6)) != 12)) {
var15 = (var15 + *(int *)(((long)arg1 + 0x30)));
var16 = (var16 + *(int *)(((long)arg1 + 0x34)));
var17 = (var17 + *(int *)(((long)arg1 + 0x38)));
var18 = (var18 + *(int *)(((long)arg1 + 0x3c)));
}
}
}
ret = (unsigned long)((unsigned int)(((var18 + var16) + (var17 + var15))));
var3 = var6;
var50 = ret;
if ((var6 == var0)) {
goto L_118c;
}
L_1180: ;
var51 = (ret + *(int *)(((long)arg1 + var3 * 4)));
ret = (unsigned long)((unsigned int)(var51));
index = (var3 + 1);
var3 = (unsigned long)((unsigned int)(index));
var50 = (unsigned long)((unsigned int)(var51));
if ((var0 != index)) {
goto L_1180;
}
L_118c: ;
*(int *)(((long)arg0)) = var50;
return var50;
} gcc -O0
1/2aliasing_accumulate pass 26 lines
// glaurung: aliasing_accumulate @ 0x116e
int32_t aliasing_accumulate(int32_t * arg0, const int32_t * arg1, int32_t arg2) {
int index;
// x86-64 prologue: save rbp
if ((arg0 == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if ((arg1 == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if (((long)(arg2) < 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if (((((unsigned long)((unsigned int)(arg2)) == 16) | ((long)(arg2) < 16)) == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
for (index = 0; (index < arg2); index++) {
*(int *)((long)arg0) = ((unsigned long)((unsigned int)(*(int *)((long)arg0))) + (unsigned long)((unsigned int)(arg1[(long)(index)])));
}
// x86-64 epilogue: restore rbp
return (unsigned int)(*(int *)((long)arg0));
} restrict_accumulate structural 26 lines
// glaurung: restrict_accumulate @ 0x10f9
int restrict_accumulate(int * arg0, int * arg1, int arg2) {
int index;
// x86-64 prologue: save rbp
if ((arg0 == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if ((arg1 == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if (((long)(arg2) < 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if (((((unsigned long)((unsigned int)(arg2)) == 16) | ((long)(arg2) < 16)) == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
for (index = 0; (index < arg2); index++) {
*(int *)((long)arg0) = ((unsigned long)((unsigned int)(*(int *)((long)arg0))) + (unsigned long)((unsigned int)(arg1[(long)(index)])));
}
// x86-64 epilogue: restore rbp
return (unsigned int)(*(int *)((long)arg0));
} gcc -O2
1/2aliasing_accumulate pass 29 lines
// glaurung: aliasing_accumulate @ 0x1140
int32_t aliasing_accumulate(int32_t * arg0, const int32_t * arg1, int32_t arg2) {
int index;
long ret;
long var2;
long var3;
int var4;
if ((arg0 == 0)) {
return 0xffffffff;
}
if ((arg1 == 0)) {
return 0xffffffff;
}
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg2))))) {
return 0xffffffff;
}
ret = (unsigned long)((unsigned int)(*(int *)(((long)arg0))));
if (((unsigned long)((unsigned int)(arg2)) != 0)) {
var2 = (long)((((long)arg1 + ((unsigned long)((unsigned int)((arg2 - 1))) * 4)) + 4));
var3 = (long)arg1;
do {
var4 = (ret + *(int *)((var3)));
ret = (unsigned long)((unsigned int)(var4));
var3 = (var3 + 4);
*(int *)(((long)arg0)) = var4;
} while ((var3 != var2));
}
return ret;
} restrict_accumulate structural 27 lines
// glaurung: restrict_accumulate @ 0x1100
int restrict_accumulate(int * arg0, int * arg1, int arg2) {
int index;
long ret;
long var2;
long var3;
if ((arg0 == 0)) {
return 0xffffffff;
}
if ((arg1 == 0)) {
return 0xffffffff;
}
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg2))))) {
return 0xffffffff;
}
ret = (unsigned long)((unsigned int)(*(int *)(((long)arg0))));
if (((unsigned long)((unsigned int)(arg2)) != 0)) {
var2 = (long)((((long)arg1 + ((unsigned long)((unsigned int)((arg2 - 1))) * 4)) + 4));
var3 = (long)arg1;
do {
ret = (unsigned long)((unsigned int)((ret + *(int *)((var3)))));
var3 = (var3 + 4);
} while ((var3 != var2));
*(int *)(((long)arg0)) = ret;
}
return ret;
}