Fixture 02

integer widths

C · 28 functions · 4 lanes · 112 of 112 function-lanes behave identically

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

Integer width / signedness fixture. Every function is a pure integer function whose result depends on the EXACT bit width and signedness of the operations a correct decompilation must recover. A width- or sign-broken lowering (dropped 32-bit zero-extension, >> on the wrong signedness, a missing truncation mask, a sign-extend where a zero-extend belonged) sends the return value to a different constant, which an execution-differential test catches.

Targets review #2 (integer width & sign). Keep every function pure (no globals, no memory beyond passed-in pointers, no libc) and deterministic in its integer arguments. Every function returns an int that differs between a correct and a width-broken lowering.

tests/decompiler_fixtures/src/02_integer_widths.c source
/* 02_integer_widths.c
 *
 * Integer width / signedness fixture. Every function is a pure integer function
 * whose result depends on the EXACT bit width and signedness of the operations
 * a correct decompilation must recover. A width- or sign-broken lowering
 * (dropped 32-bit zero-extension, `>>` on the wrong signedness, a missing
 * truncation mask, a sign-extend where a zero-extend belonged) sends the return
 * value to a different constant, which an execution-differential test catches.
 *
 * Targets review #2 (integer width & sign). Keep every function pure (no
 * globals, no memory beyond passed-in pointers, no libc) and deterministic in
 * its integer arguments. Every function returns an int that differs between a
 * correct and a width-broken lowering.
 */
#include <stdint.h>

/* --- round-trips through each unsigned width --------------------------- */

/* uint8_t round-trip: value must survive an 8-bit store/load, i.e. be masked
 * to the low byte. A decompiler that widens the temporary loses the & 0xFF. */
int rt_u8(unsigned x) {
    uint8_t v = (uint8_t)x;
    return (int)v;                 /* == x & 0xFF */
}

/* uint16_t round-trip. */
int rt_u16(unsigned x) {
    uint16_t v = (uint16_t)x;
    return (int)v;                 /* == x & 0xFFFF */
}

/* uint32_t round-trip: return the full 32-bit value as a signed int. */
int rt_u32(unsigned x) {
    uint32_t v = (uint32_t)x;
    return (int)v;
}

/* uint64_t round-trip: pack a value into 64 bits, fold the halves back to an
 * int. If the high 32 bits are dropped the fold changes. */
int rt_u64(unsigned x) {
    uint64_t v = ((uint64_t)x << 20) | (uint64_t)x;
    return (int)((v >> 20) ^ (v & 0xFFFFFF));
}

/* --- sign extension ---------------------------------------------------- */

/* Return an int8_t param as int: the top bit must sign-extend. For x=0xFF the
 * result is -1, not 255. A zero-extend here is the classic bug. */
int sext_i8(int x) {
    int8_t v = (int8_t)x;
    return (int)v;
}

/* Sign-extend a 16-bit quantity. */
int sext_i16(int x) {
    int16_t v = (int16_t)x;
    return (int)v;
}

/* --- zero extension of architecture-defined 32-bit writes -------------- */

/* Write a 32-bit value into a 64-bit register: on x86-64 a 32-bit write
 * zero-extends the full 64-bit register. Compute in 64 bits and mask so the
 * value is unambiguous; a lowering that treats the write as sign-extending or
 * leaves the high bits dirty produces a different masked result. */
int zext_u32_to_u64(uint32_t x) {
    uint64_t r = x;                /* zero-extended by definition */
    r += 0x100000000ULL;           /* deposit into the high word */
    return (int)(r >> 32);         /* == 1 for every x if zero-extended */
}

/* A 32-bit subtract that underflows: the borrow must NOT propagate into a
 * 64-bit register. (a - b) as uint32_t wraps mod 2^32; widened math would not. */
int wrap_sub_u32(uint32_t a, uint32_t b) {
    uint32_t r = a - b;
    return (int)(r >> 24);         /* top byte of the wrapped difference */
}

/* --- truncation -------------------------------------------------------- */

/* Truncate to a byte. */
int trunc_u8(unsigned x) {
    return (uint8_t)x;             /* low 8 bits, zero-extended to int */
}

/* Truncate to a halfword after an arithmetic op that overflows 16 bits. */
int trunc_u16_after_mul(unsigned x) {
    uint16_t v = (uint16_t)(x * 3u);
    return (int)v;
}

/* --- partial-word write / deposit -------------------------------------- */

/* Overwrite only the low byte of a word, keep the upper three bytes. A
 * decompiler that clobbers the whole word instead of doing a byte deposit
 * returns a different value. */
int deposit_low_byte(unsigned x, unsigned b) {
    uint32_t v = (uint32_t)x;
    v = (v & 0xFFFFFF00u) | (b & 0xFFu);
    return (int)v;
}

/* Deposit into the second byte lane [15:8]. */
int deposit_byte1(unsigned x, unsigned b) {
    uint32_t v = (uint32_t)x;
    v = (v & 0xFFFF00FFu) | ((b & 0xFFu) << 8);
    return (int)v;
}

/* --- byte extraction --------------------------------------------------- */

/* Extract byte lane 1: (x >> 8) & 0xFF. */
int extract_byte1(unsigned x) {
    return (int)((x >> 8) & 0xFFu);
}

