Fixture 174

float compare classify

C · 7 functions · 4 lanes · 15 of 28 function-lanes behave identically

4 of 4 lanes have a function that returns a different result after decompilation: clang-O2 (1/7), gcc-O0 (4/7), gcc-O2 (4/7), clang-O0 (6/7).

Floating-point comparison and classification.

Two things here are invisible to an integer corpus. First, a float compare has FOUR outcomes, not three: <, >, == and UNORDERED, the last of which makes every one of the first three false at once. On x86 that is the parity flag, and a recovery that lowers ucomiss as if it were cmp produces code that is right on ordered inputs and wrong on unordered ones. Second, zero has a sign: -0.0 == 0.0 is true while their bit patterns differ, so a recovery that folds one into the other is invisible to a value comparison and caught immediately by a bitwise one.

The NaN is BUILT FROM ITS BIT PATTERN rather than by dividing zero by zero. A bit pattern is exact and unconditionally defined; 0.0/0.0 is defined only through Annex F, and a fixture should not depend on an annex to be free of undefined behaviour. Its payload is taken from the input so the value is not a compile-time constant and the comparison is really performed.

tests/decompiler_fixtures/src/174_float_compare_classify.c source
#include <stdint.h>
#include <string.h>

/* Floating-point comparison and classification.
 *
 * Two things here are invisible to an integer corpus.  First, a float compare
 * has FOUR outcomes, not three: `<`, `>`, `==` and UNORDERED, the last of which
 * makes every one of the first three false at once.  On x86 that is the parity
 * flag, and a recovery that lowers `ucomiss` as if it were `cmp` produces code
 * that is right on ordered inputs and wrong on unordered ones.  Second, zero
 * has a sign: `-0.0 == 0.0` is true while their bit patterns differ, so a
 * recovery that folds one into the other is invisible to a value comparison and
 * caught immediately by a bitwise one.
 *
 * The NaN is BUILT FROM ITS BIT PATTERN rather than by dividing zero by zero.
 * A bit pattern is exact and unconditionally defined; `0.0/0.0` is defined only
 * through Annex F, and a fixture should not depend on an annex to be free of
 * undefined behaviour.  Its payload is taken from the input so the value is not
 * a compile-time constant and the comparison is really performed. */

#define FP174_QUIET_NAN_BITS 0x7FC00000u
#define FP174_SIGN_MASK 0x80000000u
#define FP174_EXPONENT_MASK 0x7F800000u
#define FP174_MANTISSA_MASK 0x007FFFFFu

/* Class codes returned by `classify_binary32`. */
#define FP174_CLASS_ZERO 0
#define FP174_CLASS_SUBNORMAL 1
#define FP174_CLASS_NORMAL 2
#define FP174_CLASS_INFINITE 3
#define FP174_CLASS_NAN 4

_Static_assert(sizeof(float) == sizeof(uint32_t), "binary32 is four bytes");

/* `memcpy` rather than a union or a cast: it is the one spelling that is
 * defined regardless of the aliasing rules the optimiser is applying, and both
 * compilers turn a four-byte copy into a single register move. */
static uint32_t fp174_float_bits(float value) {
    uint32_t bits;
    memcpy(&bits, &value, sizeof bits);
    return bits;
}

static float fp174_bits_to_float(uint32_t bits) {
    float value;
    memcpy(&value, &bits, sizeof value);
    return value;
}

/* -1 / 0 / 1 as usual, and 2 for the fourth outcome an integer compare does not
 * have.  Reachable only when an operand is a NaN, which arithmetic inside a
 * caller can produce from finite inputs. */
__attribute__((noinline)) int32_t ordered_compare_binary32(float left,
                                                           float right) {
    if (left < right) {
        return -1;
    }
    if (left > right) {
        return 1;
    }
    if (left == right) {
        return 0;
    }
    return 2;
}

/* Every relational operator against a quiet NaN, as a bitmask.  The answer is
 * always 8 (`!=` alone is true), so any other value from either side is a
 * mis-lowered unordered compare rather than a disagreement about arithmetic. */
