Fixture 118
bit tricks
C · 6 functions · 4 lanes · 24 of 24 function-lanes behave identically
All 4 lanes recompile and return the same results as the original.
Textbook bit manipulations. Each has a recognizable closed form, so a recovered version that merely "looks similar" fails the differential on the first boundary value.
#include <stdint.h>
/* Textbook bit manipulations. Each has a recognizable closed form, so a
* recovered version that merely "looks similar" fails the differential on the
* first boundary value. */
__attribute__((noinline)) uint32_t isolate_lowest_set(uint32_t value) {
return value & (0u - value);
}
__attribute__((noinline)) uint32_t clear_lowest_set(uint32_t value) {
return value & (value - 1u);
}
__attribute__((noinline)) int32_t is_power_of_two(uint32_t value) {
return value != 0u && (value & (value - 1u)) == 0u;
}
__attribute__((noinline)) uint32_t round_up_to_power_of_two(uint32_t value) {
if (value == 0u) {
return 1u;
}
value -= 1u;
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
return value + 1u;
}
__attribute__((noinline)) int32_t
xor_swap(int32_t *left, int32_t *right) {
if (left == 0 || right == 0 || left == right) {
return -1;
}
*left ^= *right;
*right ^= *left;
*left ^= *right;
return *left - *right;
}
__attribute__((noinline)) int32_t
sign_without_branch(int32_t value) {
return (value > 0) - (value < 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
6/6clear_lowest_set pass 6 lines
// glaurung: clear_lowest_set @ 0x1120
uint32_t clear_lowest_set(uint32_t arg0) {
// x86-64 prologue: save rbp
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned long)(arg0) & (unsigned long)((unsigned int)(((unsigned long)(arg0) - 1)))));
} is_power_of_two pass 11 lines
// glaurung: is_power_of_two @ 0x1140
int32_t is_power_of_two(uint32_t arg0) {
signed char local_5;
// x86-64 prologue: save rbp
local_5 = 0;
if ((arg0 != 0)) {
local_5 = ((unsigned long)((unsigned int)((arg0 & (unsigned long)((unsigned int)((arg0 - 1)))))) == 0);
}
// x86-64 epilogue: restore rbp
return (unsigned int)((unsigned char)((local_5 & 1)));
} isolate_lowest_set pass 6 lines
// glaurung: isolate_lowest_set @ 0x1100
uint32_t isolate_lowest_set(uint32_t arg0) {
// x86-64 prologue: save rbp
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned long)(arg0) & (unsigned long)((unsigned int)((0 - arg0)))));
} round_up_to_power_of_two pass 15 lines
// glaurung: round_up_to_power_of_two @ 0x1180
uint32_t round_up_to_power_of_two(uint32_t arg0) {
// x86-64 prologue: save rbp
if ((arg0 != 0)) {
arg0 = (arg0 - 1);
arg0 = ((unsigned int)(((unsigned int)(arg0) >> 1)) | arg0);
arg0 = ((unsigned int)(((unsigned int)(arg0) >> 2)) | arg0);
arg0 = ((unsigned int)(((unsigned int)(arg0) >> 4)) | arg0);
arg0 = ((unsigned int)(((unsigned int)(arg0) >> 8)) | arg0);
arg0 = ((unsigned int)(((unsigned int)(arg0) >> 16)) | arg0);
return (unsigned int)(((unsigned long)(arg0) + 1));
} else {
return 1;
}
} sign_without_branch pass 6 lines
// glaurung: sign_without_branch @ 0x1270
int32_t sign_without_branch(int32_t arg0) {
// x86-64 prologue: save rbp
// x86-64 epilogue: restore rbp
return (unsigned int)((((((unsigned long)((unsigned int)(arg0)) == 0) | ((long)(arg0) < 0)) == 0) - ((long)(arg0) < 0)));
} xor_swap pass 26 lines
// glaurung: xor_swap @ 0x11f0
int32_t xor_swap(int32_t * arg0, int32_t * arg1) {
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)arg0 == (long)arg1)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
*(int *)((long)arg0) = ((unsigned long)((unsigned int)(*(int *)((long)arg1))) ^ *(int *)((long)arg0));
*(int *)((long)arg1) = ((unsigned long)((unsigned int)(*(int *)((long)arg0))) ^ *(int *)((long)arg1));
*(int *)((long)arg0) = ((unsigned long)((unsigned int)(*(int *)((long)arg1))) ^ *(int *)((long)arg0));
local_4 = ((unsigned int)(*(int *)((long)arg0)) - *(int *)((long)arg1));
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} clang -O2
6/6clear_lowest_set pass 4 lines
// glaurung: clear_lowest_set @ 0x1110
uint32_t clear_lowest_set(uint32_t arg0) {
return (unsigned int)(((unsigned long)((unsigned int)((arg0 - 1))) & arg0));
} is_power_of_two pass 7 lines
// glaurung: is_power_of_two @ 0x1120
int32_t is_power_of_two(uint32_t arg0) {
if ((arg0 == 0)) {
return 0;
}
return ((unsigned long)((unsigned int)((arg0 & (unsigned long)((unsigned int)((arg0 - 1)))))) == 0);
} isolate_lowest_set pass 4 lines
// glaurung: isolate_lowest_set @ 0x1100
uint32_t isolate_lowest_set(uint32_t arg0) {
return (unsigned int)(((-(unsigned long)(arg0)) & arg0));
} round_up_to_power_of_two pass 17 lines
// glaurung: round_up_to_power_of_two @ 0x1140
uint32_t round_up_to_power_of_two(uint32_t arg0) {
int var0;
long var13;
long var19;
long var25;
long var7;
if ((arg0 == 0)) {
return 1;
}
var0 = (arg0 - 1);
var7 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var0)) >> 1))) | (unsigned long)((unsigned int)(var0)))));
var13 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var7)) >> 2))) | var7)));
var19 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var13)) >> 4))) | var13)));
var25 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var19)) >> 8))) | var19)));
return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var25)) >> 16))) | var25))) + 1));
} sign_without_branch pass 4 lines
// glaurung: sign_without_branch @ 0x11b0
int32_t sign_without_branch(int32_t arg0) {
return (unsigned int)((((((unsigned long)((unsigned int)(arg0)) == 0) | ((long)(arg0) < 0)) == 0) + (unsigned long)((unsigned int)(((int)(arg0) >> 31)))));
} xor_swap pass 23 lines
// glaurung: xor_swap @ 0x1180
int32_t xor_swap(int32_t * arg0, int32_t * arg1) {
long ret;
long var2;
long var4;
long var6;
ret = 0xffffffff;
if (((long)arg0 != (long)arg1)) {
if ((arg0 == 0)) {
return ret;
}
if ((arg1 != 0)) {
var2 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)(((long)arg0)))) ^ *(int *)(((long)arg1)))));
*(int *)(((long)arg0)) = var2;
var4 = (unsigned long)((unsigned int)((var2 ^ *(int *)(((long)arg1)))));
*(int *)(((long)arg1)) = var4;
var6 = (unsigned long)((unsigned int)((var4 ^ *(int *)(((long)arg0)))));
*(int *)(((long)arg0)) = var6;
ret = (unsigned long)((unsigned int)((var6 - *(int *)(((long)arg1)))));
}
}
return ret;
} gcc -O0
6/6clear_lowest_set pass 6 lines
// glaurung: clear_lowest_set @ 0x110e
uint32_t clear_lowest_set(uint32_t arg0) {
// x86-64 prologue: save rbp
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) - 1))) & arg0));
} is_power_of_two pass 14 lines
// glaurung: is_power_of_two @ 0x1124
int32_t is_power_of_two(uint32_t arg0) {
// x86-64 prologue: save rbp
if ((arg0 == 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)((arg0 - 1))) & arg0))) != 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
// x86-64 epilogue: restore rbp
return 1;
} isolate_lowest_set pass 6 lines
// glaurung: isolate_lowest_set @ 0x10f9
uint32_t isolate_lowest_set(uint32_t arg0) {
// x86-64 prologue: save rbp
// x86-64 epilogue: restore rbp
return (unsigned int)(((-(unsigned long)(arg0)) & arg0));
} round_up_to_power_of_two pass 15 lines
// glaurung: round_up_to_power_of_two @ 0x1150
uint32_t round_up_to_power_of_two(uint32_t arg0) {
// x86-64 prologue: save rbp
if ((arg0 != 0)) {
arg0 = (arg0 - 1);
arg0 = (arg0 | (unsigned int)(((unsigned int)(arg0) >> 1)));
arg0 = (arg0 | (unsigned int)(((unsigned int)(arg0) >> 2)));
arg0 = (arg0 | (unsigned int)(((unsigned int)(arg0) >> 4)));
arg0 = (arg0 | (unsigned int)(((unsigned int)(arg0) >> 8)));
arg0 = (arg0 | (unsigned int)(((unsigned int)(arg0) >> 16)));
return (unsigned int)(((unsigned long)(arg0) + 1));
} else {
return 1;
}
} sign_without_branch pass 6 lines
// glaurung: sign_without_branch @ 0x121d
int32_t sign_without_branch(int32_t arg0) {
// x86-64 prologue: save rbp
// x86-64 epilogue: restore rbp
return (unsigned int)((((((unsigned long)((unsigned int)(arg0)) == 0) | ((long)(arg0) < 0)) == 0) - (unsigned int)((unsigned char)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) >> 31))) & 255)))));
} xor_swap pass 21 lines
// glaurung: xor_swap @ 0x11a0
int32_t xor_swap(int32_t * arg0, int32_t * arg1) {
// 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)arg0 == (long)arg1)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
*(int *)((long)arg0) = ((unsigned long)((unsigned int)(*(int *)((long)arg0))) ^ (unsigned long)((unsigned int)(*(int *)((long)arg1))));
*(int *)((long)arg1) = ((unsigned long)((unsigned int)(*(int *)((long)arg1))) ^ (unsigned long)((unsigned int)(*(int *)((long)arg0))));
*(int *)((long)arg0) = ((unsigned long)((unsigned int)(*(int *)((long)arg0))) ^ (unsigned long)((unsigned int)(*(int *)((long)arg1))));
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned long)((unsigned int)(*(int *)((long)arg0))) - (unsigned long)((unsigned int)(*(int *)((long)arg1)))));
} gcc -O2
6/6clear_lowest_set pass 4 lines
// glaurung: clear_lowest_set @ 0x1110
uint32_t clear_lowest_set(uint32_t arg0) {
return (unsigned int)(((unsigned long)((unsigned int)((arg0 - 1))) & arg0));
} is_power_of_two pass 9 lines
// glaurung: is_power_of_two @ 0x1120
int32_t is_power_of_two(uint32_t arg0) {
long ret;
ret = 0;
if ((arg0 != 0)) {
ret = ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)((arg0 - 1))) & arg0))) == 0);
}
return ret;
} isolate_lowest_set pass 4 lines
// glaurung: isolate_lowest_set @ 0x1100
uint32_t isolate_lowest_set(uint32_t arg0) {
return (unsigned int)(((-(unsigned long)(arg0)) & arg0));
} round_up_to_power_of_two pass 19 lines
// glaurung: round_up_to_power_of_two @ 0x1140
uint32_t round_up_to_power_of_two(uint32_t arg0) {
long ret;
long var1;
long var13;
long var19;
long var25;
long var7;
ret = 1;
if ((arg0 != 0)) {
var1 = (unsigned long)((unsigned int)((arg0 - 1)));
var7 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var1)) >> 1))) | var1)));
var13 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var7)) >> 2))) | var7)));
var19 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var13)) >> 4))) | var13)));
var25 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var19)) >> 8))) | var19)));
ret = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var25)) >> 16))) | var25))) + 1)));
}
return ret;
} sign_without_branch pass 4 lines
// glaurung: sign_without_branch @ 0x11c0
int32_t sign_without_branch(int32_t arg0) {
return (unsigned int)((((((unsigned long)((unsigned int)(arg0)) == 0) | ((long)(arg0) < 0)) == 0) - (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) >> 31)))));
} xor_swap pass 18 lines
// glaurung: xor_swap @ 0x1180
int32_t xor_swap(int32_t * arg0, int32_t * arg1) {
long var10;
long var12;
long var8;
if (((arg0 != 0) && ((long)arg0 != (long)arg1))) {
if ((arg1 != 0)) {
var8 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)(((long)arg0)))) ^ *(int *)(((long)arg1)))));
*(int *)(((long)arg0)) = var8;
var10 = (unsigned long)((unsigned int)((var8 ^ *(int *)(((long)arg1)))));
*(int *)(((long)arg1)) = var10;
var12 = (unsigned long)((unsigned int)((var10 ^ *(int *)(((long)arg0)))));
*(int *)(((long)arg0)) = var12;
return (unsigned int)((var12 - *(int *)(((long)arg1))));
}
}
return 0xffffffff;
}