/* Extract byte lane 3 (top byte of a 32-bit word). */
int extract_byte3(unsigned x) {
    return (int)((x >> 24) & 0xFFu);
}

/* --- hi<<32 | lo reconstruction ---------------------------------------- */

/* Reassemble a 64-bit value from two 32-bit halves, then fold to an int. If
 * `hi` is not shifted into the true high word (e.g. shifted in 32-bit math and
 * lost) the fold differs. */
int reconstruct_64(uint32_t hi, uint32_t lo) {
    uint64_t v = ((uint64_t)hi << 32) | (uint64_t)lo;
    return (int)((v >> 32) - (v & 0xFFFFFFFFu));
}

/* --- signed vs unsigned right shift (MUST differ for negatives) -------- */

/* Arithmetic right shift on a signed int: sign bit replicates. For x<0 the
 * result stays negative. */
int sar_signed(int x) {
    return x >> 4;
}

/* Logical right shift on an unsigned: zero fill. For the SAME negative bit
 * pattern this must NOT equal sar_signed — that divergence is the whole point. */
int shr_unsigned(unsigned x) {
    return (int)(x >> 4);
}

/* Right shift after casting a negative int to unsigned: forces the logical
 * (zero-fill) form even though the source looks signed. */
int shr_via_cast(int x) {
    return (int)(((unsigned)x) >> 1);
}

/* --- overflow-sensitive add / mul -------------------------------------- */

/* 32-bit signed add that is allowed to wrap: the result is only correct if the
 * add is performed at 32 bits. Computed through uint32_t to keep it defined. */
int add_wrap32(int a, int b) {
    uint32_t r = (uint32_t)a + (uint32_t)b;
    return (int)r;
}

/* 32-bit multiply that discards the high product. If the decompiler promotes to
 * a 64-bit multiply and keeps the high bits, the masked result changes. */
int mul_wrap32(unsigned a, unsigned b) {
    uint32_t r = a * b;
    return (int)(r & 0x7FFFFFFF);
}

/* Widening multiply: the product genuinely needs 64 bits; folding it back
 * exercises the high half that a 32-bit-only lowering would drop. */
int mul_widen(uint32_t a, uint32_t b) {
    uint64_t r = (uint64_t)a * (uint64_t)b;
    return (int)((r >> 32) ^ (r & 0xFFFFFFFFu));
}

/* Full-width x86 multiply and divide have TWO architectural outputs. These
 * functions force both signed and unsigned high-product/remainder paths and
 * return the complete 64-bit result so dropping either half is observable. */
uint64_t umul_high64(uint64_t a, uint64_t b) {
    return (uint64_t)(((unsigned __int128)a * (unsigned __int128)b) >> 64);
}

int64_t smul_high64(int64_t a, int64_t b) {
    return (int64_t)(((__int128)a * (__int128)b) >> 64);
}

uint64_t urem64(uint64_t a, uint64_t b) {
    return a % b;
}

int64_t srem64(int64_t a, int64_t b) {
    return a % b;
}

/* --- rotates written in portable C ------------------------------------- */

/* Rotate-left by a fixed amount, 32-bit. The (x >> (32-n)) half must use
 * 32-bit unsigned semantics; a wrong width leaks or loses bits. */
int rotl32_7(uint32_t x) {
    uint32_t r = (x << 7) | (x >> (32 - 7));
    return (int)r;
}

/* Rotate-right by a variable amount masked to 5 bits. */
int rotr32(uint32_t x, unsigned n) {
    n &= 31u;
    uint32_t r = (x >> n) | (x << ((32 - n) & 31));
    return (int)r;
}

/* 16-bit rotate: the wrap distance is 16, and the intermediate must be masked
 * to 16 bits or the two halves collide. */
int rotl16_3(unsigned x) {
    uint16_t v = (uint16_t)x;
    uint16_t r = (uint16_t)((v << 3) | (v >> (16 - 3)));
    return (int)r;
}

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

