Fixture 144

inline asm

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

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

Inline assembly is a region the compiler does not model: the decompiler sees instructions with no source-level intent, and the constraints decide which registers are read, written and clobbered. Guarded per architecture with a portable fallback so every lane of the cross-architecture matrix builds.

tests/decompiler_fixtures/src/144_inline_asm.c source
#include <stdint.h>

/* Inline assembly is a region the compiler does not model: the decompiler sees
 * instructions with no source-level intent, and the constraints decide which
 * registers are read, written and clobbered. Guarded per architecture with a
 * portable fallback so every lane of the cross-architecture matrix builds. */

__attribute__((noinline)) int32_t asm_add_via_constraints(int32_t left,
                                                          int32_t right) {
#if defined(__x86_64__) || defined(__i386__)
    int32_t result = left;
    __asm__("addl %1, %0" : "+r"(result) : "r"(right) : "cc");
    return result;
#elif defined(__aarch64__)
    int32_t result;
    __asm__("add %w0, %w1, %w2" : "=r"(result) : "r"(left), "r"(right));
    return result;
#elif defined(__arm__)
    int32_t result;
    __asm__("add %0, %1, %2" : "=r"(result) : "r"(left), "r"(right));
    return result;
#else
    return (int32_t)((uint32_t)left + (uint32_t)right);
#endif
}

__attribute__((noinline)) int32_t asm_memory_barrier(int32_t *cell,
                                                     int32_t value) {
    if (cell == 0) {
        return -1;
    }
    *cell = value;
    /* A full compiler barrier: no memory operation may be moved across it. */
    __asm__ __volatile__("" ::: "memory");
    *cell += 1;
    return *cell;
}

__attribute__((noinline)) int32_t builtin_bit_intrinsics(uint32_t value,
                                                         int32_t which) {
    switch (which & 3) {
    case 0:
        /* clz is undefined at zero, so the zero case is spelled out. */
        return (value == 0u) ? 32 : __builtin_clz(value);
    case 1:
        return (value == 0u) ? 32 : __builtin_ctz(value);
    case 2:
        return (int32_t)__builtin_popcount(value);
    default:
        return (int32_t)__builtin_bswap32(value);
    }
}

