Fixture 98

shift semantics

C · 5 functions · 4 lanes · 20 of 20 function-lanes behave identically

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

Shift edge cases that remain well-defined: the shift count is always masked into range, unsigned left shifts are modular, and a signed right shift is implementation-defined but arithmetic on every target this corpus builds.

tests/decompiler_fixtures/src/98_shift_semantics.c source
#include <stdint.h>

/* Shift edge cases that remain well-defined: the shift count is always masked
 * into range, unsigned left shifts are modular, and a signed right shift is
 * implementation-defined but arithmetic on every target this corpus builds. */

__attribute__((noinline)) uint32_t
masked_left_shift(uint32_t value, int32_t amount) {
    return value << (uint32_t)(amount & 31);
}

__attribute__((noinline)) int32_t
arithmetic_right_shift(int32_t value, int32_t amount) {
    /* Sign-propagating on x86/ARM/RISC-V: -8 >> 1 is -4, not a huge positive. */
    return value >> (amount & 31);
}

__attribute__((noinline)) uint32_t
logical_right_shift(uint32_t value, int32_t amount) {
    return value >> (uint32_t)(amount & 31);
}

__attribute__((noinline)) uint32_t
rotate_left(uint32_t value, int32_t amount) {
    uint32_t rotation = (uint32_t)(amount & 31);
    /* The zero case is spelled out so no shift by 32 is ever evaluated. */
    if (rotation == 0u) {
        return value;
    }
    return (value << rotation) | (value >> (32u - rotation));
}

__attribute__((noinline)) uint32_t
shift_wider_than_operand(uint32_t value, int32_t amount) {
    /* Promoting to 64 bits makes a shift of 32..63 meaningful instead of UB. */
    return (uint32_t)(((uint64_t)value << (uint32_t)(amount & 63)) >> 32);
}

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

5/5
arithmetic_right_shift pass 6 lines
// glaurung: arithmetic_right_shift @ 0x1120
int32_t arithmetic_right_shift(int32_t arg0, int32_t arg1) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((long)((long)(arg0)) >> ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & 31))) & 31)));
}
logical_right_shift pass 6 lines
// glaurung: logical_right_shift @ 0x1140
uint32_t logical_right_shift(uint32_t arg0, int32_t arg1) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)(arg0) >> ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & 31))) & 31)));
}
masked_left_shift pass 6 lines
// glaurung: masked_left_shift @ 0x1100
uint32_t masked_left_shift(uint32_t arg0, int32_t arg1) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)(arg0) << ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & 31))) & 31)));
}
rotate_left pass 11 lines
// glaurung: rotate_left @ 0x1160
uint32_t rotate_left(uint32_t arg0, int32_t arg1) {
    unsigned int rotation;
    // x86-64 prologue: save rbp
    rotation = ((unsigned int)(arg1) & 31);
    if ((rotation != 0)) {
        return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) << ((unsigned long)(rotation) & 31)))) | (unsigned long)((unsigned int)(((unsigned long)(arg0) >> ((unsigned long)((unsigned int)((32 - rotation))) & 31))))));
    } else {
        return arg0;
    }
}
shift_wider_than_operand pass 6 lines
// glaurung: shift_wider_than_operand @ 0x11b0
uint32_t shift_wider_than_operand(uint32_t arg0, int32_t arg1) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return ((unsigned long)(((unsigned long)(arg0) << ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & 63))) & 63))) >> 32);
}

clang -O2