28/28
add_wrap32 pass 8 lines
// glaurung: add_wrap32 @ 0x1360
int add_wrap32(int arg0, int arg1) {
    unsigned int r;
    // x86-64 prologue: save rbp
    r = ((unsigned int)(arg0) + arg1);
    // x86-64 epilogue: restore rbp
    return r;
}
deposit_byte1 pass 9 lines
// glaurung: deposit_byte1 @ 0x1280
int deposit_byte1(unsigned int arg0, unsigned int arg1) {
    unsigned int v;
    // x86-64 prologue: save rbp
    v = arg0;
    v = ((unsigned int)((v & -0xff01LL)) | (unsigned int)(((unsigned long)((unsigned int)((arg1 & 255))) << 8)));
    // x86-64 epilogue: restore rbp
    return v;
}
deposit_low_byte pass 9 lines
// glaurung: deposit_low_byte @ 0x1250
int deposit_low_byte(unsigned int arg0, unsigned int arg1) {
    unsigned int v;
    // x86-64 prologue: save rbp
    v = arg0;
    v = ((unsigned int)((v & -256)) | (unsigned int)((arg1 & 255)));
    // x86-64 epilogue: restore rbp
    return v;
}
extract_byte1 pass 6 lines
// glaurung: extract_byte1 @ 0x12b0
int extract_byte1(unsigned int arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) >> 8))) & 255));
}
extract_byte3 pass 6 lines
// glaurung: extract_byte3 @ 0x12d0
int extract_byte3(unsigned int arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) >> 24))) & 255));
}
mul_widen pass 8 lines
// glaurung: mul_widen @ 0x13a0
int mul_widen(uint32_t arg0, uint32_t arg1) {
    unsigned long r;
    // x86-64 prologue: save rbp
    r = ((unsigned long)(arg0) * (unsigned long)(arg1));
    // x86-64 epilogue: restore rbp
    return (((unsigned long)(r) >> 32) ^ (0xffffffff & r));
}
mul_wrap32 pass 8 lines
// glaurung: mul_wrap32 @ 0x1380
int mul_wrap32(unsigned int arg0, unsigned int arg1) {
    unsigned int r;
    // x86-64 prologue: save rbp
    r = (arg0 * arg1);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)(r) & 0x7fffffff));
}
reconstruct_64 pass 8 lines
// glaurung: reconstruct_64 @ 0x12f0
int reconstruct_64(uint32_t arg0, uint32_t arg1) {
    unsigned long v;
    // x86-64 prologue: save rbp
    v = (((unsigned long)(arg0) << 32) | (unsigned long)(arg1));
    // x86-64 epilogue: restore rbp
    return (((unsigned long)(v) >> 32) - (0xffffffff & v));
}
rotl16_3 pass 10 lines
// glaurung: rotl16_3 @ 0x14c0
int rotl16_3(unsigned int arg0) {
    unsigned short v;
    unsigned short r;
    // x86-64 prologue: save rbp
    v = arg0;
    r = ((unsigned long)((unsigned int)(((unsigned int)(v) << 3))) | (unsigned long)((unsigned int)(((int)(v) >> 13))));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(r);
}
rotl32_7 pass 8 lines
// glaurung: rotl32_7 @ 0x1460
int rotl32_7(uint32_t arg0) {
    unsigned int r;
    // x86-64 prologue: save rbp
    r = ((unsigned int)((arg0 << 7)) | (unsigned int)(((unsigned int)(arg0) >> 25)));
    // x86-64 epilogue: restore rbp
    return r;
}
rotr32 pass 9 lines
// glaurung: rotr32 @ 0x1480
int rotr32(uint32_t arg0, unsigned int arg1) {
    unsigned int r;
    // x86-64 prologue: save rbp
    arg1 = (arg1 & 31);
    r = ((unsigned int)(((unsigned long)(arg0) >> (arg1 & 31))) | (unsigned int)((arg0 << ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)((32 - arg1))) & 31))) & 31))));
    // x86-64 epilogue: restore rbp
    return r;
}
rt_u16 pass 8 lines
// glaurung: rt_u16 @ 0x1120
int rt_u16(unsigned int arg0) {
    unsigned short v;
    // x86-64 prologue: save rbp
    v = arg0;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(v);
}
rt_u32 pass 8 lines
// glaurung: rt_u32 @ 0x1140
int rt_u32(unsigned int arg0) {
    unsigned int v;
    // x86-64 prologue: save rbp
    v = arg0;
    // x86-64 epilogue: restore rbp
    return v;
}
rt_u64 pass 8 lines
// glaurung: rt_u64 @ 0x1160
int rt_u64(unsigned int arg0) {
    unsigned long v;
    // x86-64 prologue: save rbp
    v = (((unsigned long)(arg0) << 20) | (unsigned long)(arg0));
    // x86-64 epilogue: restore rbp
    return (((unsigned long)(v) >> 20) ^ (v & 0xffffff));
}
rt_u8 pass 8 lines
// glaurung: rt_u8 @ 0x1100
int rt_u8(unsigned int arg0) {
    unsigned char v;
    // x86-64 prologue: save rbp
    v = arg0;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(v);
}
sar_signed pass 6 lines
// glaurung: sar_signed @ 0x1330
int sar_signed(int arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((int)(arg0) >> 4));
}
sext_i16 pass 8 lines
// glaurung: sext_i16 @ 0x11b0
int sext_i16(int arg0) {
    short v;
    // x86-64 prologue: save rbp
    v = arg0;
    // x86-64 epilogue: restore rbp
    return v;
}
sext_i8 pass 8 lines
// glaurung: sext_i8 @ 0x1190
int sext_i8(int arg0) {
    signed char v;
    // x86-64 prologue: save rbp
    v = arg0;
    // x86-64 epilogue: restore rbp
    return v;
}
shr_unsigned pass 6 lines
// glaurung: shr_unsigned @ 0x1340
int shr_unsigned(unsigned int arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)(arg0) >> 4));
}
shr_via_cast pass 6 lines
// glaurung: shr_via_cast @ 0x1350
int shr_via_cast(int arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(arg0)) >> 1));
}
smul_high64 pass 6 lines
// glaurung: smul_high64 @ 0x1400
int64_t smul_high64(int64_t arg0, int64_t arg1) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return ((long)(((unsigned __int128)((__int128)(long)(arg0) * (__int128)(long)(arg1))) >> 64));
}
srem64 pass 6 lines
// glaurung: srem64 @ 0x1440
int64_t srem64(int64_t arg0, int64_t arg1) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return ((long)((((__int128)(long)(((long)(arg0) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(arg0)) % (long)(arg1)));
}
trunc_u16_after_mul pass 8 lines
// glaurung: trunc_u16_after_mul @ 0x1230
int trunc_u16_after_mul(unsigned int arg0) {
    unsigned short v;
    // x86-64 prologue: save rbp
    v = (arg0 * 3);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(v);
}
trunc_u8 pass 6 lines
// glaurung: trunc_u8 @ 0x1220
int trunc_u8(unsigned int arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)((unsigned char)(((unsigned long)(arg0) & 255)));
}
umul_high64 pass 6 lines
// glaurung: umul_high64 @ 0x13e0
uint64_t umul_high64(uint64_t arg0, uint64_t arg1) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return ((unsigned long)(((unsigned __int128)(unsigned long)(arg0) * (unsigned __int128)(unsigned long)(arg1)) >> 64));
}
urem64 pass 6 lines
// glaurung: urem64 @ 0x1420
uint64_t urem64(uint64_t arg0, uint64_t arg1) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return ((unsigned long)(((((unsigned __int128)(unsigned long)((unsigned long)((unsigned int)((unsigned long)((unsigned int)(0))))) << 64) | (unsigned long)(arg0)) % (unsigned long)(arg1))));
}
wrap_sub_u32 pass 8 lines
// glaurung: wrap_sub_u32 @ 0x1200
int wrap_sub_u32(uint32_t arg0, uint32_t arg1) {
    unsigned int r;
    // x86-64 prologue: save rbp
    r = (arg0 - arg1);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)(r) >> 24));
}
zext_u32_to_u64 pass 9 lines
// glaurung: zext_u32_to_u64 @ 0x11d0
int zext_u32_to_u64(uint32_t arg0) {
    unsigned long r;
    // x86-64 prologue: save rbp
    r = arg0;
    r = (0x100000000 + r);
    // x86-64 epilogue: restore rbp
    return ((unsigned long)(r) >> 32);
}

