Fixture 83

ternary chains

C · 3 functions · 4 lanes · 12 of 12 function-lanes behave identically

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

Nested conditional expressions. The conditional operator is right-associative and yields an lvalue-free result whose type is the usual arithmetic conversion of both arms, so an incorrectly widened arm changes the answer.

tests/decompiler_fixtures/src/83_ternary_chains.c source
#include <stdint.h>

/* Nested conditional expressions. The conditional operator is right-associative
 * and yields an lvalue-free result whose type is the usual arithmetic
 * conversion of both arms, so an incorrectly widened arm changes the answer. */

__attribute__((noinline)) int32_t
classify_ladder(int32_t value) {
    return value < -100  ? -3
           : value < -10 ? -2
           : value < 0   ? -1
           : value == 0  ? 0
           : value < 10  ? 1
           : value < 100 ? 2
                         : 3;
}

__attribute__((noinline)) uint32_t
ternary_mixed_types(int32_t selector, int32_t signed_arm, uint32_t unsigned_arm) {
    /* Both arms convert to unsigned int: the signed arm is converted, not the
     * other way round. A negative signed_arm therefore wraps. */
    return selector ? (uint32_t)signed_arm : unsigned_arm;
}

__attribute__((noinline)) int32_t
nested_ternary_assignment(int32_t a, int32_t b, int32_t c, int32_t *out) {
    int32_t result;
    if (out == 0) {
        return -1;
    }
    result = (a > b) ? ((b > c) ? a - c : ((a > c) ? a - b : c - a))
                     : ((a > c) ? b - c : ((b > c) ? b - a : c - b));
    *out = result;
    return (a > b) + (b > c) + (a > c);
}

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

3/3
classify_ladder pass 25 lines
// glaurung: classify_ladder @ 0x1100
int32_t classify_ladder(int32_t arg0) {
    int local_10;
    int local_14;
    // x86-64 prologue: save rbp
    if ((-100 <= (long)(arg0))) {
        if ((-10 <= (long)(arg0))) {
            if ((0 <= (long)(arg0))) {
                if (((unsigned long)((unsigned int)(arg0)) != 0)) {
                    local_14 = ((10 <= (long)(arg0)) ? (((long)(arg0) < 100) ? 2 : 3) : 1);
                } else {
                    local_14 = 0;
                }
                local_10 = local_14;
            } else {
                local_10 = 0xffffffff;
            }
            return (unsigned int)(local_10);
        } else {
            return 0xfffffffe;
        }
    } else {
        return 0xfffffffd;
    }
}
nested_ternary_assignment pass 34 lines
// glaurung: nested_ternary_assignment @ 0x11e0
int32_t nested_ternary_assignment(int32_t arg0, int32_t arg1, int32_t arg2, int32_t * arg3) {
    int result;
    int local_20;
    int local_24;
    int local_28;
    int local_2c;
    int local_30;
    // x86-64 prologue: save rbp
    if ((arg3 != 0)) {
        if ((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1))) {
            if ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2))) {
                local_30 = ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) ? ((unsigned long)((unsigned int)(arg2)) - (unsigned long)((unsigned int)(arg1))) : ((unsigned long)((unsigned int)(arg1)) - (unsigned long)((unsigned int)(arg0))));
                local_2c = local_30;
            } else {
                local_2c = ((unsigned int)(arg1) - arg2);
            }
            local_28 = local_2c;
        } else {
            if ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2))) {
                local_24 = ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) ? ((unsigned long)((unsigned int)(arg2)) - (unsigned long)((unsigned int)(arg0))) : ((unsigned long)((unsigned int)(arg0)) - (unsigned long)((unsigned int)(arg1))));
                local_20 = local_24;
            } else {
                local_20 = ((unsigned int)(arg0) - arg2);
            }
            local_28 = local_20;
        }
        result = local_28;
        *(int *)((long)arg3) = result;
        return (unsigned int)(((unsigned long)((unsigned int)((((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) == 0) + ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) == 0)))) + ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) == 0)));
    } else {
        return (unsigned int)(-1);
    }
}
ternary_mixed_types pass 9 lines
// glaurung: ternary_mixed_types @ 0x11b0
uint32_t ternary_mixed_types(int32_t arg0, int32_t arg1, uint32_t arg2) {
    // x86-64 prologue: save rbp
    if (((unsigned long)((unsigned int)(arg0)) == 0)) {
        return arg2;
    } else {
        return (unsigned int)(arg1);
    }
}

clang -O2