5/5
arithmetic_right_shift pass 4 lines
// glaurung: arithmetic_right_shift @ 0x1110
int32_t arithmetic_right_shift(int32_t arg0, int32_t arg1) {
    return (unsigned int)(((long)((long)(arg0)) >> ((unsigned long)((unsigned int)(arg1)) & 31)));
}
logical_right_shift pass 4 lines
// glaurung: logical_right_shift @ 0x1120
uint32_t logical_right_shift(uint32_t arg0, int32_t arg1) {
    return (unsigned int)(((unsigned long)(arg0) >> ((unsigned long)((unsigned int)(arg1)) & 31)));
}
masked_left_shift pass 4 lines
// glaurung: masked_left_shift @ 0x1100
uint32_t masked_left_shift(uint32_t arg0, int32_t arg1) {
    return (unsigned int)(((unsigned long)(arg0) << ((unsigned long)((unsigned int)(arg1)) & 31)));
}
rotate_left pass 6 lines
// glaurung: rotate_left @ 0x1130
uint32_t rotate_left(uint32_t arg0, int32_t arg1) {
    long t41;
    t41 = ((unsigned long)((unsigned int)(arg1)) & 31);
    return (((unsigned long)(arg0) << t41) | ((unsigned long)(arg0) >> ((32 - t41) & 31)));
}
shift_wider_than_operand pass 4 lines
// glaurung: shift_wider_than_operand @ 0x1140
uint32_t shift_wider_than_operand(uint32_t arg0, int32_t arg1) {
    return ((unsigned long)(((unsigned long)(arg0) << ((unsigned long)((unsigned int)(arg1)) & 63))) >> 32);
}

gcc -O0

5/5
arithmetic_right_shift pass 6 lines
// glaurung: arithmetic_right_shift @ 0x1118
int32_t arithmetic_right_shift(int32_t arg0, int32_t arg1) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((long)((long)(arg0)) >> ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & 31))) & 31)));
}
logical_right_shift pass 6 lines
// glaurung: logical_right_shift @ 0x1137
uint32_t logical_right_shift(uint32_t arg0, int32_t arg1) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)(arg0) >> ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & 31))) & 31)));
}
masked_left_shift pass 6 lines
// glaurung: masked_left_shift @ 0x10f9
uint32_t masked_left_shift(uint32_t arg0, int32_t arg1) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)(arg0) << ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & 31))) & 31)));
}
rotate_left pass 13 lines
// glaurung: rotate_left @ 0x1156
uint32_t rotate_left(uint32_t arg0, int32_t arg1) {
    unsigned int rotation;
    long t41;
    // x86-64 prologue: save rbp
    rotation = ((unsigned int)(arg1) & 31);
    if ((rotation != 0)) {
        t41 = ((unsigned long)(rotation) & 31);
        return (unsigned int)((((unsigned long)(arg0) << t41) | ((unsigned long)(arg0) >> ((32 - t41) & 31))));
    } else {
        return arg0;
    }
}
shift_wider_than_operand pass 6 lines
// glaurung: shift_wider_than_operand @ 0x1186
uint32_t shift_wider_than_operand(uint32_t arg0, int32_t arg1) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return ((unsigned long)(((unsigned long)(arg0) << ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & 63))) & 63))) >> 32);
}

gcc -O2

5/5
arithmetic_right_shift pass 4 lines
// glaurung: arithmetic_right_shift @ 0x1110
int32_t arithmetic_right_shift(int32_t arg0, int32_t arg1) {
    return (unsigned int)(((long)((long)(arg0)) >> ((unsigned long)((unsigned int)(arg1)) & 31)));
}
logical_right_shift pass 4 lines
// glaurung: logical_right_shift @ 0x1120
uint32_t logical_right_shift(uint32_t arg0, int32_t arg1) {
    return (unsigned int)(((unsigned long)(arg0) >> ((unsigned long)((unsigned int)(arg1)) & 31)));
}
masked_left_shift pass 4 lines
// glaurung: masked_left_shift @ 0x1100
uint32_t masked_left_shift(uint32_t arg0, int32_t arg1) {
    return (unsigned int)(((unsigned long)(arg0) << ((unsigned long)((unsigned int)(arg1)) & 31)));
}
rotate_left pass 6 lines
// glaurung: rotate_left @ 0x1130
uint32_t rotate_left(uint32_t arg0, int32_t arg1) {
    long t41;
    t41 = ((unsigned long)((unsigned int)(arg1)) & 31);
    return (((unsigned long)(arg0) << t41) | ((unsigned long)(arg0) >> ((32 - t41) & 31)));
}
shift_wider_than_operand pass 4 lines
// glaurung: shift_wider_than_operand @ 0x1140
uint32_t shift_wider_than_operand(uint32_t arg0, int32_t arg1) {
    return ((unsigned long)(((unsigned long)(arg0) << ((unsigned long)((unsigned int)(arg1)) & 63))) >> 32);
}

← 213 fixtures