clang -O2

28/28
add_wrap32 pass 5 lines
// glaurung: add_wrap32 @ 0x1230
int add_wrap32(int arg0, int arg1) {
    unsigned int r;
    return (unsigned int)((arg0 + arg1));
}
deposit_byte1 pass 5 lines
// glaurung: deposit_byte1 @ 0x11c0
int deposit_byte1(unsigned int arg0, unsigned int arg1) {
    unsigned int v;
    return (unsigned int)(((unsigned int)((unsigned short)(((unsigned long)((unsigned int)((arg1 << 8))) & 0xffff))) | (unsigned long)((unsigned int)((arg0 & -0xff01LL)))));
}
deposit_low_byte pass 5 lines
// glaurung: deposit_low_byte @ 0x11b0
int deposit_low_byte(unsigned int arg0, unsigned int arg1) {
    unsigned int v;
    return (unsigned int)(((unsigned int)((unsigned char)((arg1 & 255))) | (unsigned long)((unsigned int)((arg0 & -256)))));
}
extract_byte1 pass 4 lines
// glaurung: extract_byte1 @ 0x11d0
int extract_byte1(unsigned int arg0) {
    return (unsigned int)((unsigned char)((((unsigned long)(arg0) >> 8) & 255)));
}
extract_byte3 pass 4 lines
// glaurung: extract_byte3 @ 0x11e0
int extract_byte3(unsigned int arg0) {
    return (unsigned int)(((unsigned long)(arg0) >> 24));
}
mul_widen pass 6 lines
// glaurung: mul_widen @ 0x1250
int mul_widen(uint32_t arg0, uint32_t arg1) {
    unsigned long r;
    r = ((unsigned long)(arg1) * (unsigned long)(arg0));
    return (unsigned int)((((unsigned long)(r) >> 32) ^ r));
}
mul_wrap32 pass 5 lines
// glaurung: mul_wrap32 @ 0x1240
int mul_wrap32(unsigned int arg0, unsigned int arg1) {
    unsigned int r;
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) * arg1))) & 0x7fffffff));
}
reconstruct_64 pass 4 lines
// glaurung: reconstruct_64 @ 0x11f0
int reconstruct_64(uint32_t arg0, uint32_t arg1) {
    return (unsigned int)(((unsigned long)(arg0) - arg1));
}
rotl16_3 pass 6 lines
// glaurung: rotl16_3 @ 0x12f0
int rotl16_3(unsigned int arg0) {
    int var0;
    var0 = (unsigned int)((unsigned short)((arg0 & 0xffff)));
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var0)) >> 13))) + ((unsigned long)((unsigned int)((var0 & 0x1fff))) * 8)));
}
rotl32_7 pass 5 lines
// glaurung: rotl32_7 @ 0x12d0
int rotl32_7(uint32_t arg0) {
    unsigned int r;
    return (((unsigned long)(arg0) << 7) | ((unsigned long)(arg0) >> 25));
}
rotr32 pass 7 lines
// glaurung: rotr32 @ 0x12e0
int rotr32(uint32_t arg0, unsigned int arg1) {
    unsigned int r;
    long t41;
    t41 = ((unsigned long)(arg1) & 31);
    return (((unsigned long)(arg0) >> t41) | ((unsigned long)(arg0) << ((32 - t41) & 31)));
}
rt_u16 pass 4 lines
// glaurung: rt_u16 @ 0x1110
int rt_u16(unsigned int arg0) {
    return (unsigned int)((unsigned short)((arg0 & 0xffff)));
}
rt_u32 pass 4 lines
// glaurung: rt_u32 @ 0x1120
int rt_u32(unsigned int arg0) {
    return arg0;
}
rt_u64 pass 7 lines
// glaurung: rt_u64 @ 0x1130
int rt_u64(unsigned int arg0) {
    unsigned long v;
    long var3;
    var3 = (((unsigned long)(arg0) << 20) | (unsigned long)(arg0));
    return (unsigned int)((((unsigned long)(var3) >> 20) ^ (unsigned long)((unsigned int)((var3 & 0xffffff)))));
}
rt_u8 pass 4 lines
// glaurung: rt_u8 @ 0x1100
int rt_u8(unsigned int arg0) {
    return (unsigned int)((unsigned char)((arg0 & 255)));
}
sar_signed pass 4 lines
// glaurung: sar_signed @ 0x1200
int sar_signed(int arg0) {
    return (unsigned int)(((int)(arg0) >> 4));
}
sext_i16 pass 4 lines
// glaurung: sext_i16 @ 0x1160
int sext_i16(int arg0) {
    return (int)((short)((arg0 & 0xffff)));
}
sext_i8 pass 4 lines
// glaurung: sext_i8 @ 0x1150
int sext_i8(int arg0) {
    return (int)((signed char)((arg0 & 255)));
}
shr_unsigned pass 4 lines
// glaurung: shr_unsigned @ 0x1210
int shr_unsigned(unsigned int arg0) {
    return (unsigned int)(((unsigned long)(arg0) >> 4));
}
shr_via_cast pass 4 lines
// glaurung: shr_via_cast @ 0x1220
int shr_via_cast(int arg0) {
    return (unsigned int)(((unsigned long)((unsigned int)(arg0)) >> 1));
}
smul_high64 pass 4 lines
// glaurung: smul_high64 @ 0x1280
int64_t smul_high64(int64_t arg0, int64_t arg1) {
    return ((long)(((unsigned __int128)((__int128)(long)(arg1) * (__int128)(long)(arg0))) >> 64));
}
srem64 pass 9 lines
// glaurung: srem64 @ 0x12b0
int64_t srem64(int64_t arg0, int64_t arg1) {
    long var0;
    var0 = arg0;
    if ((((unsigned long)((arg0 | arg1)) >> 32) == 0)) {
        return (unsigned long)((unsigned int)(((unsigned int)(((((unsigned long long)(unsigned int)((unsigned long)((unsigned int)(0))) << 32) | (unsigned int)(var0)) % (unsigned int)(arg1))))));
    }
    return ((long)((((__int128)(long)(((long)(arg0) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(arg0)) % (long)(arg1)));
}
trunc_u16_after_mul pass 5 lines
// glaurung: trunc_u16_after_mul @ 0x11a0
int trunc_u16_after_mul(unsigned int arg0) {
    unsigned short v;
    return (unsigned int)((unsigned short)(((unsigned long)((unsigned int)((arg0 + (arg0 * 2)))) & 0xffff)));
}
trunc_u8 pass 4 lines
// glaurung: trunc_u8 @ 0x1190
int trunc_u8(unsigned int arg0) {
    return (unsigned int)((unsigned char)((arg0 & 255)));
}
umul_high64 pass 4 lines
// glaurung: umul_high64 @ 0x1270
uint64_t umul_high64(uint64_t arg0, uint64_t arg1) {
    return ((unsigned long)(((unsigned __int128)(unsigned long)(arg1) * (unsigned __int128)(unsigned long)(arg0)) >> 64));
}
urem64 pass 9 lines
// glaurung: urem64 @ 0x1290
uint64_t urem64(uint64_t arg0, uint64_t arg1) {
    long var0;
    var0 = arg0;
    if ((((unsigned long)((arg0 | arg1)) >> 32) == 0)) {
        return (unsigned long)((unsigned int)(((unsigned int)(((((unsigned long long)(unsigned int)((unsigned long)((unsigned int)(0))) << 32) | (unsigned int)(var0)) % (unsigned int)(arg1))))));
    }
    return ((unsigned long)(((((unsigned __int128)(unsigned long)((unsigned long)((unsigned int)(0))) << 64) | (unsigned long)(arg0)) % (unsigned long)(arg1))));
}
wrap_sub_u32 pass 5 lines
// glaurung: wrap_sub_u32 @ 0x1180
int wrap_sub_u32(uint32_t arg0, uint32_t arg1) {
    unsigned int r;
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) - arg1))) >> 24));
}
zext_u32_to_u64 pass 4 lines
// glaurung: zext_u32_to_u64 @ 0x1170
int zext_u32_to_u64(uint32_t arg0) {
    return 1;
}