__attribute__((noinline)) int32_t unordered_compare_flags(float value) {
    uint32_t payload = fp174_float_bits(value) & FP174_MANTISSA_MASK;
    float nan_value = fp174_bits_to_float(FP174_QUIET_NAN_BITS | payload);
    int32_t flags = 0;
    if (value < nan_value) {
        flags |= 1;
    }
    if (value > nan_value) {
        flags |= 2;
    }
    if (value == nan_value) {
        flags |= 4;
    }
    if (value != nan_value) {
        flags |= 8;
    }
    if (value <= nan_value) {
        flags |= 16;
    }
    if (value >= nan_value) {
        flags |= 32;
    }
    return flags;
}

/* The sign bit itself, which is the only way to tell -0.0 from 0.0. */
__attribute__((noinline)) int32_t sign_bit_of_binary32(float value) {
    return (int32_t)((fp174_float_bits(value) & FP174_SIGN_MASK) >> 31);
}

/* Negation is a sign-bit flip, not a subtraction from zero: `-(0.0f)` is
 * `-0.0f`, while `0.0f - 0.0f` is `+0.0f`.  The bit-exact return comparison is
 * what makes the difference observable. */
__attribute__((noinline)) float negate_binary32(float value) {
    return -value;
}

__attribute__((noinline)) float absolute_binary32(float value) {
    return fp174_bits_to_float(fp174_float_bits(value) & ~FP174_SIGN_MASK);
}

__attribute__((noinline)) int32_t classify_binary32(float value) {
    uint32_t bits = fp174_float_bits(value);
    uint32_t exponent = bits & FP174_EXPONENT_MASK;
    uint32_t mantissa = bits & FP174_MANTISSA_MASK;
    if (exponent == FP174_EXPONENT_MASK) {
        return (mantissa != 0u) ? FP174_CLASS_NAN : FP174_CLASS_INFINITE;
    }
    if (exponent == 0u) {
        return (mantissa != 0u) ? FP174_CLASS_SUBNORMAL : FP174_CLASS_ZERO;
    }
    return FP174_CLASS_NORMAL;
}

/* A signed zero the harness cannot hand in directly: multiplying by zero keeps
 * the operand's sign, so a negative input yields -0.0 and a positive one +0.0,
 * and the two are `==` but not identical.  An infinite input yields a NaN
 * instead, which the guard rejects with -1. */
