Fixture 61

fixed point

C · 4 functions · 4 lanes · 16 of 16 function-lanes behave identically

All 4 lanes recompile and return the same results as the original.

Q16.16 fixed-point primitives. The harness executes integer signatures only, so the whole numeric half of this corpus is built on these: a multiply that rounds through a 64-bit intermediate, a divide that shifts before dividing, and an integer square root by digit-by-digit restoration.

tests/decompiler_fixtures/src/61_fixed_point.c source
#include <stdint.h>

/* Q16.16 fixed-point primitives.  The harness executes integer signatures
 * only, so the whole numeric half of this corpus is built on these: a multiply
 * that rounds through a 64-bit intermediate, a divide that shifts before
 * dividing, and an integer square root by digit-by-digit restoration. */

#define Q16_ONE 65536
#define Q16_LIMIT 1073741824

__attribute__((noinline)) int32_t fixed_multiply(int32_t left, int32_t right) {
    int64_t product = (int64_t)left * (int64_t)right;
    return (int32_t)(product >> 16);
}

__attribute__((noinline)) int32_t fixed_divide(int32_t numerator,
                                               int32_t denominator) {
    int64_t scaled;
    if (denominator == 0) {
        return 0;
    }
    scaled = ((int64_t)numerator << 16) / (int64_t)denominator;
    if (scaled > 2147483647LL) {
        return 2147483647;
    }
    if (scaled < -2147483648LL) {
        return -2147483647 - 1;
    }
    return (int32_t)scaled;
}

__attribute__((noinline)) int32_t fixed_sqrt(int32_t value) {
    uint64_t remainder;
    uint64_t root = 0;
    uint64_t bit = 1ULL << 46;
    if (value < 0) {
        return -1;
    }
    remainder = (uint64_t)value << 16;
    while (bit > remainder) {
        bit >>= 2;
    }
    while (bit != 0u) {
        if (remainder >= root + bit) {
            remainder -= root + bit;
            root = (root >> 1) + bit;
        } else {
            root >>= 1;
        }
        bit >>= 2;
    }
    return (int32_t)root;
}

__attribute__((noinline)) int32_t fixed_lerp(int32_t from, int32_t to,
                                             int32_t alpha) {
    int64_t span;
    if (alpha < 0) {
        alpha = 0;
    }
    if (alpha > Q16_ONE) {
        alpha = Q16_ONE;
    }
    span = ((int64_t)(to - from) * (int64_t)alpha) >> 16;
    return (int32_t)((int64_t)from + span);
}

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