gcc -O0

28/28
add_wrap32 pass 8 lines
// glaurung: add_wrap32 @ 0x1311
int add_wrap32(int arg0, int arg1) {
    unsigned int r;
    // x86-64 prologue: save rbp
    r = ((unsigned int)(arg1) + (unsigned int)(arg0));
    // x86-64 epilogue: restore rbp
    return r;
}
deposit_byte1 pass 9 lines
// glaurung: deposit_byte1 @ 0x124a
int deposit_byte1(unsigned int arg0, unsigned int arg1) {
    unsigned int v;
    // x86-64 prologue: save rbp
    v = arg0;
    v = ((unsigned int)((unsigned short)(((unsigned long)((unsigned int)((arg1 << 8))) & 0xffff))) | (unsigned int)((v & -0xff01LL)));
    // x86-64 epilogue: restore rbp
    return v;
}
deposit_low_byte pass 9 lines
// glaurung: deposit_low_byte @ 0x121f
int deposit_low_byte(unsigned int arg0, unsigned int arg1) {
    unsigned int v;
    // x86-64 prologue: save rbp
    v = arg0;
    v = ((unsigned int)((unsigned char)((arg1 & 255))) | (unsigned int)((v & -256)));
    // x86-64 epilogue: restore rbp
    return v;
}
extract_byte1 pass 6 lines
// glaurung: extract_byte1 @ 0x1278
int extract_byte1(unsigned int arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)((unsigned char)(((unsigned long)((unsigned int)(((unsigned long)(arg0) >> 8))) & 255)));
}
extract_byte3 pass 6 lines
// glaurung: extract_byte3 @ 0x128e
int extract_byte3(unsigned int arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)(arg0) >> 24));
}
mul_widen pass 8 lines
// glaurung: mul_widen @ 0x1351
int mul_widen(uint32_t arg0, uint32_t arg1) {
    unsigned long r;
    // x86-64 prologue: save rbp
    r = ((unsigned long)(arg1) * (unsigned long)(arg0));
    // x86-64 epilogue: restore rbp
    return (unsigned int)((r ^ (unsigned long)((unsigned int)(((unsigned long)(r) >> 32)))));
}
mul_wrap32 pass 8 lines
// glaurung: mul_wrap32 @ 0x132f
int mul_wrap32(unsigned int arg0, unsigned int arg1) {
    unsigned int r;
    // x86-64 prologue: save rbp
    r = (arg0 * arg1);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)(r) & 0x7fffffff));
}
reconstruct_64 pass 8 lines
// glaurung: reconstruct_64 @ 0x12a1
int reconstruct_64(uint32_t arg0, uint32_t arg1) {
    unsigned long v;
    // x86-64 prologue: save rbp
    v = ((unsigned long)(arg1) | ((unsigned long)(arg0) << 32));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(v) >> 32))) - (unsigned long)((unsigned int)(v))));
}
rotl16_3 pass 10 lines
// glaurung: rotl16_3 @ 0x14a6
int rotl16_3(unsigned int arg0) {
    unsigned short v;
    unsigned short r;
    // x86-64 prologue: save rbp
    v = arg0;
    r = ((((unsigned long)((unsigned short)((v & 0xffff))) >> 13) & 0xffff) | (unsigned long)((unsigned int)(((unsigned int)(v) << 3))));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(r);
}
rotl32_7 pass 8 lines
// glaurung: rotl32_7 @ 0x1467
int rotl32_7(uint32_t arg0) {
    unsigned int r;
    // x86-64 prologue: save rbp
    r = ((arg0 << 7) | ((unsigned int)(arg0) >> 25));
    // x86-64 epilogue: restore rbp
    return r;
}
rotr32 pass 11 lines
// glaurung: rotr32 @ 0x1480
int rotr32(uint32_t arg0, unsigned int arg1) {
    unsigned int r;
    long t41;
    // x86-64 prologue: save rbp
    arg1 = (arg1 & 31);
    t41 = ((unsigned long)(arg1) & 31);
    r = (((unsigned long)(arg0) >> t41) | (arg0 << ((32 - t41) & 31)));
    // x86-64 epilogue: restore rbp
    return r;
}
rt_u16 pass 8 lines
// glaurung: rt_u16 @ 0x1110
int rt_u16(unsigned int arg0) {
    unsigned short v;
    // x86-64 prologue: save rbp
    v = arg0;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(v);
}
rt_u32 pass 8 lines
// glaurung: rt_u32 @ 0x1128
int rt_u32(unsigned int arg0) {
    unsigned int v;
    // x86-64 prologue: save rbp
    v = arg0;
    // x86-64 epilogue: restore rbp
    return v;
}
rt_u64 pass 8 lines
// glaurung: rt_u64 @ 0x113e
int rt_u64(unsigned int arg0) {
    unsigned long v;
    // x86-64 prologue: save rbp
    v = ((unsigned long)(arg0) | ((unsigned long)(arg0) << 20));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)((v & 0xffffff))) ^ (unsigned long)((unsigned int)(((unsigned long)(v) >> 20)))));
}
rt_u8 pass 8 lines
// glaurung: rt_u8 @ 0x10f9
int rt_u8(unsigned int arg0) {
    unsigned char v;
    // x86-64 prologue: save rbp
    v = arg0;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(v);
}
sar_signed pass 6 lines
// glaurung: sar_signed @ 0x12d9
int sar_signed(int arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((int)(arg0) >> 4));
}
sext_i16 pass 8 lines
// glaurung: sext_i16 @ 0x118b
int sext_i16(int arg0) {
    short v;
    // x86-64 prologue: save rbp
    v = arg0;
    // x86-64 epilogue: restore rbp
    return v;
}
sext_i8 pass 8 lines
// glaurung: sext_i8 @ 0x1174
int sext_i8(int arg0) {
    signed char v;
    // x86-64 prologue: save rbp
    v = arg0;
    // x86-64 epilogue: restore rbp
    return v;
}
shr_unsigned pass 6 lines
// glaurung: shr_unsigned @ 0x12ec
int shr_unsigned(unsigned int arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)(arg0) >> 4));
}
shr_via_cast pass 6 lines
// glaurung: shr_via_cast @ 0x12ff
int shr_via_cast(int arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(arg0)) >> 1));
}
smul_high64 pass 6 lines
// glaurung: smul_high64 @ 0x13ce
int64_t smul_high64(int64_t arg0, int64_t arg1) {
    // x86-64 prologue: save rbp, frame 8 bytes
    // x86-64 epilogue: restore rbp
    return (((((long)(arg1) >> 63) * arg0) + (((long)(arg0) >> 63) * arg1)) + ((unsigned long)(((unsigned __int128)(unsigned long)(arg1) * (unsigned __int128)(unsigned long)(arg0)) >> 64)));
}
srem64 pass 6 lines
// glaurung: srem64 @ 0x1448
int64_t srem64(int64_t arg0, int64_t arg1) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return ((long)((((__int128)(long)(((long)(arg0) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(arg0)) % (long)(arg1)));
}
trunc_u16_after_mul pass 8 lines
// glaurung: trunc_u16_after_mul @ 0x11ff
int trunc_u16_after_mul(unsigned int arg0) {
    unsigned short v;
    // x86-64 prologue: save rbp
    v = ((unsigned long)((unsigned int)((arg0 + arg0))) + arg0);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(v);
}
trunc_u8 pass 6 lines
// glaurung: trunc_u8 @ 0x11ec
int trunc_u8(unsigned int arg0) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return (unsigned int)((unsigned char)(((unsigned long)(arg0) & 255)));
}
umul_high64 pass 6 lines
// glaurung: umul_high64 @ 0x137f
uint64_t umul_high64(uint64_t arg0, uint64_t arg1) {
    // x86-64 prologue: save rbp, frame 8 bytes
    // x86-64 epilogue: restore rbp
    return ((unsigned long)(((unsigned __int128)(unsigned long)(arg1) * (unsigned __int128)(unsigned long)(arg0)) >> 64));
}
urem64 pass 6 lines
// glaurung: urem64 @ 0x1426
uint64_t urem64(uint64_t arg0, uint64_t arg1) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return ((unsigned long)(((((unsigned __int128)(unsigned long)(0) << 64) | (unsigned long)(arg0)) % (unsigned long)(arg1))));
}
wrap_sub_u32 pass 8 lines
// glaurung: wrap_sub_u32 @ 0x11cd
int wrap_sub_u32(uint32_t arg0, uint32_t arg1) {
    unsigned int r;
    // x86-64 prologue: save rbp
    r = (arg0 - arg1);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)(r) >> 24));
}
zext_u32_to_u64 pass 9 lines
// glaurung: zext_u32_to_u64 @ 0x11a3
int zext_u32_to_u64(uint32_t arg0) {
    unsigned long r;
    // x86-64 prologue: save rbp
    r = arg0;
    r = (r + 0x100000000);
    // x86-64 epilogue: restore rbp
    return ((unsigned long)(r) >> 32);
}