__attribute__((noinline)) int32_t zero_sign_from_product(float value) {
    float product = value * 0.0f;
    if (!(product == 0.0f)) {
        return -1;
    }
    return (fp174_float_bits(product) == fp174_float_bits(0.0f)) ? 0 : 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 -O2

1/7
absolute_binary32 fail 5 lines
// glaurung: absolute_binary32 @ 0x11b0
float absolute_binary32(float arg0) {
    long var2;
    return ((union { unsigned int bits; float value; }){ .bits = (unsigned int)(((var2 & 0x7fffffff) | (arg0 & 0x7fffffff))) }).value;
}
classify_binary32 pass 18 lines
// glaurung: classify_binary32 @ 0x11c0
int32_t classify_binary32(float arg0) {
    unsigned int bits;
    unsigned int exponent;
    long ret;
    long var0;
    int var2;
    var0 = (unsigned long)((unsigned int)(((union { unsigned int bits; float value; }){ .value = arg0 }).bits));
    var2 = ((unsigned int)(((union { unsigned int bits; float value; }){ .value = arg0 }).bits) & 0x7f800000);
    if (((unsigned long)((unsigned int)(var2)) == 0)) {
        return ((unsigned long)((unsigned int)((var0 & 0x7fffff))) != 0);
    }
    ret = 2;
    if (((unsigned long)((unsigned int)(var2)) != 0x7f800000)) {
        return ret;
    }
    return (unsigned int)((4 - ((unsigned long)((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((union { unsigned int bits; float value; }){ .value = arg0 }).bits)) & 0x7fffff)))) < (unsigned long)(1))));
}
negate_binary32 fail 5 lines
// glaurung: negate_binary32 @ 0x11a0
float negate_binary32(float arg0) {
    long var2;
    return ((union { unsigned int bits; float value; }){ .bits = (unsigned int)(((var2 ^ 0x80000000) | (arg0 ^ 0x80000000))) }).value;
}
ordered_compare_binary32 fail 16 lines
// glaurung: ordered_compare_binary32 @ 0x1100
int32_t ordered_compare_binary32(float arg0, float arg1) {
    long ret;
    long var1;
    long var3;
    ret = 0xffffffff;
    if (((((arg1 < arg0) | ((arg1 != arg1) | (arg0 != arg0))) | ((arg1 == arg0) | ((arg1 != arg1) | (arg0 != arg0)))) != 0)) {
        ret = 1;
        if (((((arg0 < arg1) | ((arg0 != arg0) | (arg1 != arg1))) | ((arg0 == arg1) | ((arg0 != arg0) | (arg1 != arg1)))) != 0)) {
            /* asm: cmpss */
            var3 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var1)) & 1)));
            ret = (unsigned long)((unsigned int)((var3 + var3)));
        }
    }
    return ret;
}
sign_bit_of_binary32 fail 7 lines
// glaurung: sign_bit_of_binary32 @ 0x1190
int32_t sign_bit_of_binary32(float arg0) {
    long var3;
    long var5;
    long var7;
    return (unsigned int)((((((arg0 < 0) | ((var3 < 0) << 1)) | ((var5 < 0) << 2)) | ((var7 < 0) << 3)) & 1));
}
unordered_compare_flags fail 19 lines
// glaurung: unordered_compare_flags @ 0x1130
int32_t unordered_compare_flags(float arg0) {
    int flags;
    float nan_value;
    long var1;
    long var10;
    long var14;
    long var18;
    int var23;
    var10 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var1)) & 0x3fffff))) | 0x7fc00000)));
    flags = ((((var10 < arg0) | ((var10 != var10) | (arg0 != arg0))) | ((var10 == arg0) | ((var10 != var10) | (arg0 != arg0)))) == 0);
    var14 = ((((arg0 < var10) | ((arg0 != arg0) | (var10 != var10))) | ((arg0 == var10) | ((arg0 != arg0) | (var10 != var10)))) ? flags : (unsigned long)((unsigned int)((flags + 2))));
    flags = (((var10 != var10) | (arg0 != arg0)) ? var14 : ((((var10 == arg0) | ((var10 != var10) | (arg0 != arg0))) == 0) ? var14 : (unsigned long)((unsigned int)((var14 + 4)))));
    var18 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(flags)) | 8)));
    flags = (((var10 != var10) | (arg0 != arg0)) ? var18 : ((((var10 == arg0) | ((var10 != var10) | (arg0 != arg0))) == 0) ? var18 : flags));
    var23 = (((var10 < arg0) | ((var10 != var10) | (arg0 != arg0))) ? flags : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(flags)) | 16))));
    flags = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var23)) | 32)));
    return (((arg0 < var10) | ((arg0 != arg0) | (var10 != var10))) ? var23 : flags);
}
zero_sign_from_product fail 5 lines
// glaurung: zero_sign_from_product @ 0x1200
int32_t zero_sign_from_product(float arg0) {
    float product;
    return 0;
}

gcc -O0

