Fixture 96

integer promotion

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

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

Integer promotion and the usual arithmetic conversions. Everything narrower than int promotes to int before arithmetic, so uint8_t * uint8_t is computed in int and can exceed 255 without wrapping.

tests/decompiler_fixtures/src/96_integer_promotion.c source
#include <stdint.h>

/* Integer promotion and the usual arithmetic conversions. Everything narrower
 * than int promotes to int before arithmetic, so uint8_t * uint8_t is computed
 * in int and can exceed 255 without wrapping. */

__attribute__((noinline)) int32_t
promote_narrow_product(int32_t left, int32_t right) {
    uint8_t a = (uint8_t)left;
    uint8_t b = (uint8_t)right;
    /* Promoted to int: 200 * 200 is 40000, not 64. */
    return a * b;
}

__attribute__((noinline)) int32_t
promote_then_truncate(int32_t left, int32_t right) {
    uint8_t a = (uint8_t)left;
    uint8_t b = (uint8_t)right;
    return (int32_t)(uint8_t)(a * b);
}

__attribute__((noinline)) int32_t
short_promotion_sign(int32_t value) {
    int16_t narrow = (int16_t)value;
    /* Promotes to int, keeping the sign; the addition happens in int. */
    return narrow + 1;
}

__attribute__((noinline)) uint32_t
unsigned_conversion_rank(int32_t signed_value, uint32_t unsigned_value) {
    /* The signed operand converts to unsigned: the comparison is unsigned. */
    return ((uint32_t)signed_value < unsigned_value) ? 1u : 0u;
}

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
promote_narrow_product pass 10 lines
// glaurung: promote_narrow_product @ 0x1100
int32_t promote_narrow_product(int32_t arg0, int32_t arg1) {
    unsigned char a;
    unsigned char b;
    // x86-64 prologue: save rbp
    a = arg0;
    b = arg1;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned int)(a) * (unsigned int)(b)));
}
promote_then_truncate pass 10 lines
// glaurung: promote_then_truncate @ 0x1130
int32_t promote_then_truncate(int32_t arg0, int32_t arg1) {
    unsigned char a;
    unsigned char b;
    // x86-64 prologue: save rbp
    a = arg0;
    b = arg1;
    // x86-64 epilogue: restore rbp
    return (unsigned int)((unsigned char)(((unsigned long)((unsigned int)(((unsigned int)(a) * (unsigned int)(b)))) & 255)));
}
short_promotion_sign pass 8 lines
// glaurung: short_promotion_sign @ 0x1160
int32_t short_promotion_sign(int32_t arg0) {
    short narrow;
    // x86-64 prologue: save rbp
    narrow = arg0;
    // x86-64 epilogue: restore rbp
    return (unsigned int)((narrow + 1));
}
unsigned_conversion_rank pass 6 lines
// glaurung: unsigned_conversion_rank @ 0x1180
uint32_t unsigned_conversion_rank(int32_t arg0, uint32_t arg1) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (((unsigned long)((unsigned long)((unsigned int)(arg0))) < (unsigned long)((unsigned long)(arg1))) ? 1 : 0);
}

clang -O2

4/4
promote_narrow_product pass 4 lines
// glaurung: promote_narrow_product @ 0x1100
int32_t promote_narrow_product(int32_t arg0, int32_t arg1) {
    return (unsigned int)(((unsigned int)((unsigned char)((arg1 & 255))) * (unsigned int)((unsigned char)((arg0 & 255)))));
}
promote_then_truncate pass 4 lines
// glaurung: promote_then_truncate @ 0x1110
int32_t promote_then_truncate(int32_t arg0, int32_t arg1) {
    return (unsigned int)((unsigned char)(((unsigned long)((unsigned int)((arg0 * arg1))) & 255)));
}
short_promotion_sign pass 4 lines
// glaurung: short_promotion_sign @ 0x1120
int32_t short_promotion_sign(int32_t arg0) {
    return (unsigned int)(((int)((short)((arg0 & 0xffff))) + 1));
}
unsigned_conversion_rank pass 4 lines
// glaurung: unsigned_conversion_rank @ 0x1130
uint32_t unsigned_conversion_rank(int32_t arg0, uint32_t arg1) {
    return ((unsigned long)((unsigned long)((unsigned int)(arg0))) < (unsigned long)((unsigned long)(arg1)));
}

gcc -O0

4/4
promote_narrow_product pass 10 lines
// glaurung: promote_narrow_product @ 0x10f9
int32_t promote_narrow_product(int32_t arg0, int32_t arg1) {
    unsigned char a;
    unsigned char b;
    // x86-64 prologue: save rbp
    a = arg0;
    b = arg1;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned int)(b) * (unsigned int)(a)));
}
promote_then_truncate pass 12 lines
// glaurung: promote_then_truncate @ 0x1120
int32_t promote_then_truncate(int32_t arg0, int32_t arg1) {
    unsigned char a;
    unsigned char b;
    long t60;
    // x86-64 prologue: save rbp
    a = arg0;
    b = arg1;
    t60 = ((unsigned long)(a) & 255);
    // x86-64 epilogue: restore rbp
    return (unsigned int)((unsigned char)(((((t60 * b) & 255) | ((((unsigned char)(((unsigned short)(unsigned char)(t60) * (unsigned short)(unsigned char)(b)) >> 8)) & 255) << 8)) & 255)));
}
short_promotion_sign pass 8 lines
// glaurung: short_promotion_sign @ 0x1146
int32_t short_promotion_sign(int32_t arg0) {
    short narrow;
    // x86-64 prologue: save rbp
    narrow = arg0;
    // x86-64 epilogue: restore rbp
    return (unsigned int)((narrow + 1));
}
unsigned_conversion_rank pass 9 lines
// glaurung: unsigned_conversion_rank @ 0x1161
uint32_t unsigned_conversion_rank(int32_t arg0, uint32_t arg1) {
    // x86-64 prologue: save rbp
    if (((unsigned long)(arg1) <= (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
        return 0;
    } else {
        return 1;
    }
}

gcc -O2

4/4
promote_narrow_product pass 5 lines
// glaurung: promote_narrow_product @ 0x1100
int32_t promote_narrow_product(int32_t arg0, int32_t arg1) {
    unsigned char b;
    return (unsigned int)(((unsigned int)((unsigned char)((arg0 & 255))) * (unsigned int)((unsigned char)((arg1 & 255)))));
}
promote_then_truncate pass 4 lines
// glaurung: promote_then_truncate @ 0x1110
int32_t promote_then_truncate(int32_t arg0, int32_t arg1) {
    return (unsigned int)((unsigned char)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) * arg1))) & 255)));
}
short_promotion_sign pass 4 lines
// glaurung: short_promotion_sign @ 0x1120
int32_t short_promotion_sign(int32_t arg0) {
    return (unsigned int)(((int)((short)((arg0 & 0xffff))) + 1));
}
unsigned_conversion_rank pass 4 lines
// glaurung: unsigned_conversion_rank @ 0x1130
uint32_t unsigned_conversion_rank(int32_t arg0, uint32_t arg1) {
    return ((unsigned long)((unsigned long)((unsigned int)(arg0))) < (unsigned long)((unsigned long)(arg1)));
}

← 213 fixtures