Fixture 68

thermodynamics

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

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

Ideal-gas pressure, Newton's law of cooling over discrete steps, and a mixing temperature. The cooling loop is a geometric decay whose factor is recomputed each step from two parameters.

tests/decompiler_fixtures/src/68_thermodynamics.c source
#include <stdint.h>

/* Ideal-gas pressure, Newton's law of cooling over discrete steps, and a
 * mixing temperature.  The cooling loop is a geometric decay whose factor is
 * recomputed each step from two parameters. */

#define THERMO_STEPS_MAX 24

static int32_t thermo_mul_q16(int32_t left, int32_t right) {
    return (int32_t)(((int64_t)left * (int64_t)right) >> 16);
}

static int32_t thermo_div_q16(int32_t numerator, int32_t denominator) {
    if (denominator == 0) {
        return 0;
    }
    return (int32_t)(((int64_t)numerator << 16) / (int64_t)denominator);
}

__attribute__((noinline)) int32_t
ideal_gas_pressure(int32_t moles, int32_t temperature, int32_t volume) {
    int32_t gas_constant = 544807; /* 8.314 in Q16.16 */
    int32_t numerator;
    if (volume <= 0 || moles < 0 || temperature < 0) {
        return 0;
    }
    numerator = thermo_mul_q16(thermo_mul_q16(moles, gas_constant), temperature);
    return thermo_div_q16(numerator, volume);
}

__attribute__((noinline)) int32_t
newton_cooling(int32_t temperature, int32_t ambient, int32_t rate,
               int32_t steps) {
    int32_t step;
    if (steps < 0 || steps > THERMO_STEPS_MAX || rate < 0 || rate > 65536) {
        return temperature;
    }
    for (step = 0; step < steps; ++step) {
        int32_t difference = temperature - ambient;
        temperature -= thermo_mul_q16(rate, difference);
    }
    return temperature;
}