4/7
absolute_binary32 fail 12 lines
// glaurung: absolute_binary32 @ 0x12ec
float absolute_binary32(float arg0) {
    extern float fp174_bits_to_float(unsigned int);
    extern unsigned int fp174_float_bits(float);
    float ret;
    unsigned int var5;
    // x86-64 prologue: save rbp, frame 16 bytes
    var5 = fp174_float_bits(arg0);
    ret = fp174_bits_to_float((unsigned long)((unsigned int)((var5 & 0x7fffffff))));
    // x86-64 epilogue: restore rbp
    return ret;
}
classify_binary32 pass 26 lines
// glaurung: classify_binary32 @ 0x1317
int32_t classify_binary32(float arg0) {
    extern unsigned int fp174_float_bits(float);
    unsigned int bits;
    unsigned int exponent;
    unsigned int mantissa;
    unsigned int var5;
    // x86-64 prologue: save rbp, frame 32 bytes
    var5 = fp174_float_bits(arg0);
    bits = var5;
    exponent = (bits & 0x7f800000);
    mantissa = (bits & 0x7fffff);
    if ((exponent != 0x7f800000)) {
        if ((exponent != 0)) {
            return 2;
        } else {
            return ((unsigned long)(mantissa) != 0);
        }
    } else {
        if ((mantissa == 0)) {
            return 3;
        } else {
            return 4;
        }
    }
}
negate_binary32 pass 7 lines
// glaurung: negate_binary32 @ 0x12cd
float negate_binary32(float arg0) {
    // x86-64 prologue: save rbp
    arg0 = ((union { unsigned int bits; float value; }){ .bits = (unsigned int)(((unsigned int)(((union { unsigned int bits; float value; }){ .value = arg0 }).bits) ^ 0x80000000)) }).value;
    // x86-64 epilogue: restore rbp
    return arg0;
}
ordered_compare_binary32 pass 21 lines
// glaurung: ordered_compare_binary32 @ 0x1197
int32_t ordered_compare_binary32(float arg0, float arg1) {
    // x86-64 prologue: save rbp
    if ((((arg1 < arg0) | ((arg1 != arg1) | (arg0 != arg0))) | ((arg1 == arg0) | ((arg1 != arg1) | (arg0 != arg0))))) {
        if ((((arg0 < arg1) | ((arg0 != arg0) | (arg1 != arg1))) | ((arg0 == arg1) | ((arg0 != arg0) | (arg1 != arg1))))) {
            if (((arg0 != arg0) | (arg1 != arg1))) {
                // x86-64 epilogue: restore rbp
                return 2;
            }
            if ((((arg0 == arg1) | ((arg0 != arg0) | (arg1 != arg1))) == 0)) {
                // x86-64 epilogue: restore rbp
                return 2;
            }
            return 0;
        } else {
            return 1;
        }
    } else {
        return 0xffffffff;
    }
}
sign_bit_of_binary32 pass 9 lines
// glaurung: sign_bit_of_binary32 @ 0x12a8
int32_t sign_bit_of_binary32(float arg0) {
    extern unsigned int fp174_float_bits(float);
    unsigned int var5;
    // x86-64 prologue: save rbp, frame 16 bytes
    var5 = fp174_float_bits(arg0);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var5)) >> 31))) & 1));
}
unordered_compare_flags fail 45 lines
// glaurung: unordered_compare_flags @ 0x11f1
int32_t unordered_compare_flags(float arg0) {
    extern float fp174_bits_to_float(unsigned int);
    extern unsigned int fp174_float_bits(float);
    unsigned int payload;
    float nan_value;
    int flags;
    float var12;
    unsigned int var5;
    // x86-64 prologue: save rbp, frame 32 bytes
    var5 = fp174_float_bits(arg0);
    payload = (var5 & 0x7fffff);
    var12 = fp174_bits_to_float((unsigned long)((unsigned int)((payload | 0x7fc00000))));
    nan_value = var12;
    flags = 0;
    if (((((nan_value < arg0) | ((nan_value != nan_value) | (arg0 != arg0))) | ((nan_value == arg0) | ((nan_value != nan_value) | (arg0 != arg0)))) == 0)) {
        flags = (flags | 1);
    }
    if (((((arg0 < nan_value) | ((arg0 != arg0) | (nan_value != nan_value))) | ((arg0 == nan_value) | ((arg0 != arg0) | (nan_value != nan_value)))) == 0)) {
        flags = (flags | 2);
    }
    if ((((arg0 != arg0) | (nan_value != nan_value)) == 0)) {
        if ((((arg0 == nan_value) | ((arg0 != arg0) | (nan_value != nan_value))) != 0)) {
            flags = (flags | 4);
        }
    }
    if (((arg0 != arg0) | (nan_value != nan_value))) {
        L_1281: ;
        flags = (flags | 8);
    } else {
        if (((arg0 == nan_value) | ((arg0 != arg0) | (nan_value != nan_value)))) {
            goto L_1285;
        }
        goto L_1281;
    }
    L_1285: ;
    if ((((nan_value < arg0) | ((nan_value != nan_value) | (arg0 != arg0))) == 0)) {
        flags = (flags | 16);
    }
    if ((((arg0 < nan_value) | ((arg0 != arg0) | (nan_value != nan_value))) == 0)) {
        flags = (flags | 32);
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(flags);
}
zero_sign_from_product fail 23 lines
// glaurung: zero_sign_from_product @ 0x1383
int32_t zero_sign_from_product(float arg0) {
    extern unsigned int fp174_float_bits(float);
    float product;
    unsigned int var28;
    long var30;
    unsigned int var36;
    // x86-64 prologue: save rbp, frame 8 bytes
    product = ((union { unsigned int bits; float value; }){ .bits = (unsigned int)(0) }).value;
    if ((product != product)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if ((((0 == product) | (product != product)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    var28 = fp174_float_bits((float)(((union { unsigned int bits; float value; }){ .bits = (unsigned int)((unsigned long)((unsigned int)(((union { unsigned int bits; float value; }){ .value = product }).bits))) }).value));
    var30 = (unsigned long)(var28);
    var36 = fp174_float_bits((float)(((union { unsigned int bits; float value; }){ .bits = (unsigned int)(0) }).value));
    // x86-64 epilogue: restore rbp
    return ((unsigned int)(var30) != (unsigned int)(var36));
}

gcc -O2

4/7
absolute_binary32 pass 4 lines
// glaurung: absolute_binary32 @ 0x11b0
float absolute_binary32(float arg0) {
    return ((union { unsigned int bits; float value; }){ .bits = (unsigned int)((unsigned int)(((unsigned long)((unsigned int)(((union { unsigned int bits; float value; }){ .value = arg0 }).bits)) & 0x7fffffff))) }).value;
}
classify_binary32 pass 15 lines
// glaurung: classify_binary32 @ 0x11d0
int32_t classify_binary32(float arg0) {
    unsigned int exponent;
    unsigned int mantissa;
    unsigned int bits;
    exponent = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((union { unsigned int bits; float value; }){ .value = arg0 }).bits)) & 0x7f800000)));
    mantissa = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((union { unsigned int bits; float value; }){ .value = arg0 }).bits)) & 0x7fffff)));
    if ((exponent == 0x7f800000)) {
        return (unsigned int)((4 - ((unsigned long)((unsigned long)(mantissa)) < (unsigned long)(1))));
    }
    if ((exponent == 0)) {
        return ((unsigned long)(mantissa) != 0);
    }
    return 2;
}
negate_binary32 fail 5 lines
// glaurung: negate_binary32 @ 0x11a0
float negate_binary32(float arg0) {
    long var2;
    return ((union { unsigned int bits; float value; }){ .bits = (unsigned int)((var2 | (arg0 ^ 0x80000000))) }).value;
}
ordered_compare_binary32 pass 14 lines
// glaurung: ordered_compare_binary32 @ 0x1100
int32_t ordered_compare_binary32(float arg0, float arg1) {
    long ret;
    int var4;
    if (((((arg1 < arg0) | ((arg1 != arg1) | (arg0 != arg0))) | ((arg1 == arg0) | ((arg1 != arg1) | (arg0 != arg0)))) == 0)) {
        return 0xffffffff;
    }
    ret = 1;
    if (((((arg0 < arg1) | ((arg0 != arg0) | (arg1 != arg1))) | ((arg0 == arg1) | ((arg0 != arg0) | (arg1 != arg1)))) == 0)) {
        return ret;
    }
    var4 = (((arg0 == arg1) | ((arg0 != arg0) | (arg1 != arg1))) ? (((arg0 != arg0) | (arg1 != arg1)) & 255) : 1);
    return (unsigned int)((var4 + var4));
}
sign_bit_of_binary32 pass 4 lines
// glaurung: sign_bit_of_binary32 @ 0x1190
int32_t sign_bit_of_binary32(float arg0) {
    return (unsigned int)(((unsigned long)((unsigned int)(((union { unsigned int bits; float value; }){ .value = arg0 }).bits)) >> 31));
}
unordered_compare_flags fail 47 lines
// glaurung: unordered_compare_flags @ 0x1130
int32_t unordered_compare_flags(float arg0) {
    int flags;
    float nan_value;
    unsigned int payload;
    int local_4;
    long var1;
    long var10;
    long var14;
    long zf_10;
    local_4 = var1;
    var10 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)((0x7fffff & local_4))) | 0x7fc00000)));
    flags = ((((var10 < arg0) | ((var10 != var10) | (arg0 != arg0))) | ((var10 == arg0) | ((var10 != var10) | (arg0 != arg0)))) == 0);
    if ((((arg0 < var10) | ((arg0 != arg0) | (var10 != var10))) | ((arg0 == var10) | ((arg0 != arg0) | (var10 != var10))))) {
        goto L_1168;
    }
    flags = (unsigned long)((unsigned int)((flags | 10)));
    var14 = flags;
    if ((((var10 < arg0) | ((var10 != var10) | (arg0 != arg0))) == 0)) {
        goto L_1172;
    }
    L_1161: ;
    return (unsigned int)((flags | 32));
    L_1168: ;
    zf_10 = ((arg0 == var10) | ((arg0 != arg0) | (var10 != var10)));
    if (((arg0 != arg0) | (var10 != var10))) {
        goto L_117b;
    }
    if ((zf_10 == 0)) {
        goto L_117b;
    }
    var14 = (unsigned long)((unsigned int)((flags | 4)));
    L_1172: ;
    flags = (unsigned long)((unsigned int)((var14 | 16)));
    L_1175: ;
    if ((((arg0 < var10) | ((arg0 != arg0) | (var10 != var10))) == 0)) {
        goto L_1161;
    }
    return flags;
    L_117b: ;
    flags = (unsigned long)((unsigned int)((flags | 8)));
    if (((var10 < arg0) | ((var10 != var10) | (arg0 != arg0)))) {
        goto L_1175;
    }
    var14 = flags;
    goto L_1172;
}
zero_sign_from_product fail 13 lines
// glaurung: zero_sign_from_product @ 0x1230
int32_t zero_sign_from_product(float arg0) {
    float product;
    int var6;
    var6 = 0;
    if (0) {
        return 0xffffffff;
    }
    if (1) {
        return ((unsigned long)((unsigned int)(var6)) != 0);
    }
    return 0xffffffff;
}

