Fixture 130

bitpacked codec

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

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

A wire codec that packs four fields of different widths into one word and reads them back. The shift/mask constants are the entire specification, so an off-by-one in any of them is invisible structurally and fatal behaviorally.

tests/decompiler_fixtures/src/130_bitpacked_codec.c source
#include <stdint.h>

/* A wire codec that packs four fields of different widths into one word and
 * reads them back. The shift/mask constants are the entire specification, so an
 * off-by-one in any of them is invisible structurally and fatal behaviorally. */

#define FIELD_A_BITS 5
#define FIELD_B_BITS 7
#define FIELD_C_BITS 12
#define FIELD_D_BITS 8

__attribute__((noinline)) uint32_t
pack_fields(int32_t a, int32_t b, int32_t c, int32_t d) {
    uint32_t packed = 0;
    packed |= (uint32_t)a & ((1u << FIELD_A_BITS) - 1u);
    packed |= ((uint32_t)b & ((1u << FIELD_B_BITS) - 1u)) << FIELD_A_BITS;
    packed |= ((uint32_t)c & ((1u << FIELD_C_BITS) - 1u))
              << (FIELD_A_BITS + FIELD_B_BITS);
    packed |= ((uint32_t)d & ((1u << FIELD_D_BITS) - 1u))
              << (FIELD_A_BITS + FIELD_B_BITS + FIELD_C_BITS);
    return packed;
}

__attribute__((noinline)) int32_t
unpack_field(uint32_t packed, int32_t which) {
    switch (which & 3) {
    case 0:
        return (int32_t)(packed & ((1u << FIELD_A_BITS) - 1u));
    case 1:
        return (int32_t)((packed >> FIELD_A_BITS) &
                         ((1u << FIELD_B_BITS) - 1u));
    case 2:
        return (int32_t)((packed >> (FIELD_A_BITS + FIELD_B_BITS)) &
                         ((1u << FIELD_C_BITS) - 1u));
    default:
        return (int32_t)((packed >>
                          (FIELD_A_BITS + FIELD_B_BITS + FIELD_C_BITS)) &
                         ((1u << FIELD_D_BITS) - 1u));
    }
}

__attribute__((noinline)) int32_t
codec_roundtrip(int32_t a, int32_t b, int32_t c, int32_t d) {
    uint32_t packed = pack_fields(a, b, c, d);
    return (unpack_field(packed, 0) == (a & 31)) +
           (unpack_field(packed, 1) == (b & 127)) +
           (unpack_field(packed, 2) == (c & 4095)) +
           (unpack_field(packed, 3) == (d & 255));
}

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
codec_roundtrip pass 26 lines
// glaurung: codec_roundtrip @ 0x1210
int32_t codec_roundtrip(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern unsigned int pack_fields(int, int, int, int);
    extern int unpack_field(unsigned int, int);
    unsigned int packed;
    int local_18;
    int local_1c;
    int local_20;
    unsigned int var0;
    int var13;
    int var27;
    int var3;
    int var41;
    // x86-64 prologue: save rbp, frame 32 bytes
    var0 = pack_fields((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg2)), (unsigned long)((unsigned int)(arg3)));
    packed = var0;
    var3 = unpack_field(packed, 0);
    local_20 = ((unsigned int)(var3) == (unsigned int)(((unsigned long)((unsigned int)(arg0)) & 31)));
    var13 = unpack_field(packed, 1);
    local_1c = ((unsigned int)(local_20) + ((unsigned int)(var13) == (unsigned int)(((unsigned long)((unsigned int)(arg1)) & 127))));
    var27 = unpack_field(packed, 2);
    local_18 = ((unsigned int)(local_1c) + ((unsigned int)(var27) == (unsigned int)(((unsigned long)((unsigned int)(arg2)) & 4095))));
    var41 = unpack_field(packed, 3);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(local_18)) + ((unsigned int)(var41) == (unsigned int)(((unsigned long)((unsigned int)(arg3)) & 255)))));
}
pack_fields pass 12 lines
// glaurung: pack_fields @ 0x1120
uint32_t pack_fields(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    unsigned int packed;
    // x86-64 prologue: save rbp
    packed = 0;
    packed = ((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 31)) | packed);
    packed = ((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & 127))) << 5)) | packed);
    packed = ((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) & 4095))) << 12)) | packed);
    packed = ((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg3)) & 255))) << 24)) | packed);
    // x86-64 epilogue: restore rbp
    return packed;
}
unpack_field pass 21 lines
// glaurung: unpack_field @ 0x1180
int32_t unpack_field(uint32_t arg0, int32_t arg1) {
    int local_10;
    int var1;
    // x86-64 prologue: save rbp
    var1 = ((unsigned int)(arg1) & 3);
    local_10 = var1;
    if (((unsigned long)((unsigned int)(var1)) == 0)) {
        return (unsigned int)(((unsigned long)(arg0) & 31));
    } else {
        if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_10)) - 1))) == 0)) {
            return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) >> 5))) & 127));
        } else {
            if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_10)) - 2))) == 0)) {
                return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) >> 12))) & 4095));
            } else {
                return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) >> 24))) & 255));
            }
        }
    }
}

