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.

tests/decompiler_fixtures/src/118_bit_tricks.c source
#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/6
clear_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/6
clear_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/6
clear_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/6
clear_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;
}

← 213 fixtures