Fixture 115

enum semantics

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

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

An enum's underlying type is implementation-defined and is chosen to fit the enumerators. A value outside the enumerated set is still representable, so a switch over an enum needs its default arm.

tests/decompiler_fixtures/src/115_enum_semantics.c source
#include <stdint.h>

/* An enum's underlying type is implementation-defined and is chosen to fit the
 * enumerators. A value outside the enumerated set is still representable, so a
 * switch over an enum needs its default arm. */

enum Small {
    SMALL_ZERO = 0,
    SMALL_ONE = 1,
    SMALL_TWO = 2
};

enum Wide {
    WIDE_LOW = -70000,
    WIDE_HIGH = 70000
};

enum Sparse {
    SPARSE_A = 1,
    SPARSE_B = 100,
    SPARSE_C = 10000
};

__attribute__((noinline)) int32_t enum_sizes(int32_t which) {
    switch (which & 3) {
    case 0:
        return (int32_t)sizeof(enum Small);
    case 1:
        return (int32_t)sizeof(enum Wide);
    default:
        return (int32_t)sizeof(enum Sparse);
    }
}

__attribute__((noinline)) int32_t enum_switch(int32_t raw) {
    enum Sparse value = (enum Sparse)raw;
    switch (value) {
    case SPARSE_A:
        return 11;
    case SPARSE_B:
        return 22;
    case SPARSE_C:
        return 33;
    default:
        return -1; /* reachable: raw need not be an enumerator */
    }
}

__attribute__((noinline)) int32_t enum_arithmetic(int32_t step) {
    enum Small value = SMALL_ZERO;
    if (step < 0 || step > 8) {
        return -1;
    }
    /* Enums participate in integer arithmetic after promotion. */
    return (int32_t)value + step * (int32_t)SMALL_TWO + (int32_t)WIDE_HIGH;
}

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
enum_arithmetic pass 20 lines
// glaurung: enum_arithmetic @ 0x11d0
int32_t enum_arithmetic(int32_t arg0) {
    int local_4;
    int local_c;
    // x86-64 prologue: save rbp
    local_c = 0;
    if (((long)(arg0) < 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((((unsigned long)((unsigned int)(arg0)) == 8) | ((long)(arg0) < 8)) == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    local_4 = ((unsigned int)(((unsigned long)((unsigned int)(local_c)) + (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) << 1))))) + 0x11170);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
enum_sizes pass 17 lines
// glaurung: enum_sizes @ 0x1100
int32_t enum_sizes(int32_t arg0) {
    int local_c;
    int var1;
    // x86-64 prologue: save rbp
    var1 = ((unsigned int)(arg0) & 3);
    local_c = var1;
    if (((unsigned long)((unsigned int)(var1)) == 0)) {
        return 4;
    } else {
        if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_c)) - 1))) == 0)) {
            return 4;
        } else {
            return 4;
        }
    }
}
enum_switch pass 19 lines
// glaurung: enum_switch @ 0x1150
int32_t enum_switch(int32_t arg0) {
    int local_10;
    // x86-64 prologue: save rbp
    local_10 = arg0;
    if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - 1))) == 0)) {
        return 11;
    } else {
        if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_10)) - 100))) == 0)) {
            return 22;
        } else {
            if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_10)) - 0x2710))) == 0)) {
                return 33;
            } else {
                return (unsigned int)(-1);
            }
        }
    }
}

clang -O2

3/3
enum_arithmetic pass 4 lines
// glaurung: enum_arithmetic @ 0x1140
int32_t enum_arithmetic(int32_t arg0) {
    return (((unsigned long)((unsigned long)((unsigned int)(arg0))) < (unsigned long)(9)) ? (unsigned long)((unsigned int)(((arg0 + arg0) + 0x11170))) : 0xffffffff);
}
enum_sizes pass 4 lines
// glaurung: enum_sizes @ 0x1100
int32_t enum_sizes(int32_t arg0) {
    return 4;
}
enum_switch pass 13 lines
// glaurung: enum_switch @ 0x1110
int32_t enum_switch(int32_t arg0) {
    if (((unsigned long)((unsigned int)(arg0)) == 1)) {
        return 11;
    }
    if (((unsigned long)((unsigned int)(arg0)) == 0x2710)) {
        return 33;
    }
    if (((unsigned long)((unsigned int)(arg0)) != 100)) {
        return 0xffffffff;
    }
    return 22;
}

gcc -O0

3/3
enum_arithmetic pass 16 lines
// glaurung: enum_arithmetic @ 0x1177
int32_t enum_arithmetic(int32_t arg0) {
    int local_4;
    // x86-64 prologue: save rbp
    local_4 = 0;
    if (((long)(arg0) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((((unsigned long)((unsigned int)(arg0)) == 8) | ((long)(arg0) < 8)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_4)) + (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) + (unsigned long)((unsigned int)(arg0)))))))) + 0x11170));
}
enum_sizes pass 15 lines
// glaurung: enum_sizes @ 0x10f9
int32_t enum_sizes(int32_t arg0) {
    long var2;
    // x86-64 prologue: save rbp
    var2 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 3)));
    if (((unsigned long)((unsigned int)(var2)) == 0)) {
        return 4;
    } else {
        if (((unsigned long)((unsigned int)(var2)) == 1)) {
            return 4;
        } else {
            return 4;
        }
    }
}
enum_switch pass 21 lines
// glaurung: enum_switch @ 0x112a
int32_t enum_switch(int32_t arg0) {
    // x86-64 prologue: save rbp
    if (((unsigned long)((unsigned int)(arg0)) == 0x2710)) {
        return 33;
    } else {
        if (((unsigned long)(0x2710) < (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
            // x86-64 epilogue: restore rbp
            return 0xffffffff;
        }
        if (((unsigned long)((unsigned int)(arg0)) == 1)) {
            return 11;
        } else {
            if (((unsigned long)((unsigned int)(arg0)) == 100)) {
                return 22;
            } else {
                return 0xffffffff;
            }
        }
    }
}

gcc -O2

3/3
enum_arithmetic pass 7 lines
// glaurung: enum_arithmetic @ 0x1140
int32_t enum_arithmetic(int32_t arg0) {
    if (((unsigned long)(8) < (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
        return 0xffffffff;
    }
    return (unsigned int)(((arg0 + arg0) + 0x11170));
}
enum_sizes pass 4 lines
// glaurung: enum_sizes @ 0x1100
int32_t enum_sizes(int32_t arg0) {
    return 4;
}
enum_switch pass 16 lines
// glaurung: enum_switch @ 0x1110
int32_t enum_switch(int32_t arg0) {
    long ret;
    ret = 22;
    if (((unsigned long)((unsigned int)(arg0)) == 100)) {
        return ret;
    }
    if (((unsigned long)((unsigned int)(arg0)) != 0x2710)) {
        if (((unsigned long)((unsigned int)(arg0)) == 1)) {
            return 11;
        } else {
            return 0xffffffff;
        }
    }
    return 33;
}

← 213 fixtures