__attribute__((noinline)) int32_t builtin_overflow_checked(int32_t left,
                                                           int32_t right,
                                                           int32_t *result) {
    if (result == 0) {
        return -1;
    }
    /* Returns 1 on overflow without ever executing signed overflow itself. */
    if (__builtin_add_overflow(left, right, result)) {
        *result = 0;
        return 1;
    }
    return 0;
}

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
asm_add_via_constraints pass 9 lines
// glaurung: asm_add_via_constraints @ 0x1100
int32_t asm_add_via_constraints(int32_t arg0, int32_t arg1) {
    int result;
    // x86-64 prologue: save rbp
    result = arg0;
    result = ((unsigned int)(result) + (unsigned int)(arg1));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(result);
}
asm_memory_barrier pass 11 lines
// glaurung: asm_memory_barrier @ 0x1120
int32_t asm_memory_barrier(int32_t * arg0, int32_t arg1) {
    // x86-64 prologue: save rbp
    if ((arg0 != 0)) {
        *(int *)((long)arg0) = arg1;
        *(int *)((long)arg0) = ((unsigned long)((unsigned int)(*(int *)((long)arg0))) + 1);
        return (unsigned int)(*(int *)((long)arg0));
    } else {
        return (unsigned int)(-1);
    }
}
builtin_bit_intrinsics pass 25 lines
// glaurung: builtin_bit_intrinsics @ 0x1170
int32_t builtin_bit_intrinsics(uint32_t arg0, int32_t arg1) {
    int local_10;
    int var1;
    long var27;
    int var36;
    // 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) != 0) ? ((31 - (((unsigned int)((unsigned long)((unsigned int)((unsigned long)(arg0)))) == 0) ? 32 : __builtin_clz((unsigned int)((unsigned long)((unsigned int)((unsigned long)(arg0))))))) ^ 31) : 32);
    } else {
        if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_10)) - 1))) == 0)) {
            return (unsigned int)(((unsigned long)(arg0) != 0) ? (31 - (((unsigned int)(((unsigned long)((unsigned int)((unsigned long)(arg0))) ^ ((unsigned long)((unsigned int)((unsigned long)(arg0))) - 1))) == 0) ? 32 : __builtin_clz((unsigned int)(((unsigned long)((unsigned int)((unsigned long)(arg0))) ^ ((unsigned long)((unsigned int)((unsigned long)(arg0))) - 1)))))) : 32);
        } else {
            if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_10)) - 2))) == 0)) {
                var27 = (unsigned long)((unsigned int)((arg0 - (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned int)(arg0) >> 1))) & 0x55555555))))));
                var36 = ((unsigned int)(((unsigned long)((unsigned int)(var27)) & 0x33333333)) + (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var27)) >> 2))) & 0x33333333)));
                return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var36)) + (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var36)) >> 4)))))) & 0xf0f0f0f))) * 0x1010101))) >> 24));
            } else {
                return (unsigned int)((((((arg0 & 255) << 24) | (((arg0 >> 8) & 255) << 16)) | (((arg0 >> 16) & 255) << 8)) | ((arg0 >> 24) & 255)));
            }
        }
    }
}
builtin_overflow_checked pass 19 lines
// glaurung: builtin_overflow_checked @ 0x1260
int32_t builtin_overflow_checked(int32_t arg0, int32_t arg1, int32_t * arg2) {
    long t143;
    int var3;
    // x86-64 prologue: save rbp
    if ((arg2 != 0)) {
        t143 = ((long)(arg0) < 0);
        var3 = ((unsigned int)(arg0) + (unsigned int)(arg1));
        *(int *)((long)arg2) = var3;
        if (((t143 == ((long)(arg1) < 0)) && (((long)((int)(var3)) < 0) != t143))) {
            *(int *)((long)arg2) = 0;
            return 1;
        } else {
            return 0;
        }
    } else {
        return (unsigned int)(-1);
    }
}

clang -O2

4/4
asm_add_via_constraints pass 4 lines
// glaurung: asm_add_via_constraints @ 0x1100
int32_t asm_add_via_constraints(int32_t arg0, int32_t arg1) {
    return (unsigned int)(((unsigned long)((unsigned int)(arg0)) + arg1));
}
asm_memory_barrier pass 11 lines
// glaurung: asm_memory_barrier @ 0x1110
int32_t asm_memory_barrier(int32_t * arg0, int32_t arg1) {
    int var1;
    if ((arg0 == 0)) {
        return 0xffffffff;
    }
    *(int *)(((long)arg0)) = arg1;
    var1 = ((unsigned int)(*(int *)(((long)arg0))) + 1);
    *(int *)(((long)arg0)) = var1;
    return (unsigned int)(var1);
}
builtin_bit_intrinsics pass 27 lines
// glaurung: builtin_bit_intrinsics @ 0x1130
int32_t builtin_bit_intrinsics(uint32_t arg0, int32_t arg1) {
    long var1;
    long var11;
    int var20;
    var1 = (unsigned long)((unsigned int)((arg1 & 3)));
    if (((unsigned long)((unsigned int)(var1)) != 2)) {
        if (((unsigned long)((unsigned int)(var1)) == 1)) {
            goto L_117f;
        }
        if (((unsigned long)((unsigned int)(var1)) != 0)) {
            return (unsigned int)((((((arg0 & 255) << 24) | (((arg0 >> 8) & 255) << 16)) | (((arg0 >> 16) & 255) << 8)) | ((arg0 >> 24) & 255)));
        }
        if ((arg0 == 0)) {
            return 32;
        }
        return (unsigned int)(((31 - (((unsigned int)((unsigned long)(arg0)) == 0) ? 32 : __builtin_clz((unsigned int)((unsigned long)(arg0))))) ^ 31));
    }
    var11 = (unsigned long)((unsigned int)((arg0 - (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned int)(arg0) >> 1))) & 0x55555555))))));
    var20 = ((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var11)) >> 2))) & 0x33333333)) + (unsigned int)(((unsigned long)((unsigned int)(var11)) & 0x33333333)));
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var20)) >> 4))) + (unsigned long)((unsigned int)(var20))))) & 0xf0f0f0f))) * 0x1010101))) >> 24));
    L_117f: ;
    if ((arg0 == 0)) {
        return 32;
    }
    return (31 - (((unsigned int)(((unsigned long)(arg0) ^ ((unsigned long)(arg0) - 1))) == 0) ? 32 : __builtin_clz((unsigned int)(((unsigned long)(arg0) ^ ((unsigned long)(arg0) - 1))))));
}
builtin_overflow_checked pass 12 lines
// glaurung: builtin_overflow_checked @ 0x11a0
int32_t builtin_overflow_checked(int32_t arg0, int32_t arg1, int32_t * arg2) {
    long t33;
    int var4;
    if ((arg2 == 0)) {
        return 0xffffffff;
    }
    t33 = ((long)(arg0) < 0);
    var4 = (arg0 + arg1);
    *(int *)(((long)arg2)) = (((t33 == ((long)(arg1) < 0)) & (((long)((int)(var4)) < 0) != t33)) ? 0 : (unsigned long)((unsigned int)(var4)));
    return (((t33 == ((long)(arg1) < 0)) & (((long)((int)(var4)) < 0) != t33)) & 255);
}