clang -O2

3/3
codec_roundtrip pass 34 lines
// glaurung: codec_roundtrip @ 0x1170
int32_t codec_roundtrip(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern unsigned int pack_fields(int, int, int, int);
    extern int unpack_field(unsigned int, int);
    unsigned int packed;
    long var0;
    long var1;
    long var15;
    int var16;
    long var2;
    long var25;
    int var26;
    long var3;
    long var35;
    int var36;
    unsigned int var4;
    int var8;
    // x86-64 prologue: save callee registers, frame 56 bytes
    var0 = (unsigned long)((unsigned int)(arg3));
    var1 = (unsigned long)((unsigned int)(arg2));
    var2 = (unsigned long)((unsigned int)(arg1));
    var3 = (unsigned long)((unsigned int)(arg0));
    var4 = pack_fields(arg0, arg1, arg2, arg3);
    packed = var4;
    var8 = unpack_field(var4, 0);
    var15 = ((unsigned int)(var8) == (unsigned int)((var3 & 31)));
    var16 = unpack_field(packed, 1);
    var25 = (unsigned long)((unsigned int)((((unsigned int)(var16) == (unsigned int)((var2 & 127))) + var15)));
    var26 = unpack_field(packed, 2);
    var35 = (unsigned long)((unsigned int)((((unsigned int)(var26) == (unsigned int)((var1 & 4095))) + var25)));
    var36 = unpack_field(packed, 3);
    // x86-64 epilogue: restore callee registers
    return (unsigned int)((((unsigned int)(var36) == (unsigned int)((unsigned char)((var0 & 255)))) + var35));
}
pack_fields pass 5 lines
// glaurung: pack_fields @ 0x1120
uint32_t pack_fields(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    unsigned int packed;
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)((arg1 & 127))) << 5))) + (unsigned long)((unsigned int)((arg0 & 31)))))) | (unsigned long)((unsigned int)(((unsigned long)((unsigned int)((arg2 << 12))) & 0xfff000)))))) | (unsigned long)((unsigned int)((arg3 << 24)))));
}
unpack_field pass 17 lines
// glaurung: unpack_field @ 0x1140
int32_t unpack_field(uint32_t arg0, int32_t arg1) {
    long var0;
    long var2;
    var0 = (unsigned long)(arg0);
    var2 = (unsigned long)((unsigned int)((arg1 & 3)));
    if (((unsigned long)((unsigned int)(var2)) == 2)) {
        return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var0)) >> 12))) & 4095));
    }
    if (((unsigned long)((unsigned int)(var2)) == 1)) {
        return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var0)) >> 5))) & 127));
    }
    if (((unsigned long)((unsigned int)(var2)) != 0)) {
        return (unsigned int)(((unsigned long)((unsigned int)(var0)) >> 24));
    }
    return (unsigned int)(((unsigned long)(arg0) & 31));
}

gcc -O0