gcc -O2

28/28
add_wrap32 pass 5 lines
// glaurung: add_wrap32 @ 0x1240
int add_wrap32(int arg0, int arg1) {
    unsigned int r;
    return (unsigned int)((arg0 + arg1));
}
deposit_byte1 pass 4 lines
// glaurung: deposit_byte1 @ 0x11c0
int deposit_byte1(unsigned int arg0, unsigned int arg1) {
    return (unsigned int)(((unsigned int)((unsigned short)(((unsigned long)((unsigned int)((arg1 << 8))) & 0xffff))) | (unsigned long)((unsigned int)((arg0 & -0xff01LL)))));
}
deposit_low_byte pass 4 lines
// glaurung: deposit_low_byte @ 0x11b0
int deposit_low_byte(unsigned int arg0, unsigned int arg1) {
    return (unsigned int)(((unsigned long)((unsigned int)((arg0 & -256))) | (unsigned int)((unsigned char)((arg1 & 255)))));
}
extract_byte1 pass 4 lines
// glaurung: extract_byte1 @ 0x11e0
int extract_byte1(unsigned int arg0) {
    return (unsigned int)((unsigned char)((((unsigned long)(arg0) >> 8) & 255)));
}
extract_byte3 pass 4 lines
// glaurung: extract_byte3 @ 0x11f0
int extract_byte3(unsigned int arg0) {
    return (unsigned int)(((unsigned long)(arg0) >> 24));
}
mul_widen pass 6 lines
// glaurung: mul_widen @ 0x1260
int mul_widen(uint32_t arg0, uint32_t arg1) {
    unsigned long r;
    r = ((unsigned long)(arg0) * (unsigned long)(arg1));
    return (unsigned int)((((unsigned long)(r) >> 32) ^ r));
}
mul_wrap32 pass 5 lines
// glaurung: mul_wrap32 @ 0x1250
int mul_wrap32(unsigned int arg0, unsigned int arg1) {
    unsigned int r;
    return (unsigned int)(((unsigned long)((unsigned int)((arg0 * arg1))) & 0x7fffffff));
}
reconstruct_64 pass 4 lines
// glaurung: reconstruct_64 @ 0x1200
int reconstruct_64(uint32_t arg0, uint32_t arg1) {
    return (unsigned int)(((unsigned long)(arg0) - arg1));
}
rotl16_3 pass 7 lines
// glaurung: rotl16_3 @ 0x12e0
int rotl16_3(unsigned int arg0) {
    unsigned short v;
    long t40;
    t40 = ((unsigned long)(arg0) & 0xffff);
    return (unsigned int)((unsigned short)((((t40 << 3) | ((unsigned long)(t40) >> 13)) & 0xffff)));
}
rotl32_7 pass 5 lines
// glaurung: rotl32_7 @ 0x12c0
int rotl32_7(uint32_t arg0) {
    unsigned int r;
    return (((unsigned long)(arg0) << 7) | ((unsigned long)(arg0) >> 25));
}
rotr32 pass 6 lines
// glaurung: rotr32 @ 0x12d0
int rotr32(uint32_t arg0, unsigned int arg1) {
    long t41;
    t41 = ((unsigned long)(arg1) & 31);
    return (((unsigned long)(arg0) >> t41) | ((unsigned long)(arg0) << ((32 - t41) & 31)));
}
rt_u16 pass 4 lines
// glaurung: rt_u16 @ 0x1110
int rt_u16(unsigned int arg0) {
    return (unsigned int)((unsigned short)((arg0 & 0xffff)));
}
rt_u32 pass 5 lines
// glaurung: rt_u32 @ 0x1120
int rt_u32(unsigned int arg0) {
    unsigned int v;
    return arg0;
}
rt_u64 pass 7 lines
// glaurung: rt_u64 @ 0x1130
int rt_u64(unsigned int arg0) {
    unsigned long v;
    long var3;
    var3 = (((unsigned long)(arg0) << 20) | (unsigned long)(arg0));
    return (unsigned int)(((unsigned long)((unsigned int)((var3 & 0xffffff))) ^ ((unsigned long)(var3) >> 20)));
}
rt_u8 pass 4 lines
// glaurung: rt_u8 @ 0x1100
int rt_u8(unsigned int arg0) {
    return (unsigned int)((unsigned char)((arg0 & 255)));
}
sar_signed pass 4 lines
// glaurung: sar_signed @ 0x1210
int sar_signed(int arg0) {
    return (unsigned int)(((int)(arg0) >> 4));
}
sext_i16 pass 4 lines
// glaurung: sext_i16 @ 0x1160
int sext_i16(int arg0) {
    return (int)((short)((arg0 & 0xffff)));
}
sext_i8 pass 4 lines
// glaurung: sext_i8 @ 0x1150
int sext_i8(int arg0) {
    return (int)((signed char)((arg0 & 255)));
}
shr_unsigned pass 4 lines
// glaurung: shr_unsigned @ 0x1220
int shr_unsigned(unsigned int arg0) {
    return (unsigned int)(((unsigned long)(arg0) >> 4));
}
shr_via_cast pass 4 lines
// glaurung: shr_via_cast @ 0x1230
int shr_via_cast(int arg0) {
    return (unsigned int)(((unsigned long)((unsigned int)(arg0)) >> 1));
}
smul_high64 pass 4 lines
// glaurung: smul_high64 @ 0x1290
int64_t smul_high64(int64_t arg0, int64_t arg1) {
    return ((long)(((unsigned __int128)((__int128)(long)(arg0) * (__int128)(long)(arg1))) >> 64));
}
srem64 pass 4 lines
// glaurung: srem64 @ 0x12b0
int64_t srem64(int64_t arg0, int64_t arg1) {
    return ((long)((((__int128)(long)(((long)(arg0) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(arg0)) % (long)(arg1)));
}
trunc_u16_after_mul pass 4 lines
// glaurung: trunc_u16_after_mul @ 0x11a0
int trunc_u16_after_mul(unsigned int arg0) {
    return (unsigned int)((unsigned short)(((unsigned long)((unsigned int)((arg0 + (arg0 * 2)))) & 0xffff)));
}
trunc_u8 pass 4 lines
// glaurung: trunc_u8 @ 0x1190
unsigned int trunc_u8(signed char arg0) {
    return (unsigned int)((unsigned char)((arg0 & 255)));
}
umul_high64 pass 4 lines
// glaurung: umul_high64 @ 0x1280
uint64_t umul_high64(uint64_t arg0, uint64_t arg1) {
    return ((unsigned long)(((unsigned __int128)(unsigned long)(arg0) * (unsigned __int128)(unsigned long)(arg1)) >> 64));
}
urem64 pass 4 lines
// glaurung: urem64 @ 0x12a0
uint64_t urem64(uint64_t arg0, uint64_t arg1) {
    return ((unsigned long)(((((unsigned __int128)(unsigned long)((unsigned long)((unsigned int)(0))) << 64) | (unsigned long)(arg0)) % (unsigned long)(arg1))));
}
wrap_sub_u32 pass 5 lines
// glaurung: wrap_sub_u32 @ 0x1180
int wrap_sub_u32(uint32_t arg0, uint32_t arg1) {
    unsigned int r;
    return (unsigned int)(((unsigned long)((unsigned int)((arg0 - arg1))) >> 24));
}
zext_u32_to_u64 pass 4 lines
// glaurung: zext_u32_to_u64 @ 0x1170
int zext_u32_to_u64(uint32_t arg0) {
    return 1;
}

← 213 fixtures