Fixture 108
multidimensional arrays
C · 3 functions · 4 lanes · 4 of 12 function-lanes behave identically
4 of 4 lanes have a function that returns a different result after decompilation: clang-O0 (1/3), clang-O2 (1/3), gcc-O0 (1/3), gcc-O2 (1/3).
A true 2D array is one object with a compound stride; an array of pointers is two loads. The functions below are deliberately confusable at the source level and completely different in the binary.
#include <stdint.h>
/* A true 2D array is one object with a compound stride; an array of pointers is
* two loads. The functions below are deliberately confusable at the source
* level and completely different in the binary. */
#define GRID_ROWS 4
#define GRID_COLUMNS 4
__attribute__((noinline)) int32_t
sum_true_2d(const int32_t grid[GRID_ROWS][GRID_COLUMNS], int32_t rows) {
int32_t total = 0;
int32_t row;
int32_t column;
if (grid == 0 || rows < 0 || rows > GRID_ROWS) {
return -1;
}
for (row = 0; row < rows; ++row) {
for (column = 0; column < GRID_COLUMNS; ++column) {
total += grid[row][column];
}
}
return total;
}
__attribute__((noinline)) int32_t
sum_flat_with_stride(const int32_t *flat, int32_t rows, int32_t columns) {
int32_t total = 0;
int32_t row;
int32_t column;
if (flat == 0 || rows < 0 || rows > GRID_ROWS || columns < 0 ||
columns > GRID_COLUMNS) {
return -1;
}
for (row = 0; row < rows; ++row) {
for (column = 0; column < columns; ++column) {
total += flat[row * columns + column];
}
}
return total;
}
__attribute__((noinline)) int32_t
row_decay_span(const int32_t grid[GRID_ROWS][GRID_COLUMNS], int32_t row) {
const int32_t *decayed;
if (grid == 0 || row < 0 || row >= GRID_ROWS) {
return -1;
}
decayed = grid[row]; /* a row decays to int32_t*, not int32_t(*)[4] */
return decayed[0] + decayed[GRID_COLUMNS - 1];
} 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/3row_decay_span structural 25 lines
// glaurung: row_decay_span @ 0x1270
int32_t row_decay_span(char * arg0, int32_t arg1) {
int * decayed;
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 ((4 <= (long)(arg1))) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
decayed = (int *)(((long)arg0 + ((long)(arg1) << 4)));
local_4 = ((unsigned int)(*(int *)(decayed)) + *(int *)((decayed + 0xc)));
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} sum_flat_with_stride pass 44 lines
// glaurung: sum_flat_with_stride @ 0x11b0
int32_t sum_flat_with_stride(const int32_t * arg0, int32_t arg1, int32_t arg2) {
int total;
int row;
int column;
int local_4;
// x86-64 prologue: save rbp
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)) == 4) | ((long)(arg1) < 4)) == 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)) == 4) | ((long)(arg2) < 4)) == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
row = 0;
while ((row < arg1)) {
for (column = 0; (column < arg2); column++) {
total = ((unsigned int)(arg0[(long)((int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(row)) * arg2))) + column)))]) + total);
}
row = ((unsigned int)(row) + 1);
}
local_4 = total;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} sum_true_2d structural 34 lines
// glaurung: sum_true_2d @ 0x1100
int32_t sum_true_2d(char * arg0, int32_t arg1) {
int total;
int row;
int column;
int local_4;
// x86-64 prologue: save rbp
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)) == 4) | ((long)(arg1) < 4)) == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
row = 0;
while ((row < arg1)) {
for (column = 0; ((long)(column) < 4); column++) {
total = ((unsigned int)(*(int *)((((long)arg0 + ((long)(row) << 4)) + ((long)(column) * 4)))) + total);
}
row = ((unsigned int)(row) + 1);
}
local_4 = total;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} clang -O2
1/3row_decay_span structural 13 lines
// glaurung: row_decay_span @ 0x1290
int32_t row_decay_span(char * arg0, int32_t arg1) {
long ret;
long var1;
ret = 0xffffffff;
if ((arg0 != 0)) {
if (((unsigned long)((unsigned long)((unsigned int)(arg1))) <= (unsigned long)(3))) {
var1 = ((unsigned long)((unsigned int)(arg1)) << 4);
ret = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)(((long)arg0 + var1 + 0xc)))) + *(int *)(((long)arg0 + var1)))));
}
}
return ret;
} sum_flat_with_stride pass 110 lines
// glaurung: sum_flat_with_stride @ 0x11b0
int32_t sum_flat_with_stride(const int32_t * arg0, int32_t arg1, int32_t arg2) {
int total;
int column;
int row;
long ret;
long var10;
long var17;
long var23;
int var24;
int var26;
int var28;
long var29;
int var4;
long var5;
int var6;
long var7;
ret = 0xffffffff;
if (((unsigned long)((unsigned long)((unsigned int)(arg2))) <= (unsigned long)(4))) {
ret = 0xffffffff;
if ((arg0 == 0)) {
return ret;
}
ret = 0xffffffff;
if (((unsigned long)(4) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return ret;
}
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
return 0;
}
if (((unsigned long)((unsigned int)(arg2)) == 0)) {
ret = 0;
} else {
ret = (unsigned long)((unsigned int)(*(int *)(((long)arg0))));
if (((unsigned long)((unsigned int)(arg2)) != 1)) {
var4 = (ret + *(int *)(((long)arg0 + 0x4)));
var5 = (unsigned long)((unsigned int)(var4));
ret = (unsigned long)((unsigned int)(var4));
if (((unsigned long)((unsigned int)(arg2)) != 2)) {
var6 = (var5 + *(int *)(((long)arg0 + 0x8)));
var7 = (unsigned long)((unsigned int)(var6));
ret = (unsigned long)((unsigned int)(var6));
if (((unsigned long)((unsigned int)(arg2)) != 3)) {
ret = (unsigned long)((unsigned int)((var7 + *(int *)(((long)arg0 + 0xc)))));
}
}
}
}
if (((unsigned long)((unsigned int)(arg1)) == 1)) {
return ret;
}
var10 = (unsigned long)((unsigned int)(arg2));
total = ret;
if (((unsigned long)((unsigned int)(arg2)) != 0)) {
total = (unsigned long)((unsigned int)((ret + *(int *)(((long)arg0 + var10 * 4)))));
if (((unsigned long)((unsigned int)(arg2)) != 1)) {
total = (unsigned long)((unsigned int)((total + *(int *)(((long)arg0 + var10 * 4 + 0x4)))));
if (((unsigned long)((unsigned int)(arg2)) != 2)) {
total = (unsigned long)((unsigned int)((total + *(int *)(((long)arg0 + var10 * 4 + 0x8)))));
if (((unsigned long)((unsigned int)(arg2)) != 3)) {
total = (unsigned long)((unsigned int)((total + *(int *)(((long)arg0 + var10 * 4 + 0xc)))));
}
}
}
}
ret = (unsigned long)((unsigned int)(total));
if (((unsigned long)((unsigned int)(arg1)) == 2)) {
return ret;
}
if (((unsigned long)((unsigned int)(arg2)) != 0)) {
total = (unsigned long)((unsigned int)((total + *(int *)(((long)arg0 + var10 * 8)))));
if (((unsigned long)((unsigned int)(arg2)) != 1)) {
var17 = (var10 + var10);
total = (unsigned long)((unsigned int)((total + *(int *)(((long)arg0 + ((var17 * 4) | 4))))));
if (((unsigned long)((unsigned int)(arg2)) != 2)) {
total = (unsigned long)((unsigned int)((total + *(int *)(((long)arg0 + var17 * 4 + 0x8)))));
if (((unsigned long)((unsigned int)(arg2)) != 3)) {
total = (unsigned long)((unsigned int)((total + *(int *)(((long)arg0 + var17 * 4 + 0xc)))));
}
}
}
}
ret = (unsigned long)((unsigned int)(total));
if (((unsigned long)((unsigned int)(arg1)) == 3)) {
return ret;
}
ret = (unsigned long)((unsigned int)(total));
if (((unsigned long)((unsigned int)(arg2)) == 0)) {
return ret;
}
var23 = (var10 + (var10 * 2));
var24 = (total + *(int *)(((long)arg0 + var23 * 4)));
ret = (unsigned long)((unsigned int)(var24));
if (((unsigned long)((unsigned int)(arg2)) == 1)) {
return ret;
}
var26 = ((unsigned int)(var24) + *(int *)(((long)arg0 + var23 * 4 + 0x4)));
ret = (unsigned long)((unsigned int)(var26));
if (((unsigned long)((unsigned int)(arg2)) == 2)) {
return ret;
}
var28 = ((unsigned int)(var26) + *(int *)(((long)arg0 + var23 * 4 + 0x8)));
var29 = (unsigned long)((unsigned int)(var28));
ret = (unsigned long)((unsigned int)(var28));
if (((unsigned long)((unsigned int)(arg2)) != 3)) {
ret = (unsigned long)((unsigned int)((var29 + *(int *)(((long)arg0 + var23 * 4 + 0xc)))));
}
}
return ret;
} sum_true_2d structural 42 lines
// glaurung: sum_true_2d @ 0x1100
int32_t sum_true_2d(char * arg0, int32_t arg1) {
int column;
int row;
int total;
long ret;
int var31;
int var38;
int var53;
int var60;
int var75;
int var82;
ret = 0xffffffff;
if ((arg0 != 0)) {
ret = 0xffffffff;
if (((unsigned long)(4) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return ret;
}
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
return 0;
}
ret = (unsigned long)((unsigned int)(((*(int *)(((long)arg0 + 0xc)) + *(int *)(((long)arg0 + 0x4))) + (*(int *)(((long)arg0 + 0x8)) + *(int *)(((long)arg0))))));
if (((unsigned long)((unsigned int)(arg1)) == 1)) {
return ret;
}
var31 = (*(int *)(((long)arg0 + 0x1c)) + *(int *)(((long)arg0 + 0x14)));
var38 = (var31 + (*(int *)(((long)arg0 + 0x18)) + *(int *)(((long)arg0 + 0x10))));
ret = (unsigned long)((unsigned int)((((var31 + var31) | var38) + (unsigned long)((unsigned int)(var38)))));
if (((unsigned long)((unsigned int)(arg1)) == 2)) {
return ret;
}
var53 = (*(int *)(((long)arg0 + 0x2c)) + *(int *)(((long)arg0 + 0x24)));
var60 = (var53 + (*(int *)(((long)arg0 + 0x28)) + *(int *)(((long)arg0 + 0x20))));
ret = (unsigned long)((unsigned int)((((var53 + var53) | var60) + (unsigned long)((unsigned int)(var60)))));
if (((unsigned long)((unsigned int)(arg1)) != 3)) {
var75 = (*(int *)(((long)arg0 + 0x3c)) + *(int *)(((long)arg0 + 0x34)));
var82 = (var75 + (*(int *)(((long)arg0 + 0x38)) + *(int *)(((long)arg0 + 0x30))));
ret = (unsigned long)((unsigned int)((((var75 + var75) | var82) + (unsigned long)((unsigned int)(var82)))));
}
}
return ret;
} gcc -O0
1/3row_decay_span structural 20 lines
// glaurung: row_decay_span @ 0x1206
int32_t row_decay_span(char * arg0, int32_t arg1) {
int * decayed;
// 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)) == 3) | ((long)(arg1) < 3)) == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
decayed = (int *)(((long)arg0 + ((long)(arg1) << 4)));
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned long)((unsigned int)(*(int *)((decayed + 3)))) + (unsigned long)((unsigned int)(*(int *)(decayed)))));
} sum_flat_with_stride pass 37 lines
// glaurung: sum_flat_with_stride @ 0x1174
int32_t sum_flat_with_stride(const int32_t * arg0, int32_t arg1, int32_t arg2) {
int total;
int row;
int column;
// x86-64 prologue: save rbp
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)) == 4) | ((long)(arg1) < 4)) == 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)) == 4) | ((long)(arg2) < 4)) == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
row = 0;
while ((row < arg1)) {
for (column = 0; (column < arg2); column++) {
total = (total + (unsigned int)(arg0[(long)((int)(((unsigned long)((unsigned int)(column)) + (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(row)) * arg2))))))]));
}
row = (row + 1);
}
// x86-64 epilogue: restore rbp
return (unsigned int)(total);
} sum_true_2d structural 29 lines
// glaurung: sum_true_2d @ 0x10f9
int32_t sum_true_2d(char * arg0, int32_t arg1) {
int total;
int row;
int column;
// x86-64 prologue: save rbp
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)) == 4) | ((long)(arg1) < 4)) == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
row = 0;
while ((row < arg1)) {
for (column = 0; ((((unsigned long)((unsigned int)(column)) == 3) | ((long)(column) < 3)) != 0); column++) {
total = (total + (unsigned int)(*(int *)(((((long)(row) << 4) + (long)arg0) + ((long)(column) * 4)))));
}
row = (row + 1);
}
// x86-64 epilogue: restore rbp
return (unsigned int)(total);
} gcc -O2
1/3row_decay_span structural 11 lines
// glaurung: row_decay_span @ 0x11c0
int32_t row_decay_span(char * arg0, int32_t arg1) {
long var2;
if ((arg0 != 0)) {
if (((unsigned long)((unsigned long)((unsigned int)(arg1))) <= (unsigned long)(3))) {
var2 = (long)(((long)arg0 + ((long)(arg1) << 4)));
return (unsigned int)(((unsigned long)((unsigned int)(*(int *)((var2 + 0xc)))) + *(int *)((var2))));
}
}
return 0xffffffff;
} sum_flat_with_stride pass 60 lines
// glaurung: sum_flat_with_stride @ 0x1150
int32_t sum_flat_with_stride(const int32_t * arg0, int32_t arg1, int32_t arg2) {
int total;
int column;
int row;
long var0;
long var10;
long var11;
long var12;
long var13;
long var15;
long var17;
long var18;
long var2;
int var20;
long var4;
long var9;
if ((arg0 == 0)) {
var0 = 0xffffffff;
return 0xffffffff;
}
if (((unsigned long)(4) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
var0 = 0xffffffff;
return 0xffffffff;
}
if (((unsigned long)(4) < (unsigned long)((unsigned long)((unsigned int)(arg2))))) {
var0 = 0xffffffff;
return 0xffffffff;
}
var0 = 0;
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
return (unsigned int)(var0);
}
var2 = (long)arg0;
var4 = 0;
var9 = (unsigned long)((unsigned int)((arg2 - 1)));
var10 = (long)((arg0 + 1));
var11 = 0;
var12 = 0;
do {
var13 = var11;
if (((unsigned long)((unsigned int)(arg2)) != 0)) {
var15 = (var2 + ((long)((int)(var4)) * 4));
var17 = (var10 + (((long)((int)(var4)) + var9) * 4));
var18 = var11;
do {
total = (var18 + *(int *)((var15)));
var18 = (unsigned long)((unsigned int)(total));
var15 = (var15 + 4);
var13 = (unsigned long)((unsigned int)(total));
} while ((var15 != var17));
}
var20 = (var12 + 1);
var4 = (unsigned long)((unsigned int)((var4 + arg2)));
var11 = var13;
var12 = (unsigned long)((unsigned int)(var20));
} while (((unsigned int)(arg1) != (unsigned int)(var20)));
// x86-64 epilogue: tear down frame
return (unsigned int)(var13);
} sum_true_2d structural 32 lines
// glaurung: sum_true_2d @ 0x1100
int32_t sum_true_2d(char * arg0, int32_t arg1) {
int column;
int row;
int total;
long ret;
int var14;
long var3;
long var6;
long var7;
int var8;
if ((arg0 == 0)) {
return 0xffffffff;
}
if (((unsigned long)(4) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return 0xffffffff;
}
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
return 0;
}
var3 = (long)((((long)arg0 + ((unsigned long)((unsigned int)((arg1 - 1))) << 4)) + 16));
var6 = 0;
var7 = (long)arg0;
do {
var8 = (var6 + *(int *)((var7)));
var7 = (var7 + 16);
var14 = ((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var8)) + *(int *)((var7 - 0xc))))) + *(int *)((var7 - 0x8)))) + *(int *)((var7 - 0x4)));
ret = (unsigned long)((unsigned int)(var14));
var6 = (unsigned long)((unsigned int)(var14));
} while ((var7 != var3));
return ret;
}