3/3
codec_roundtrip pass 26 lines
// glaurung: codec_roundtrip @ 0x11d8
int32_t codec_roundtrip(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern unsigned int pack_fields(int, int, int, int);
    extern int unpack_field(unsigned int, int);
    unsigned int packed;
    unsigned int var1;
    int var11;
    int var13;
    long var22;
    int var24;
    long var33;
    int var35;
    int var4;
    // x86-64 prologue: save rbp, frame 8 bytes
    var1 = pack_fields((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg2)), (unsigned long)((unsigned int)(arg3)));
    packed = var1;
    var4 = unpack_field(packed, 0);
    var11 = ((unsigned int)(var4) == (unsigned int)(((unsigned long)((unsigned int)(arg0)) & 31)));
    var13 = unpack_field(packed, 1);
    var22 = (unsigned long)((unsigned int)((var11 + ((unsigned int)(var13) == (unsigned int)(((unsigned long)((unsigned int)(arg1)) & 127))))));
    var24 = unpack_field(packed, 2);
    var33 = (unsigned long)((unsigned int)((var22 + ((unsigned int)(var24) == (unsigned int)(((unsigned long)((unsigned int)(arg2)) & 4095))))));
    var35 = unpack_field(packed, 3);
    // x86-64 epilogue: restore rbp
    return (unsigned int)((((unsigned int)(var35) == (unsigned int)((unsigned char)(((unsigned long)((unsigned int)(arg3)) & 255)))) + var33));
}
pack_fields pass 12 lines
// glaurung: pack_fields @ 0x1139
uint32_t pack_fields(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    unsigned int packed;
    // x86-64 prologue: save rbp
    packed = 0;
    packed = (packed | (unsigned int)(((unsigned long)((unsigned int)(arg0)) & 31)));
    packed = (packed | (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) << 5))) & 4064)));
    packed = (packed | (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) << 12))) & 0xfff000)));
    packed = (packed | (unsigned int)(((unsigned long)((unsigned int)(arg3)) << 24)));
    // x86-64 epilogue: restore rbp
    return packed;
}
unpack_field pass 26 lines
// glaurung: unpack_field @ 0x1187
int32_t unpack_field(uint32_t arg0, int32_t arg1) {
    int var10;
    long var2;
    // x86-64 prologue: save rbp
    var2 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & 3)));
    if (((unsigned long)((unsigned int)(var2)) == 2)) {
        return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) >> 12))) & 4095));
    } else {
        if (((((unsigned long)((unsigned int)(var2)) == 2) | ((long)((int)(var2)) < 2)) == 0)) {
            var10 = ((unsigned int)(arg0) >> 24);
            // x86-64 epilogue: restore rbp
            return (unsigned int)(var10);
        }
        if (((unsigned long)((unsigned int)(var2)) == 0)) {
            return (unsigned int)(((unsigned long)(arg0) & 31));
        } else {
            if (((unsigned long)((unsigned int)(var2)) == 1)) {
                return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) >> 5))) & 127));
            } else {
                var10 = ((unsigned int)(arg0) >> 24);
                return (unsigned int)(var10);
            }
        }
    }
}

gcc -O2

3/3
codec_roundtrip pass 35 lines
// glaurung: codec_roundtrip @ 0x11b0
int32_t codec_roundtrip(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern unsigned int pack_fields(int, int, int, int);
    extern int unpack_field(unsigned int, int);
    unsigned int packed;
    long var1;
    int var11;
    long var13;
    int var14;
    long var25;
    long var27;
    int var28;
    long var3;
    long var31;
    int var32;
    long var4;
    int var6;
    unsigned int var7;
    var1 = (unsigned long)((unsigned int)(arg1));
    var3 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 31)));
    var4 = (unsigned long)((unsigned int)(arg2));
    var6 = (unsigned int)((unsigned char)(((unsigned long)((unsigned int)(arg3)) & 255)));
    var7 = pack_fields(arg0, arg1, arg2, arg3);
    packed = var7;
    var11 = unpack_field(var7, 0);
    var13 = (unsigned long)((unsigned int)(var11));
    var14 = unpack_field(packed, 1);
    var25 = (unsigned long)((unsigned int)((var4 & 4095)));
    var27 = (unsigned long)((unsigned int)((((unsigned int)(var3) == (unsigned int)(var13)) + ((unsigned int)((var1 & 127)) == (unsigned int)(var14)))));
    var28 = unpack_field(packed, 2);
    var31 = ((unsigned int)(var25) == (unsigned int)(var28));
    var32 = unpack_field(packed, 3);
    // x86-64 epilogue: tear down frame
    return (unsigned int)((((unsigned int)(var6) == (unsigned int)(var32)) + (unsigned long)((unsigned int)(((unsigned int)((unsigned char)((var31 & 255))) + var27)))));
}
pack_fields pass 4 lines
// glaurung: pack_fields @ 0x1140
uint32_t pack_fields(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)((arg2 << 12))) & 0xfff000))) | (unsigned long)((unsigned int)((arg3 << 24)))))) | (unsigned long)((unsigned int)((arg0 & 31)))))) | (unsigned long)((unsigned int)(((unsigned long)((unsigned int)((arg1 << 5))) & 4064)))));
}
unpack_field pass 12 lines
// glaurung: unpack_field @ 0x1170
int32_t unpack_field(uint32_t arg0, int32_t arg1) {
    long var1;
    var1 = (unsigned long)((unsigned int)((arg1 & 3)));
    if (((unsigned long)((unsigned int)(var1)) == 1)) {
        return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) >> 5))) & 127));
    }
    if (((unsigned long)((unsigned int)(var1)) == 2)) {
        return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) >> 12))) & 4095));
    }
    return (((unsigned long)((unsigned int)(var1)) != 0) ? (unsigned long)((unsigned int)(((unsigned long)(arg0) >> 24))) : (unsigned long)((unsigned int)(((unsigned long)(arg0) & 31))));
}

← 213 fixtures