Fixture 128
qualifier combinations
C · 3 functions · 4 lanes · 10 of 12 function-lanes behave identically
2 of 4 lanes have a function that returns a different result after decompilation: clang-O0 (2/3), gcc-O0 (2/3).
The qualifier binds to what precedes the const: const int * is a mutable pointer to constant data, int *const is a constant pointer to mutable data. They generate different code for the same-looking source.
#include <stdint.h>
/* The qualifier binds to what precedes the const: `const int *` is a mutable
* pointer to constant data, `int *const` is a constant pointer to mutable data.
* They generate different code for the same-looking source. */
__attribute__((noinline)) int32_t
pointer_to_const_walks(const int32_t *values, int32_t count) {
const int32_t *cursor = values; /* the pointer may move */
int32_t total = 0;
int32_t index;
if (values == 0 || count < 0 || count > 16) {
return -1;
}
for (index = 0; index < count; ++index) {
total += *cursor;
cursor += 1;
}
return total;
}
__attribute__((noinline)) int32_t
const_pointer_writes(int32_t *const target, int32_t count) {
int32_t index;
if (target == 0 || count < 0 || count > 16) {
return -1;
}
/* The pointer cannot move, but the pointee can change. */
for (index = 0; index < count; ++index) {
target[index] = index * 2;
}
return target[0] + count;
}
__attribute__((noinline)) int32_t
volatile_const_is_readable(int32_t seed) {
/* A hardware-register idiom: not writable here, but re-read every time. */
volatile const int32_t cell = seed;
int32_t total = 0;
total += cell;
total += cell;
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/3const_pointer_writes fail 27 lines
// glaurung: const_pointer_writes @ 0x1190
int32_t const_pointer_writes(const int32_t * arg0, int32_t arg1) {
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 (((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 (index = 0; (index < arg1); index++) {
arg0[(long)(index)] = ((unsigned long)((unsigned int)(index)) << 1);
}
local_4 = ((unsigned int)(*(int *)((long)arg0)) + arg1);
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} pointer_to_const_walks pass 32 lines
// glaurung: pointer_to_const_walks @ 0x1100
int32_t pointer_to_const_walks(const int32_t * arg0, int32_t arg1) {
int * cursor;
int total;
int index;
int local_4;
// x86-64 prologue: save rbp
cursor = (int *)arg0;
total = 0;
if ((arg0 == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
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 (index = 0; (index < arg1); index++) {
total = ((unsigned int)(*(int *)(cursor)) + total);
cursor = (int *)((cursor + 1));
}
local_4 = total;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} volatile_const_is_readable pass 12 lines
// glaurung: volatile_const_is_readable @ 0x1210
int32_t volatile_const_is_readable(int32_t arg0) {
int cell;
int total;
// x86-64 prologue: save rbp
cell = arg0;
total = 0;
total = ((unsigned int)(cell) + total);
total = ((unsigned int)(cell) + total);
// x86-64 epilogue: restore rbp
return (unsigned int)(total);
} gcc -O0
2/3const_pointer_writes fail 22 lines
// glaurung: const_pointer_writes @ 0x1159
int32_t const_pointer_writes(const int32_t * arg0, int32_t arg1) {
int index;
// x86-64 prologue: save rbp
if ((arg0 == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
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 (index = 0; (index < arg1); index++) {
arg0[(long)(index)] = ((unsigned long)((unsigned int)(index)) + (unsigned long)((unsigned int)(index)));
}
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) + (unsigned long)((unsigned int)(*(int *)((long)arg0)))));
} pointer_to_const_walks pass 27 lines
// glaurung: pointer_to_const_walks @ 0x10f9
int32_t pointer_to_const_walks(const int32_t * arg0, int32_t arg1) {
int * cursor;
int total;
int index;
// x86-64 prologue: save rbp
cursor = (int *)arg0;
total = 0;
if ((arg0 == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
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 (index = 0; (index < arg1); index++) {
total = (total + (unsigned int)(*(int *)(cursor)));
cursor = (int *)((cursor + 1));
}
// x86-64 epilogue: restore rbp
return (unsigned int)(total);
} volatile_const_is_readable pass 12 lines
// glaurung: volatile_const_is_readable @ 0x11bf
int32_t volatile_const_is_readable(int32_t arg0) {
int cell;
int total;
// x86-64 prologue: save rbp
cell = arg0;
total = 0;
total = (total + (unsigned int)(cell));
total = (total + (unsigned int)(cell));
// x86-64 epilogue: restore rbp
return (unsigned int)(total);
} clang -O2
3/3const_pointer_writes pass 66 lines
// glaurung: const_pointer_writes @ 0x1230
int32_t const_pointer_writes(const int32_t * arg0, int32_t arg1) {
int index;
long ret;
long t2;
long var0;
long var20;
int var21;
long var23;
long var3;
ret = 0xffffffff;
if ((arg0 == 0)) {
return ret;
}
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return ret;
}
if (((unsigned long)((unsigned int)(arg1)) != 0)) {
var0 = (unsigned long)((unsigned int)(arg1));
if (((unsigned long)(4) <= (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
var3 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var0)) & -4)));
*(int *)(((long)arg0)) = 0;
*(int *)(((long)arg0 + 0x4)) = 2;
*(int *)(((long)arg0 + 0x8)) = 4;
*(int *)(((long)arg0 + 0xc)) = 6;
if ((var3 != 4)) {
*(int *)(((long)arg0 + 0x10)) = 8;
*(int *)(((long)arg0 + 0x14)) = 10;
*(int *)(((long)arg0 + 0x18)) = 12;
*(int *)(((long)arg0 + 0x1c)) = 14;
if (((unsigned long)((unsigned int)(var3)) != 8)) {
*(int *)(((long)arg0 + 0x20)) = 16;
*(int *)(((long)arg0 + 0x24)) = 18;
*(int *)(((long)arg0 + 0x28)) = 20;
*(int *)(((long)arg0 + 0x2c)) = 22;
if (((unsigned long)((unsigned int)(var3)) != 12)) {
*(int *)(((long)arg0 + 0x30)) = 24;
*(int *)(((long)arg0 + 0x34)) = 26;
*(int *)(((long)arg0 + 0x38)) = 28;
*(int *)(((long)arg0 + 0x3c)) = 30;
}
}
}
var20 = var3;
if ((var3 == var0)) {
t2 = *(int *)(((long)arg0));
var21 = (arg1 + t2);
return (unsigned int)(var21);
}
L_1293: ;
var23 = (unsigned long)((unsigned int)((var20 + var20)));
index = var20;
do {
*(int *)(((long)arg0 + index * 4)) = var23;
index = (index + 1);
var23 = (unsigned long)((unsigned int)((var23 + 2)));
} while ((var0 != index));
} else {
var20 = 0;
goto L_1293;
}
}
t2 = *(int *)(((long)arg0));
var21 = (arg1 + t2);
return (unsigned int)(var21);
} pointer_to_const_walks pass 127 lines
// glaurung: pointer_to_const_walks @ 0x1100
int32_t pointer_to_const_walks(const int32_t * arg0, int32_t arg1) {
int total;
int index;
long ret;
long var10;
long var117;
long var119;
long var120;
long var122;
long var124;
long var125;
long var129;
long var13;
long var14;
int var16;
int var17;
int var18;
int var19;
long var2;
long var21;
long var4;
long var5;
long var7;
long var82;
int var83;
int var84;
int var85;
int var86;
int var89;
int var90;
int var91;
int var92;
long var93;
long var95;
ret = 0xffffffff;
if ((arg0 == 0)) {
return ret;
}
ret = 0xffffffff;
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return ret;
}
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
return 0;
}
var2 = (unsigned long)((unsigned int)((arg1 - 1)));
var4 = 0;
if (((unsigned long)(3) <= (unsigned long)((unsigned long)((unsigned int)(var2))))) {
var5 = (var2 + 1);
var4 = (var5 & -4);
var7 = (var4 - 4);
var10 = (((unsigned long)(var7) >> 2) + 1);
var13 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var10)) & 7)));
if (((unsigned long)(28) <= (unsigned long)(var7))) {
var14 = (var10 & -8);
var16 = 0;
var17 = 0;
var18 = 0;
var19 = 0;
var21 = 0;
do {
var16 = ((*(int *)(((long)arg0 + var21 * 4 + 0x70)) + *(int *)(((long)arg0 + var21 * 4 + 0x60))) + ((*(int *)(((long)arg0 + var21 * 4 + 0x50)) + (*(int *)(((long)arg0 + var21 * 4 + 0x40)) + *(int *)(((long)arg0 + var21 * 4 + 0x30)))) + ((*(int *)(((long)arg0 + var21 * 4 + 0x20)) + *(int *)(((long)arg0 + var21 * 4 + 0x10))) + (*(int *)(((long)arg0 + var21 * 4)) + var16))));
var17 = ((*(int *)(((long)arg0 + var21 * 4 + 0x74)) + *(int *)(((long)arg0 + var21 * 4 + 0x64))) + ((*(int *)(((long)arg0 + var21 * 4 + 0x54)) + (*(int *)(((long)arg0 + var21 * 4 + 0x44)) + *(int *)(((long)arg0 + var21 * 4 + 0x34)))) + ((*(int *)(((long)arg0 + var21 * 4 + 0x24)) + *(int *)(((long)arg0 + var21 * 4 + 0x14))) + (*(int *)(((long)arg0 + var21 * 4 + 0x4)) + var17))));
var18 = ((*(int *)(((long)arg0 + var21 * 4 + 0x78)) + *(int *)(((long)arg0 + var21 * 4 + 0x68))) + ((*(int *)(((long)arg0 + var21 * 4 + 0x58)) + (*(int *)(((long)arg0 + var21 * 4 + 0x48)) + *(int *)(((long)arg0 + var21 * 4 + 0x38)))) + ((*(int *)(((long)arg0 + var21 * 4 + 0x28)) + *(int *)(((long)arg0 + var21 * 4 + 0x18))) + (*(int *)(((long)arg0 + var21 * 4 + 0x8)) + var18))));
var19 = ((*(int *)(((long)arg0 + var21 * 4 + 0x7c)) + *(int *)(((long)arg0 + var21 * 4 + 0x6c))) + ((*(int *)(((long)arg0 + var21 * 4 + 0x5c)) + (*(int *)(((long)arg0 + var21 * 4 + 0x4c)) + *(int *)(((long)arg0 + var21 * 4 + 0x3c)))) + ((*(int *)(((long)arg0 + var21 * 4 + 0x2c)) + *(int *)(((long)arg0 + var21 * 4 + 0x1c))) + (*(int *)(((long)arg0 + var21 * 4 + 0xc)) + var19))));
ret = ((unsigned long)((unsigned int)(var17)) | (unsigned long)((unsigned int)(var16)));
var21 = (var21 + 32);
var14 = (var14 - 8);
var82 = var21;
var83 = var16;
var84 = var17;
var85 = var18;
var86 = var19;
} while ((var14 != 0));
} else {
var83 = 0;
var84 = 0;
var85 = 0;
var86 = 0;
var82 = 0;
}
var89 = var83;
var90 = var84;
var91 = var85;
var92 = var86;
if ((var13 != 0)) {
var93 = (long)(((long)arg0 + (var82 * 4)));
var13 = (var13 << 4);
var95 = 0;
do {
var83 = (var83 + *(int *)((var93 + var95)));
var84 = (var84 + *(int *)((var93 + var95 + 0x4)));
var85 = (var85 + *(int *)((var93 + var95 + 0x8)));
var86 = (var86 + *(int *)((var93 + var95 + 0xc)));
var95 = (var95 + 16);
var89 = var83;
var90 = var84;
var91 = var85;
var92 = var86;
} while ((var13 != var95));
}
var117 = (unsigned long)((unsigned int)(((var92 + var90) + (var91 + var89))));
ret = var117;
if ((var5 == var4)) {
return ret;
}
var119 = var117;
var120 = (long)(((long)arg0 + (var4 * 4)));
L_1211: ;
var122 = (unsigned long)((unsigned int)((arg1 - var4)));
var124 = 0;
var125 = var119;
do {
total = (var125 + *(int *)((var120 + var124 * 4)));
var125 = (unsigned long)((unsigned int)(total));
var124 = (var124 + 1);
ret = (unsigned long)((unsigned int)(total));
} while (((unsigned int)(var122) != (unsigned int)(var124)));
} else {
var119 = 0;
var13 = var129;
var120 = (long)arg0;
goto L_1211;
}
return ret;
} volatile_const_is_readable pass 5 lines
// glaurung: volatile_const_is_readable @ 0x12c0
int32_t volatile_const_is_readable(int32_t arg0) {
int total;
return (unsigned int)(((unsigned long)((unsigned int)(arg0)) + arg0));
} gcc -O2
3/3const_pointer_writes pass 29 lines
// glaurung: const_pointer_writes @ 0x1140
int32_t const_pointer_writes(const int32_t * arg0, int32_t arg1) {
int index;
long var0;
int var1;
long var2;
long zf_7;
if ((arg0 == 0)) {
return 0xffffffff;
}
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)(*(int *)(((long)arg0))));
var1 = (var0 + arg1);
return (unsigned int)(var1);
}
var2 = (unsigned long)((unsigned int)((arg1 - 1)));
index = 0;
do {
*(int *)(((long)arg0 + index * 4)) = (index + index);
zf_7 = (index == var2);
index = (index + 1);
} while ((zf_7 == 0));
var0 = (unsigned long)((unsigned int)(*(int *)(((long)arg0))));
var1 = (var0 + arg1);
return (unsigned int)(var1);
} pointer_to_const_walks pass 25 lines
// glaurung: pointer_to_const_walks @ 0x1100
int32_t pointer_to_const_walks(const int32_t * arg0, int32_t arg1) {
int * cursor;
int index;
int total;
long ret;
long var2;
if ((arg0 == 0)) {
return 0xffffffff;
}
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return 0xffffffff;
}
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
return 0;
}
var2 = (long)((((long)arg0 + ((unsigned long)((unsigned int)((arg1 - 1))) * 4)) + 4));
ret = 0;
cursor = (int *)arg0;
do {
ret = (unsigned long)((unsigned int)((ret + *(int *)((cursor)))));
cursor = (int *)((cursor + 1));
} while ((cursor != var2));
return ret;
} volatile_const_is_readable pass 7 lines
// glaurung: volatile_const_is_readable @ 0x1180
int32_t volatile_const_is_readable(int32_t arg0) {
int cell;
int total;
cell = arg0;
return (unsigned int)(((unsigned long)((unsigned int)(cell)) + (unsigned long)((unsigned int)(cell))));
}