gcc -O0

4/4
asm_add_via_constraints pass 9 lines
// glaurung: asm_add_via_constraints @ 0x10f9
int32_t asm_add_via_constraints(int32_t arg0, int32_t arg1) {
    int result;
    // x86-64 prologue: save rbp
    result = arg0;
    result = ((unsigned int)(result) + (unsigned int)(arg1));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(result);
}
asm_memory_barrier pass 11 lines
// glaurung: asm_memory_barrier @ 0x111d
int32_t asm_memory_barrier(int32_t * arg0, int32_t arg1) {
    // x86-64 prologue: save rbp
    if ((arg0 != 0)) {
        *(int *)((long)arg0) = arg1;
        *(int *)((long)arg0) = ((unsigned long)((unsigned int)(*(int *)((long)arg0))) + 1);
        return (unsigned int)(*(int *)((long)arg0));
    } else {
        return 0xffffffff;
    }
}
builtin_bit_intrinsics pass 37 lines
// glaurung: builtin_bit_intrinsics @ 0x115a
int32_t builtin_bit_intrinsics(uint32_t arg0, int32_t arg1) {
    extern unsigned long __popcountdi2(unsigned long);
    long var2;
    unsigned long var4;
    long var7;
    // x86-64 prologue: save rbp, frame 16 bytes
    var2 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & 3)));
    if (((unsigned long)((unsigned int)(var2)) == 2)) {
        var4 = __popcountdi2(arg0);
        return var4;
    } else {
        if (((((unsigned long)((unsigned int)(var2)) == 2) | ((long)((int)(var2)) < 2)) == 0)) {
            var7 = (unsigned int)((((((arg0 & 255) << 24) | (((arg0 >> 8) & 255) << 16)) | (((arg0 >> 16) & 255) << 8)) | ((arg0 >> 24) & 255)));
            // x86-64 epilogue: restore rbp
            return var7;
        }
        if (((unsigned long)((unsigned int)(var2)) == 0)) {
            if ((arg0 == 0)) {
                return 32;
            } else {
                return (unsigned int)(((31 - (((unsigned int)((unsigned long)(arg0)) == 0) ? 32 : __builtin_clz((unsigned int)((unsigned long)(arg0))))) ^ 31));
            }
        } else {
            if (((unsigned long)((unsigned int)(var2)) == 1)) {
                if ((arg0 == 0)) {
                    return 32;
                } else {
                    return (((unsigned int)((unsigned long)(arg0)) == 0) ? 32 : __builtin_ctz((unsigned int)((unsigned long)(arg0))));
                }
            } else {
                var7 = (unsigned int)((((((arg0 & 255) << 24) | (((arg0 >> 8) & 255) << 16)) | (((arg0 >> 16) & 255) << 8)) | ((arg0 >> 24) & 255)));
                return var7;
            }
        }
    }
}
builtin_overflow_checked pass 26 lines
// glaurung: builtin_overflow_checked @ 0x11c7
int32_t builtin_overflow_checked(int32_t arg0, int32_t arg1, int32_t * arg2) {
    long t142;
    int var0;
    int var3;
    long var4;
    // x86-64 prologue: save rbp
    if ((arg2 != 0)) {
        var0 = 0;
        t142 = ((long)(arg1) < 0);
        var3 = ((unsigned int)(arg1) + (unsigned int)(arg0));
        var4 = (unsigned long)((unsigned int)(var3));
        if ((((t142 == ((long)(arg0) < 0)) & (((long)((int)(var3)) < 0) != t142)) != 0)) {
            var0 = 1;
        }
        *(int *)((long)arg2) = var4;
        if (((unsigned long)((unsigned char)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var0)) & 1))) & 255))) == 0)) {
            return 0;
        } else {
            *(int *)((long)arg2) = 0;
            return 1;
        }
    } else {
        return 0xffffffff;
    }
}