__attribute__((noinline)) int32_t
mixing_temperature(int32_t mass_a, int32_t temperature_a, int32_t mass_b,
                   int32_t temperature_b) {
    int32_t total = mass_a + mass_b;
    int32_t weighted;
    if (mass_a < 0 || mass_b < 0 || total <= 0) {
        return 0;
    }
    weighted = thermo_mul_q16(mass_a, temperature_a) +
               thermo_mul_q16(mass_b, temperature_b);
    return thermo_div_q16(weighted, total);
}

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
ideal_gas_pressure pass 32 lines
// glaurung: ideal_gas_pressure @ 0x1100
int32_t ideal_gas_pressure(int32_t arg0, int32_t arg1, int32_t arg2) {
    extern int thermo_div_q16(int, int);
    extern int thermo_mul_q16(int, int);
    int gas_constant;
    int numerator;
    int local_4;
    int var0;
    int var2;
    int var4;
    // x86-64 prologue: save rbp, frame 32 bytes
    gas_constant = 0x85027;
    if ((((unsigned long)((unsigned int)(arg2)) == 0) | ((long)(arg2) < 0))) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if (((long)(arg0) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if (((long)(arg1) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    var0 = thermo_mul_q16((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(gas_constant)));
    var2 = thermo_mul_q16((unsigned long)((unsigned int)(var0)), (unsigned long)((unsigned int)(arg1)));
    numerator = var2;
    var4 = thermo_div_q16((unsigned long)((unsigned int)(numerator)), (unsigned long)((unsigned int)(arg2)));
    local_4 = var4;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
mixing_temperature pass 34 lines
// glaurung: mixing_temperature @ 0x1280
int32_t mixing_temperature(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern int thermo_div_q16(int, int);
    extern int thermo_mul_q16(int, int);
    int total;
    int weighted;
    int local_20;
    int local_4;
    int var11;
    int var3;
    int var5;
    // x86-64 prologue: save rbp, frame 32 bytes
    total = ((unsigned int)(arg0) + arg2);
    if (((long)(arg0) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if (((long)(arg2) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if (((((unsigned long)((unsigned int)(total)) == 0) | ((long)(total) < 0)) != 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    var3 = thermo_mul_q16((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)));
    local_20 = var3;
    var5 = thermo_mul_q16((unsigned long)((unsigned int)(arg2)), (unsigned long)((unsigned int)(arg3)));
    weighted = ((unsigned int)(local_20) + (unsigned int)(var5));
    var11 = thermo_div_q16((unsigned long)((unsigned int)(weighted)), (unsigned long)((unsigned int)(total)));
    local_4 = var11;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
newton_cooling pass 37 lines
// glaurung: newton_cooling @ 0x11e0
int32_t newton_cooling(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern int thermo_mul_q16(int, int);
    int step;
    int difference;
    int local_4;
    int var6;
    // x86-64 prologue: save rbp, frame 32 bytes
    if (((long)(arg3) < 0)) {
        local_4 = arg0;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((((unsigned long)((unsigned int)(arg3)) == 24) | ((long)(arg3) < 24)) == 0)) {
        local_4 = arg0;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((long)(arg2) < 0)) {
        local_4 = arg0;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((((unsigned long)((unsigned int)(arg2)) == 0x10000) | ((long)(arg2) < 0x10000)) == 0)) {
        local_4 = arg0;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    for (step = 0; (step < arg3); step++) {
        difference = ((unsigned int)(arg0) - arg1);
        var6 = thermo_mul_q16((unsigned long)((unsigned int)(arg2)), (unsigned long)((unsigned int)(difference)));
        arg0 = ((unsigned int)(arg0) - (unsigned int)(var6));
    }
    local_4 = arg0;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}

clang -O2

3/3
ideal_gas_pressure pass 21 lines
// glaurung: ideal_gas_pressure @ 0x1100
int32_t ideal_gas_pressure(int32_t arg0, int32_t arg1, int32_t arg2) {
    long ret;
    long var11;
    long var13;
    long var14;
    ret = 0;
    if (((long)((int)(((unsigned long)((unsigned int)(arg1)) | arg0))) < 0)) {
        return ret;
    }
    if ((((unsigned long)((unsigned int)(arg2)) == 0) | ((long)(arg2) < 0))) {
        return ret;
    }
    var11 = ((long)((((long)(arg1) * ((long)((0x850270000 * (long)(arg0))) >> 32)) << 16)) >> 16);
    var13 = (var11 & -0x10000LL);
    var14 = (unsigned long)((unsigned int)(arg2));
    if ((((unsigned long)(var11) >> 32) == 0)) {
        return ((unsigned int)(((((unsigned long long)(unsigned int)((unsigned long)((unsigned int)(0))) << 32) | (unsigned int)(var13)) / (unsigned int)(var14))));
    }
    return ((long)((((__int128)(long)(((long)(var13) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(var13)) / (long)((unsigned long)((unsigned int)(arg2)))));
}
mixing_temperature pass 22 lines
// glaurung: mixing_temperature @ 0x11f0
int32_t mixing_temperature(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    int total;
    long ret;
    long var16;
    long var17;
    long var4;
    ret = 0;
    if (((long)((int)(((unsigned long)((unsigned int)(arg2)) | arg0))) < 0)) {
        return ret;
    }
    var4 = (unsigned long)((unsigned int)((arg2 + arg0)));
    if ((((unsigned long)((unsigned int)(var4)) == 0) | ((long)((int)(var4)) < 0))) {
        return ret;
    }
    var16 = ((long)((int)((((unsigned long)(((long)(arg3) * (long)(arg2))) >> 16) + ((unsigned long)(((long)(arg1) * (long)(arg0))) >> 16)))) << 16);
    var17 = (unsigned long)((unsigned int)(var4));
    if ((((unsigned long)(var16) >> 32) == 0)) {
        return ((unsigned int)(((((unsigned long long)(unsigned int)((unsigned long)((unsigned int)(0))) << 32) | (unsigned int)(var16)) / (unsigned int)(var17))));
    }
    return ((long)((((__int128)(long)(((long)(var16) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(var16)) / (long)((unsigned long)((unsigned int)(var4)))));
}
newton_cooling pass 49 lines
// glaurung: newton_cooling @ 0x1150
int32_t newton_cooling(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    int difference;
    int step;
    long ret;
    long var0;
    long var1;
    long var15;
    long var23;
    long var31;
    int var39;
    long var4;
    int var47;
    long var5;
    long var7;
    ret = (unsigned long)((unsigned int)(arg0));
    var0 = (unsigned long)((unsigned int)((arg3 - 1)));
    if (((unsigned long)((unsigned long)((unsigned int)(var0))) <= (unsigned long)(23))) {
        if (((unsigned long)(0x10000) < (unsigned long)((unsigned long)((unsigned int)(arg2))))) {
            return ret;
        }
        var1 = (unsigned long)((unsigned int)(arg2));
        var4 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg3)) & 3)));
        var5 = (unsigned long)((unsigned int)(arg0));
        if (((unsigned long)(3) <= (unsigned long)((unsigned long)((unsigned int)(var0))))) {
            var7 = (unsigned long)((unsigned int)((arg3 & -4)));
            do {
                var15 = (unsigned long)((unsigned int)((ret - ((unsigned long)(((long)((int)(((unsigned long)((unsigned int)(ret)) - arg1))) * var1)) >> 16))));
                var23 = (unsigned long)((unsigned int)((var15 - ((unsigned long)(((long)((int)(((unsigned long)((unsigned int)(var15)) - arg1))) * var1)) >> 16))));
                var31 = (unsigned long)((unsigned int)((var23 - ((unsigned long)(((long)((int)(((unsigned long)((unsigned int)(var23)) - arg1))) * var1)) >> 16))));
                ret = (unsigned long)((unsigned int)((var31 - ((unsigned long)(((long)((int)(((unsigned long)((unsigned int)(var31)) - arg1))) * var1)) >> 16))));
                var39 = (var7 - 4);
                var7 = (unsigned long)((unsigned int)(var39));
                var5 = ret;
            } while (((unsigned long)((unsigned int)(var39)) != 0));
        }
        ret = var5;
        if (((unsigned long)((unsigned int)(var4)) == 0)) {
            return ret;
        }
        do {
            var5 = (unsigned long)((unsigned int)((var5 - ((unsigned long)(((long)((int)(((unsigned long)((unsigned int)(var5)) - arg1))) * var1)) >> 16))));
            var47 = (var4 - 1);
            var4 = (unsigned long)((unsigned int)(var47));
            ret = var5;
        } while (((unsigned long)((unsigned int)(var47)) != 0));
    }
    return ret;
}

gcc -O0

3/3
ideal_gas_pressure pass 30 lines
// glaurung: ideal_gas_pressure @ 0x114d
int32_t ideal_gas_pressure(int32_t arg0, int32_t arg1, int32_t arg2) {
    extern int thermo_div_q16(int, int);
    extern int thermo_mul_q16(int, int);
    int gas_constant;
    int numerator;
    int ret;
    int var2;
    int var6;
    // x86-64 prologue: save rbp, frame 32 bytes
    gas_constant = 0x85027;
    if ((((unsigned long)((unsigned int)(arg2)) == 0) | ((long)(arg2) < 0))) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if (((long)(arg0) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if (((long)(arg1) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    var2 = thermo_mul_q16((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(gas_constant)));
    var6 = thermo_mul_q16((unsigned long)((unsigned int)(var2)), (unsigned long)((unsigned int)(arg1)));
    numerator = var6;
    ret = thermo_div_q16((unsigned long)((unsigned int)(numerator)), (unsigned long)((unsigned int)(arg2)));
    // x86-64 epilogue: restore rbp
    return ret;
}
mixing_temperature pass 32 lines
// glaurung: mixing_temperature @ 0x1220
int32_t mixing_temperature(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern int thermo_div_q16(int, int);
    extern int thermo_mul_q16(int, int);
    int total;
    int weighted;
    int ret;
    int var12;
    int var7;
    long var9;
    // x86-64 prologue: save rbp, frame 8 bytes
    total = ((unsigned int)(arg2) + (unsigned int)(arg0));
    if (((long)(arg0) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if (((long)(arg2) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if (((((unsigned long)((unsigned int)(total)) == 0) | ((long)(total) < 0)) != 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    var7 = thermo_mul_q16((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)));
    var9 = (unsigned long)((unsigned int)(var7));
    var12 = thermo_mul_q16((unsigned long)((unsigned int)(arg2)), (unsigned long)((unsigned int)(arg3)));
    weighted = (var12 + var9);
    ret = thermo_div_q16((unsigned long)((unsigned int)(weighted)), (unsigned long)((unsigned int)(total)));
    // x86-64 epilogue: restore rbp
    return ret;
}
newton_cooling pass 31 lines
// glaurung: newton_cooling @ 0x11b3
int32_t newton_cooling(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern int thermo_mul_q16(int, int);
    int step;
    int difference;
    int var6;
    // x86-64 prologue: save rbp, frame 32 bytes
    if (((long)(arg3) < 0)) {
        // x86-64 epilogue: restore rbp
        return (unsigned int)(arg0);
    }
    if (((((unsigned long)((unsigned int)(arg3)) == 24) | ((long)(arg3) < 24)) == 0)) {
        // x86-64 epilogue: restore rbp
        return (unsigned int)(arg0);
    }
    if (((long)(arg2) < 0)) {
        // x86-64 epilogue: restore rbp
        return (unsigned int)(arg0);
    }
    if (((((unsigned long)((unsigned int)(arg2)) == 0x10000) | ((long)(arg2) < 0x10000)) == 0)) {
        // x86-64 epilogue: restore rbp
        return (unsigned int)(arg0);
    }
    for (step = 0; (step < arg3); step++) {
        difference = ((unsigned int)(arg0) - arg1);
        var6 = thermo_mul_q16((unsigned long)((unsigned int)(arg2)), (unsigned long)((unsigned int)(difference)));
        arg0 = (arg0 - var6);
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(arg0);
}

gcc -O2

3/3
ideal_gas_pressure pass 11 lines
// glaurung: ideal_gas_pressure @ 0x1100
int32_t ideal_gas_pressure(int32_t arg0, int32_t arg1, int32_t arg2) {
    long var13;
    if ((0 <= (long)((int)(((unsigned long)((unsigned int)(arg0)) | arg1))))) {
        if (((((unsigned long)((unsigned int)(arg2)) == 0) | ((long)(arg2) < 0)) == 0)) {
            var13 = ((long)((int)(((long)(((long)((int)(((long)(((long)(arg0) * 0x85027)) >> 16))) * (long)(arg1))) >> 16))) << 16);
            return ((long)((((__int128)(long)(((long)(var13) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(var13)) / (long)((long)(arg2))));
        }
    }
    return 0;
}
mixing_temperature pass 13 lines
// glaurung: mixing_temperature @ 0x11a0
int32_t mixing_temperature(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    int total;
    long var17;
    total = (unsigned long)((unsigned int)((arg0 + arg2)));
    if ((0 <= (long)((int)(((unsigned long)((unsigned int)(arg0)) | arg2))))) {
        if (((((unsigned long)((unsigned int)(total)) == 0) | ((long)(total) < 0)) == 0)) {
            var17 = ((long)((int)((((long)(((long)(arg2) * (long)(arg3))) >> 16) + ((long)(((long)(arg0) * (long)(arg1))) >> 16)))) << 16);
            return ((long)((((__int128)(long)(((long)(var17) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(var17)) / (long)((long)(total))));
        }
    }
    return 0;
}
newton_cooling pass 22 lines
// glaurung: newton_cooling @ 0x1150
int32_t newton_cooling(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    int step;
    int difference;
    long var0;
    long var2;
    int var7;
    var0 = (unsigned long)((unsigned int)(arg0));
    if (((unsigned long)((unsigned long)((unsigned int)(arg2))) <= (unsigned long)(0x10000))) {
        if (((unsigned long)(23) < (unsigned long)((unsigned long)((unsigned int)((arg3 - 1)))))) {
            return (unsigned int)(var0);
        }
        var2 = (long)(arg2);
        step = 0;
        do {
            var7 = (step + 1);
            step = (unsigned long)((unsigned int)(var7));
            var0 = (unsigned long)((unsigned int)((var0 - ((long)(((long)((int)(((unsigned long)((unsigned int)(var0)) - arg1))) * var2)) >> 16))));
        } while (((unsigned int)(arg3) != (unsigned int)(var7)));
    }
    return (unsigned int)(var0);
}

← 213 fixtures