3/3
classify_ladder pass 22 lines
// glaurung: classify_ladder @ 0x1100
int32_t classify_ladder(int32_t arg0) {
    long ret;
    ret = 0xfffffffd;
    if ((-100 <= (long)(arg0))) {
        ret = 0xfffffffe;
        if (((long)(arg0) < -10)) {
            return ret;
        }
        if (((long)(arg0) < 0)) {
            return 0xffffffff;
        }
        if (((unsigned long)((unsigned int)(arg0)) == 0)) {
            return 0;
        }
        ret = 1;
        if (((unsigned long)(10) <= (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
            return (unsigned int)((3 - ((unsigned long)((unsigned long)((unsigned int)(arg0))) < (unsigned long)(100))));
        }
    }
    return ret;
}
nested_ternary_assignment pass 25 lines
// glaurung: nested_ternary_assignment @ 0x1150
int32_t nested_ternary_assignment(int32_t arg0, int32_t arg1, int32_t arg2, int32_t * arg3) {
    int result;
    int var1;
    long var2;
    if ((arg3 == 0)) {
        return 0xffffffff;
    }
    var1 = ((unsigned int)(arg0) - arg1);
    var2 = (unsigned long)((unsigned int)(var1));
    if ((((unsigned long)((unsigned int)(var1)) == 0) | (arg0 < arg1))) {
        result = ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) ? ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) ? (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) - arg1))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) - arg0)))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) - arg2))));
    } else {
        if ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2))) {
            result = var2;
            if (((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) != 0)) {
                result = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) - arg0)));
            }
        } else {
            result = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - arg2)));
        }
    }
    *(int *)(((long)arg3)) = result;
    return (unsigned int)((((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) == 0) + (unsigned long)((unsigned int)((((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) == 0) + ((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) == 0))))));
}
ternary_mixed_types pass 4 lines
// glaurung: ternary_mixed_types @ 0x1140
uint32_t ternary_mixed_types(int32_t arg0, int32_t arg1, uint32_t arg2) {
    return (((unsigned long)((unsigned int)(arg0)) == 0) ? arg2 : (unsigned long)((unsigned int)(arg1)));
}

gcc -O0

3/3
classify_ladder pass 29 lines
// glaurung: classify_ladder @ 0x10f9
int32_t classify_ladder(int32_t arg0) {
    // x86-64 prologue: save rbp
    if (((long)(arg0) < -100)) {
        return 0xfffffffd;
    } else {
        if (((long)(arg0) < -10)) {
            return 0xfffffffe;
        } else {
            if (((long)(arg0) < 0)) {
                return 0xffffffff;
            } else {
                if (((unsigned long)((unsigned int)(arg0)) == 0)) {
                    return 0;
                } else {
                    if ((((unsigned long)((unsigned int)(arg0)) == 9) | ((long)(arg0) < 9))) {
                        return 1;
                    } else {
                        if (((((unsigned long)((unsigned int)(arg0)) == 99) | ((long)(arg0) < 99)) == 0)) {
                            return 3;
                        } else {
                            return 2;
                        }
                    }
                }
            }
        }
    }
}
nested_ternary_assignment pass 12 lines
// glaurung: nested_ternary_assignment @ 0x117a
int32_t nested_ternary_assignment(int32_t arg0, int32_t arg1, int32_t arg2, int32_t * arg3) {
    int result;
    // x86-64 prologue: save rbp
    if ((arg3 != 0)) {
        result = ((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) ? ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) ? ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) ? (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) - arg1))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) - arg0)))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) - arg2)))) : ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) ? ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) ? (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) - arg0))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - arg1)))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - arg2)))));
        *(int *)((long)arg3) = result;
        return (unsigned int)((((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) == 0) + (unsigned long)((unsigned int)((((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) == 0) + ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) == 0))))));
    } else {
        return 0xffffffff;
    }
}
ternary_mixed_types pass 9 lines
// glaurung: ternary_mixed_types @ 0x1159
uint32_t ternary_mixed_types(int32_t arg0, int32_t arg1, uint32_t arg2) {
    // x86-64 prologue: save rbp
    if (((unsigned long)((unsigned int)(arg0)) == 0)) {
        return arg2;
    } else {
        return (unsigned int)(arg1);
    }
}

gcc -O2

3/3
classify_ladder pass 22 lines
// glaurung: classify_ladder @ 0x1100
int32_t classify_ladder(int32_t arg0) {
    long ret;
    if (((long)(arg0) < -100)) {
        return 0xfffffffd;
    }
    if (((long)(arg0) < -10)) {
        return 0xfffffffe;
    }
    if (((long)(arg0) < 0)) {
        return 0xffffffff;
    }
    ret = 0;
    if (((unsigned long)((unsigned int)(arg0)) == 0)) {
        return ret;
    }
    ret = 1;
    if ((((unsigned long)((unsigned int)(arg0)) == 9) | ((long)(arg0) < 9))) {
        return ret;
    }
    return (unsigned int)((((((unsigned long)((unsigned int)(arg0)) == 99) | ((long)(arg0) < 99)) == 0) + 2));
}
nested_ternary_assignment pass 9 lines
// glaurung: nested_ternary_assignment @ 0x1170
int32_t nested_ternary_assignment(int32_t arg0, int32_t arg1, int32_t arg2, int32_t * arg3) {
    int result;
    if ((arg3 == 0)) {
        return 0xffffffff;
    }
    *(int *)(((long)arg3)) = (((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) == 0) ? ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) ? (((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) == 0) ? (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - arg1))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) - arg0)))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - arg2)))) : ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) ? (((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) == 0) ? (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) - arg0))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) - arg1)))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) - arg2)))));
    return (unsigned int)(((unsigned long)((unsigned int)((((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) == 0) + ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) == 0)))) + ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) == 0)));
}
ternary_mixed_types pass 4 lines
// glaurung: ternary_mixed_types @ 0x1160
uint32_t ternary_mixed_types(int32_t arg0, int32_t arg1, uint32_t arg2) {
    return (((unsigned long)((unsigned int)(arg0)) == 0) ? arg2 : (unsigned long)((unsigned int)(arg1)));
}

← 213 fixtures