gcc -O2

4/4
asm_add_via_constraints pass 4 lines
// glaurung: asm_add_via_constraints @ 0x1100
int32_t asm_add_via_constraints(int32_t arg0, int32_t arg1) {
    return (unsigned int)(((unsigned long)((unsigned int)(arg0)) + arg1));
}
asm_memory_barrier pass 11 lines
// glaurung: asm_memory_barrier @ 0x1110
int32_t asm_memory_barrier(int32_t * arg0, int32_t arg1) {
    int var1;
    if ((arg0 == 0)) {
        return 0xffffffff;
    }
    *(int *)(((long)arg0)) = arg1;
    var1 = ((unsigned int)(*(int *)(((long)arg0))) + 1);
    *(int *)(((long)arg0)) = var1;
    return (unsigned int)(var1);
}
builtin_bit_intrinsics pass 23 lines
// glaurung: builtin_bit_intrinsics @ 0x1130
int32_t builtin_bit_intrinsics(uint32_t arg0, int32_t arg1) {
    extern unsigned long __popcountdi2(unsigned long);
    unsigned long ret;
    long var1;
    var1 = (unsigned long)((unsigned int)((arg1 & 3)));
    if (((unsigned long)((unsigned int)(var1)) == 1)) {
        return (((unsigned long)(arg0) == 0) ? 32 : (((unsigned int)((unsigned long)(arg0)) == 0) ? 32 : __builtin_ctz((unsigned int)((unsigned long)(arg0)))));
    }
    if (((unsigned long)((unsigned int)(var1)) == 2)) {
        ret = __popcountdi2(arg0);
        return ret;
    }
    ret = (unsigned int)((((((arg0 & 255) << 24) | (((arg0 >> 8) & 255) << 16)) | (((arg0 >> 16) & 255) << 8)) | ((arg0 >> 24) & 255)));
    if (((unsigned long)((unsigned int)(var1)) != 0)) {
        return ret;
    }
    ret = 32;
    if ((arg0 != 0)) {
        return (unsigned int)(((31 - (((unsigned int)((unsigned long)(arg0)) == 0) ? 32 : __builtin_clz((unsigned int)((unsigned long)(arg0))))) ^ 31));
    }
    return 32;
}
builtin_overflow_checked pass 14 lines
// glaurung: builtin_overflow_checked @ 0x1190
int32_t builtin_overflow_checked(int32_t arg0, int32_t arg1, int32_t * arg2) {
    long ret;
    long t33;
    int var2;
    if ((arg2 == 0)) {
        return 0xffffffff;
    }
    t33 = ((long)(arg0) < 0);
    var2 = (arg0 + arg1);
    ret = (((t33 == ((long)(arg1) < 0)) & (((long)((int)(var2)) < 0) != t33)) & 255);
    *(int *)(((long)arg2)) = (((unsigned long)((unsigned int)(ret)) != 0) ? 0 : (unsigned long)((unsigned int)(var2)));
    return ret;
}

← 213 fixtures