4/4
fixed_divide pass 21 lines
// glaurung: fixed_divide @ 0x1130
int32_t fixed_divide(int32_t arg0, int32_t arg1) {
    long scaled;
    long var1;
    // x86-64 prologue: save rbp
    if (((unsigned long)((unsigned int)(arg1)) != 0)) {
        var1 = ((long)(arg0) << 16);
        scaled = ((long)((((__int128)(long)(((long)(var1) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(var1)) / (long)((long)(arg1))));
        if ((scaled <= 0x7fffffff)) {
            if ((-0x80000000LL <= scaled)) {
                return (unsigned int)(scaled);
            } else {
                return (unsigned int)(-0x80000000LL);
            }
        } else {
            return 0x7fffffff;
        }
    } else {
        return 0;
    }
}
fixed_lerp pass 16 lines
// glaurung: fixed_lerp @ 0x1290
int32_t fixed_lerp(int32_t arg0, int32_t arg1, int32_t arg2) {
    long span;
    int local_c;
    // x86-64 prologue: save rbp
    local_c = arg2;
    if (((long)(local_c) < 0)) {
        local_c = 0;
    }
    if (((((unsigned long)((unsigned int)(local_c)) == 0x10000) | ((long)(local_c) < 0x10000)) == 0)) {
        local_c = 0x10000;
    }
    span = ((long)(((long)((int)(((unsigned long)((unsigned int)(arg1)) - arg0))) * (long)(local_c))) >> 16);
    // x86-64 epilogue: restore rbp
    return ((long)(arg0) + span);
}
fixed_multiply pass 8 lines
// glaurung: fixed_multiply @ 0x1100
int32_t fixed_multiply(int32_t arg0, int32_t arg1) {
    long product;
    // x86-64 prologue: save rbp
    product = ((long)(arg0) * (long)(arg1));
    // x86-64 epilogue: restore rbp
    return ((long)(product) >> 16);
}
fixed_sqrt pass 27 lines
// glaurung: fixed_sqrt @ 0x11b0
int32_t fixed_sqrt(int32_t arg0) {
    unsigned long root;
    unsigned long bit;
    unsigned long remainder;
    // x86-64 prologue: save rbp
    root = 0;
    bit = 0x400000000000;
    if ((0 <= (long)(arg0))) {
        remainder = ((long)(arg0) << 16);
        while (((unsigned long)(remainder) < (unsigned long)(bit))) {
            bit = ((unsigned long)(bit) >> 2);
        }
        while ((bit != 0)) {
            if (((unsigned long)(remainder) < (unsigned long)((root + bit)))) {
                root = ((unsigned long)(root) >> 1);
            } else {
                remainder = (remainder - (root + bit));
                root = (((unsigned long)(root) >> 1) + bit);
            }
            bit = ((unsigned long)(bit) >> 2);
        }
        return (unsigned int)(root);
    } else {
        return (unsigned int)(-1);
    }
}

clang -O2

4/4
fixed_divide pass 16 lines
// glaurung: fixed_divide @ 0x1110
int32_t fixed_divide(int32_t arg0, int32_t arg1) {
    long scaled;
    int var15;
    long var2;
    if (((unsigned long)((unsigned int)(arg1)) == 0)) {
        return 0;
    }
    var2 = ((long)(arg0) << 16);
    scaled = ((((unsigned long)((var2 | (long)(arg1))) >> 32) == 0) ? ((unsigned int)(((((unsigned long long)(unsigned int)((unsigned long)((unsigned int)(0))) << 32) | (unsigned int)(var2)) / (unsigned int)(arg1)))) : ((long)((((__int128)(long)(((long)(var2) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(var2)) / (long)((long)(arg1)))));
    var15 = 0x7fffffff;
    if ((scaled <= 0x7fffffff)) {
        var15 = ((-0x7fffffffLL <= scaled) ? scaled : 0x80000000);
    }
    return (unsigned int)(var15);
}
fixed_lerp pass 6 lines
// glaurung: fixed_lerp @ 0x11e0
int32_t fixed_lerp(int32_t arg0, int32_t arg1, int32_t arg2) {
    int var2;
    var2 = ((0 <= (long)(arg2)) ? arg2 : 0);
    return (unsigned int)((((unsigned long)(((((unsigned long)((unsigned long)((unsigned int)(var2))) < (unsigned long)(0x10000)) ? var2 : 0x10000) * (long)((int)((arg1 - arg0))))) >> 16) + arg0));
}
fixed_multiply pass 5 lines
// glaurung: fixed_multiply @ 0x1100
int32_t fixed_multiply(int32_t arg0, int32_t arg1) {
    long product;
    return ((unsigned long)(((long)(arg1) * (long)(arg0))) >> 16);
}
fixed_sqrt pass 42 lines
// glaurung: fixed_sqrt @ 0x1160
int32_t fixed_sqrt(int32_t arg0) {
    unsigned long bit;
    unsigned long remainder;
    unsigned long root;
    long ret;
    long t134;
    long var1;
    long var11;
    long var13;
    long var14;
    long var19;
    long var3;
    long var7;
    if (((long)(arg0) < 0)) {
        return 0xffffffff;
    }
    var1 = ((unsigned long)((unsigned int)(arg0)) << 16);
    var3 = 0x400000000000;
    do {
        bit = var3;
        var3 = ((unsigned long)(var3) >> 2);
    } while (((unsigned long)(var1) < (unsigned long)(bit)));
    if ((bit == 0)) {
        return 0;
    }
    var7 = 0;
    var11 = 0;
    remainder = var1;
    var13 = bit;
    do {
        var14 = (bit + var11);
        var19 = (((unsigned long)(remainder) < (unsigned long)(var14)) ? var7 : bit);
        remainder = (remainder - (((unsigned long)(remainder) < (unsigned long)(var14)) ? var7 : var14));
        ret = (var19 + ((unsigned long)(var11) >> 1));
        var13 = ((unsigned long)(var13) >> 2);
        t134 = ((unsigned long)(bit) <= (unsigned long)(3));
        var11 = ret;
        bit = var13;
    } while ((t134 == 0));
    return ret;
}

gcc -O0

4/4
fixed_divide pass 21 lines
// glaurung: fixed_divide @ 0x1124
int32_t fixed_divide(int32_t arg0, int32_t arg1) {
    long scaled;
    long var2;
    // x86-64 prologue: save rbp
    if (((unsigned long)((unsigned int)(arg1)) != 0)) {
        var2 = ((long)(arg0) << 16);
        scaled = ((long)((((__int128)(long)(((long)(var2) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(var2)) / (long)((long)((int)((unsigned long)((unsigned int)(arg1)))))));
        if ((scaled < 0x80000000)) {
            if ((-0x80000001LL < scaled)) {
                return scaled;
            } else {
                return 0x80000000;
            }
        } else {
            return 0x7fffffff;
        }
    } else {
        return 0;
    }
}
fixed_lerp pass 16 lines
// glaurung: fixed_lerp @ 0x1221
int32_t fixed_lerp(int32_t arg0, int32_t arg1, int32_t arg2) {
    long span;
    int local_1c;
    // x86-64 prologue: save rbp
    local_1c = arg2;
    if (((long)(local_1c) < 0)) {
        local_1c = 0;
    }
    if (((((unsigned long)((unsigned int)(local_1c)) == 0x10000) | ((long)(local_1c) < 0x10000)) == 0)) {
        local_1c = 0x10000;
    }
    span = ((long)(((long)(local_1c) * (long)((int)(((unsigned long)((unsigned int)(arg1)) - arg0))))) >> 16);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(arg0)) + (unsigned long)((unsigned int)(span))));
}
fixed_multiply pass 8 lines
// glaurung: fixed_multiply @ 0x10f9
int32_t fixed_multiply(int32_t arg0, int32_t arg1) {
    long product;
    // x86-64 prologue: save rbp
    product = ((long)(arg1) * (long)(arg0));
    // x86-64 epilogue: restore rbp
    return ((long)(product) >> 16);
}
fixed_sqrt pass 27 lines
// glaurung: fixed_sqrt @ 0x1186
int32_t fixed_sqrt(int32_t arg0) {
    unsigned long root;
    unsigned long bit;
    unsigned long remainder;
    // x86-64 prologue: save rbp
    root = 0;
    bit = 0x400000000000;
    if ((0 <= (long)(arg0))) {
        remainder = ((long)(arg0) << 16);
        while (((unsigned long)(remainder) < (unsigned long)(bit))) {
            bit = ((unsigned long)(bit) >> 2);
        }
        while ((bit != 0)) {
            if (((unsigned long)(remainder) < (unsigned long)((bit + root)))) {
                root = ((unsigned long)(root) >> 1);
            } else {
                remainder = (remainder - (bit + root));
                root = (bit + ((unsigned long)(root) >> 1));
            }
            bit = ((unsigned long)(bit) >> 2);
        }
        return root;
    } else {
        return 0xffffffff;
    }
}

gcc -O2

4/4
fixed_divide pass 16 lines
// glaurung: fixed_divide @ 0x1120
int32_t fixed_divide(int32_t arg0, int32_t arg1) {
    long scaled;
    long var2;
    long var6;
    var2 = 0;
    if (((unsigned long)((unsigned int)(arg1)) != 0)) {
        var6 = ((long)(arg0) << 16);
        scaled = ((long)((((__int128)(long)(((long)(var6) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(var6)) / (long)((long)(arg1))));
        var2 = 0x7fffffff;
        if ((scaled <= 0x7fffffff)) {
            var2 = ((-0x80000000LL <= scaled) ? scaled : 0x80000000);
        }
    }
    return (unsigned int)(var2);
}
fixed_lerp pass 6 lines
// glaurung: fixed_lerp @ 0x11d0
int32_t fixed_lerp(int32_t arg0, int32_t arg1, int32_t arg2) {
    long var1;
    var1 = (((((unsigned long)((unsigned int)(arg2)) == 0x10000) | ((long)(arg2) < 0x10000)) == 0) ? 0x10000 : arg2);
    return (unsigned int)((arg0 + ((long)(((long)((int)((((long)((int)(var1)) < 0) ? 0 : var1))) * (long)((int)((arg1 - arg0))))) >> 16)));
}
fixed_multiply pass 5 lines
// glaurung: fixed_multiply @ 0x1100
int32_t fixed_multiply(int32_t arg0, int32_t arg1) {
    long product;
    return ((long)(((long)(arg0) * (long)(arg1))) >> 16);
}
fixed_sqrt pass 37 lines
// glaurung: fixed_sqrt @ 0x1160
int32_t fixed_sqrt(int32_t arg0) {
    unsigned long remainder;
    unsigned long bit;
    unsigned long root;
    long var0;
    long var8;
    long var9;
    if (((long)(arg0) < 0)) {
        return 0xffffffff;
    }
    var0 = 0x400000000000;
    remainder = ((long)(arg0) << 16);
    if ((((unsigned long)(remainder) >> 46) == 0)) {
        bit = var0;
        do {
            bit = ((unsigned long)(bit) >> 2);
        } while (((unsigned long)(remainder) < (unsigned long)(bit)));
        var0 = bit;
        if ((bit == 0)) {
            return 0;
        }
    }
    root = 0;
    do {
        var8 = (root + var0);
        root = (root >> 1);
        var9 = remainder;
        if (((unsigned long)(var8) <= (unsigned long)(remainder))) {
            var9 = (remainder - var8);
            root = (root + var0);
        }
        var0 = ((unsigned long)(var0) >> 2);
        remainder = var9;
    } while ((var0 != 0));
    return root;
}

← 213 fixtures