clang -O0

6/7
absolute_binary32 pass 12 lines
// glaurung: absolute_binary32 @ 0x1300
float absolute_binary32(float arg0) {
    extern float fp174_bits_to_float(unsigned int);
    extern unsigned int fp174_float_bits(float);
    unsigned int var5;
    float var9;
    // x86-64 prologue: save rbp, frame 16 bytes
    var5 = fp174_float_bits(arg0);
    var9 = fp174_bits_to_float((unsigned long)((unsigned int)((var5 & 0x7fffffff))));
    // x86-64 epilogue: restore rbp
    return var9;
}
classify_binary32 pass 22 lines
// glaurung: classify_binary32 @ 0x1330
int32_t classify_binary32(float arg0) {
    extern unsigned int fp174_float_bits(float);
    unsigned int bits;
    unsigned int exponent;
    unsigned int mantissa;
    unsigned int var5;
    // x86-64 prologue: save rbp, frame 32 bytes
    var5 = fp174_float_bits(arg0);
    bits = var5;
    exponent = (bits & 0x7f800000);
    mantissa = (bits & 0x7fffff);
    if ((exponent != 0x7f800000)) {
        if ((exponent != 0)) {
            return 2;
        } else {
            return (unsigned int)(((unsigned long)(mantissa) != 0) ? 1 : 0);
        }
    } else {
        return (unsigned int)(((unsigned long)(mantissa) != 0) ? 4 : 3);
    }
}
negate_binary32 pass 6 lines
// glaurung: negate_binary32 @ 0x12e0
float negate_binary32(float arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return ((union { unsigned int bits; float value; }){ .bits = (unsigned int)((unsigned int)(((unsigned long)((unsigned int)(((union { unsigned int bits; float value; }){ .value = arg0 }).bits)) ^ -0x80000000LL))) }).value;
}
ordered_compare_binary32 pass 23 lines
// glaurung: ordered_compare_binary32 @ 0x1100
int32_t ordered_compare_binary32(float arg0, float arg1) {
    long pf_3;
    // x86-64 prologue: save rbp
    if ((((arg1 < arg0) | ((arg1 != arg1) | (arg0 != arg0))) | ((arg1 == arg0) | ((arg1 != arg1) | (arg0 != arg0))))) {
        if ((((arg0 < arg1) | ((arg0 != arg0) | (arg1 != arg1))) | ((arg0 == arg1) | ((arg0 != arg0) | (arg1 != arg1))))) {
            pf_3 = ((arg0 != arg0) | (arg1 != arg1));
            if ((((arg0 == arg1) | ((arg0 != arg0) | (arg1 != arg1))) == 0)) {
                // x86-64 epilogue: restore rbp
                return 2;
            }
            if (pf_3) {
                // x86-64 epilogue: restore rbp
                return 2;
            }
            return 0;
        } else {
            return 1;
        }
    } else {
        return (unsigned int)(-1);
    }
}
sign_bit_of_binary32 pass 9 lines
// glaurung: sign_bit_of_binary32 @ 0x12b0
int32_t sign_bit_of_binary32(float arg0) {
    extern unsigned int fp174_float_bits(float);
    unsigned int var5;
    // x86-64 prologue: save rbp, frame 16 bytes
    var5 = fp174_float_bits(arg0);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)((var5 & -0x80000000LL))) >> 31));
}
unordered_compare_flags pass 41 lines
// glaurung: unordered_compare_flags @ 0x1180
int32_t unordered_compare_flags(float arg0) {
    extern float fp174_bits_to_float(unsigned int);
    extern unsigned int fp174_float_bits(float);
    unsigned int payload;
    float nan_value;
    int flags;
    long pf_10;
    float var11;
    unsigned int var5;
    // x86-64 prologue: save rbp, frame 16 bytes
    var5 = fp174_float_bits(arg0);
    payload = (var5 & 0x7fffff);
    var11 = fp174_bits_to_float((unsigned long)((unsigned int)((payload | 0x7fc00000))));
    nan_value = var11;
    flags = 0;
    if (((((nan_value < arg0) | ((nan_value != nan_value) | (arg0 != arg0))) | ((nan_value == arg0) | ((nan_value != nan_value) | (arg0 != arg0)))) == 0)) {
        flags = ((unsigned int)(flags) | 1);
    }
    if (((((arg0 < nan_value) | ((arg0 != arg0) | (nan_value != nan_value))) | ((arg0 == nan_value) | ((arg0 != arg0) | (nan_value != nan_value)))) == 0)) {
        flags = ((unsigned int)(flags) | 2);
    }
    pf_10 = ((arg0 != arg0) | (nan_value != nan_value));
    if ((((arg0 == nan_value) | ((arg0 != arg0) | (nan_value != nan_value))) != 0)) {
        if ((pf_10 == 0)) {
            flags = ((unsigned int)(flags) | 4);
        }
    }
    if (((((arg0 == nan_value) | ((arg0 != arg0) | (nan_value != nan_value))) == 0) || ((arg0 != arg0) | (nan_value != nan_value)))) {
        flags = ((unsigned int)(flags) | 8);
    } else {
    }
    if ((((nan_value < arg0) | ((nan_value != nan_value) | (arg0 != arg0))) == 0)) {
        flags = ((unsigned int)(flags) | 16);
    }
    if ((((arg0 < nan_value) | ((arg0 != arg0) | (nan_value != nan_value))) == 0)) {
        flags = ((unsigned int)(flags) | 32);
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(flags);
}
zero_sign_from_product fail 28 lines
// glaurung: zero_sign_from_product @ 0x13c0
int32_t zero_sign_from_product(float arg0) {
    extern unsigned int fp174_float_bits(float);
    float product;
    int local_10;
    int local_4;
    long pf_2;
    unsigned int var22;
    unsigned int var28;
    // x86-64 prologue: save rbp, frame 16 bytes
    product = ((union { unsigned int bits; float value; }){ .bits = (unsigned int)(0) }).value;
    pf_2 = (product != product);
    if ((((product == 0) | (product != product)) == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (pf_2) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    var22 = fp174_float_bits(product);
    local_10 = var22;
    var28 = fp174_float_bits((float)(((union { unsigned int bits; float value; }){ .bits = (unsigned int)(0) }).value));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned int)(local_10) == (unsigned int)(var28)) ? 0 : 1);
}

← 213 fixtures