Fixture 65

projectile motion

C · 2 functions · 4 lanes · 7 of 8 function-lanes behave identically

One lane has a function that returns a different result after decompilation: gcc-O2 (1/2).

Ballistic trajectory in Q16.16: position and velocity integrated under constant gravity, with an impact test. Two coupled state variables update per step, the classic physics-loop shape.

tests/decompiler_fixtures/src/65_projectile_motion.c source
#include <stdint.h>

/* Ballistic trajectory in Q16.16: position and velocity integrated under
 * constant gravity, with an impact test.  Two coupled state variables update
 * per step, the classic physics-loop shape. */

#define KIN_STEPS_MAX 32
#define KIN_GRAVITY 642245 /* 9.8 m/s^2 in Q16.16 */

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

__attribute__((noinline)) int32_t
projectile_step(int32_t initial_height, int32_t initial_velocity,
                int32_t timestep, int32_t steps, int32_t *impact_step) {
    int32_t height = initial_height;
    int32_t velocity = initial_velocity;
    int32_t step;
    if (impact_step == 0 || steps < 0 || steps > KIN_STEPS_MAX ||
        timestep <= 0 || timestep > 65536) {
        return 0;
    }
    *impact_step = -1;
    for (step = 0; step < steps; ++step) {
        velocity -= kin_mul_q16(KIN_GRAVITY, timestep);
        height += kin_mul_q16(velocity, timestep);
        if (height <= 0) {
            *impact_step = step;
            height = 0;
            velocity = 0;
            break;
        }
    }
    return height;
}

__attribute__((noinline)) int32_t
kinetic_energy(int32_t mass, int32_t velocity) {
    int32_t square = kin_mul_q16(velocity, velocity);
    return kin_mul_q16(mass, square) / 2;
}

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.

gcc -O2

1/2
kinetic_energy pass 6 lines
// glaurung: kinetic_energy @ 0x11b0
int32_t kinetic_energy(int32_t arg0, int32_t arg1) {
    long var6;
    var6 = ((long)(((long)((int)(((long)(((long)(arg1) * (long)(arg1))) >> 16))) * (long)(arg0))) >> 16);
    return (unsigned int)(((int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var6)) >> 31))) + var6)) >> 1));
}
projectile_step fail 78 lines
// glaurung: projectile_step @ 0x1100
int32_t projectile_step(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t * arg4) {
    int velocity;
    int height;
    int step;
    long var0;
    long var10;
    int var16;
    long var17;
    long var21;
    long var23;
    long var27;
    long var28;
    long var3;
    int var30;
    long var33;
    int var34;
    long var4;
    long var6;
    var0 = (unsigned long)((unsigned int)(arg0));
    var3 = (unsigned long)((unsigned int)(arg3));
    var4 = 0;
    if ((arg4 == 0)) {
        goto L_1189;
    }
    if (((unsigned long)(0xffff) < (unsigned long)((unsigned long)((unsigned int)((arg2 - 1)))))) {
        goto L_1190;
    }
    if (((unsigned long)(32) < (unsigned long)((unsigned long)((unsigned int)(arg3))))) {
        goto L_1190;
    }
    *(int *)(((long)arg4)) = -1;
    if (((unsigned long)((unsigned int)(arg3)) == 0)) {
        goto L_11a3;
    }
    var6 = (long)(arg2);
    var10 = ((long)(((long)(arg2) * 0x9ccc5)) >> 16);
    velocity = (long)((int)(((unsigned long)((unsigned int)(arg1)) - var10)));
    var16 = (((long)(((long)(arg2) * velocity)) >> 16) + var0);
    var17 = (unsigned long)((unsigned int)(var16));
    if ((((unsigned long)((unsigned int)(var16)) == 0) | ((long)((int)(var16)) < 0))) {
        goto L_1197;
    }
    var21 = (((unsigned long)((unsigned int)(velocity)) - var10) * var6);
    var23 = ((long)((int)((-(unsigned long)((unsigned int)(var10))))) * var6);
    height = var17;
    var27 = 0;
    goto L_1182;
    L_1170: ;
    var28 = var21;
    var21 = (var21 + var23);
    var30 = (height + ((long)(var28) >> 16));
    height = (unsigned long)((unsigned int)(var30));
    var27 = (unsigned long)((unsigned int)(step));
    var33 = (unsigned long)((unsigned int)(step));
    if ((((unsigned long)((unsigned int)(var30)) == 0) | ((long)((int)(var30)) < 0))) {
        goto L_1199;
    }
    L_1182: ;
    var34 = (var27 + 1);
    step = (unsigned long)((unsigned int)(var34));
    var4 = (unsigned long)((unsigned int)(height));
    if (((unsigned int)(var3) != (unsigned int)(var34))) {
        goto L_1170;
    }
    L_1189: ;
    return (unsigned int)(var4);
    L_1190: ;
    return 0;
    L_1197: ;
    var33 = 0;
    L_1199: ;
    *(int *)(((long)arg4)) = var33;
    return 0;
    L_11a3: ;
    var4 = (unsigned long)((unsigned int)(var0));
    goto L_1189;
}

clang -O0

2/2
kinetic_energy pass 13 lines
// glaurung: kinetic_energy @ 0x1220
int32_t kinetic_energy(int32_t arg0, int32_t arg1) {
    extern int kin_mul_q16(int, int);
    int square;
    int var0;
    int var2;
    // x86-64 prologue: save rbp, frame 16 bytes
    var0 = kin_mul_q16((unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg1)));
    square = var0;
    var2 = kin_mul_q16((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(square)));
    // x86-64 epilogue: restore rbp
    return ((int)((((long long)(int)((((unsigned long)((long)((int)(var2))) >> 32) & 0xffffffff)) * (((long long)1) << 32)) + (unsigned int)(var2)) / (int)(2)));
}
projectile_step pass 51 lines
// glaurung: projectile_step @ 0x1100
int32_t projectile_step(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t * arg4) {
    extern int kin_mul_q16(int, int);
    int height;
    int velocity;
    int step;
    int local_4;
    int var11;
    int var5;
    // x86-64 prologue: save rbp, frame 48 bytes
    height = arg0;
    velocity = arg1;
    if ((arg4 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if (((long)(arg3) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if (((((unsigned long)((unsigned int)(arg3)) == 32) | ((long)(arg3) < 32)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if ((((unsigned long)((unsigned int)(arg2)) == 0) | ((long)(arg2) < 0))) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if (((((unsigned long)((unsigned int)(arg2)) == 0x10000) | ((long)(arg2) < 0x10000)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    *(int *)((long)arg4) = -1;
    step = 0;
    while ((step < arg3)) {
        var5 = kin_mul_q16(0x9ccc5, (unsigned long)((unsigned int)(arg2)));
        velocity = ((unsigned int)(velocity) - (unsigned int)(var5));
        var11 = kin_mul_q16((unsigned long)((unsigned int)(velocity)), (unsigned long)((unsigned int)(arg2)));
        height = (var11 + height);
        if (((((unsigned long)((unsigned int)(height)) == 0) | ((long)(height) < 0)) != 0)) {
            *(int *)((long)arg4) = step;
            height = 0;
            velocity = 0;
            break;
        }
        step = ((unsigned int)(step) + 1);
    }
    local_4 = height;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}

clang -O2

2/2
kinetic_energy pass 6 lines
// glaurung: kinetic_energy @ 0x1170
int32_t kinetic_energy(int32_t arg0, int32_t arg1) {
    long var6;
    var6 = ((unsigned long)(((long)((int)(((unsigned long)(((long)(arg1) * (long)(arg1))) >> 16))) * (long)(arg0))) >> 16);
    return (unsigned int)(((int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var6)) >> 31))) + var6)) >> 1));
}
projectile_step pass 54 lines
// glaurung: projectile_step @ 0x1100
int32_t projectile_step(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t * arg4) {
    int velocity;
    int height;
    int step;
    long ret;
    long t161;
    long var11;
    long var12;
    long var16;
    int var17;
    int var18;
    long var3;
    long var5;
    ret = 0;
    if (((unsigned long)((unsigned long)((unsigned int)((arg2 - 0x10001)))) < (unsigned long)(0xffff0000))) {
        return ret;
    }
    ret = 0;
    if (((unsigned long)(32) < (unsigned long)((unsigned long)((unsigned int)(arg3))))) {
        return ret;
    }
    ret = 0;
    if ((arg4 == 0)) {
        return ret;
    }
    *(int *)(((long)arg4)) = -1;
    if (((unsigned long)((unsigned int)(arg3)) == 0)) {
        return (unsigned int)(arg0);
    }
    var3 = (unsigned long)((unsigned int)(arg2));
    var5 = ((unsigned long)(((unsigned long)((unsigned int)(arg2)) * 0x9ccc5)) >> 16);
    velocity = (unsigned long)((unsigned int)((arg1 - var5)));
    var11 = (unsigned long)((unsigned int)(arg0));
    var12 = 0;
    while (1) {
        var16 = ((unsigned long)(((long)(velocity) * var3)) >> 16);
        t161 = ((long)((int)(var16)) < 0);
        var17 = (var16 + (unsigned int)(var11));
        ret = (unsigned long)((unsigned int)(var17));
        if (((((unsigned long)((unsigned int)(var17)) == 0) | (((long)((int)(var17)) < 0) ^ ((t161 == ((long)((int)(var11)) < 0)) & (((long)((int)(var17)) < 0) != t161)))) != 0)) {
            break;
        }
        var18 = (var12 + 1);
        velocity = (unsigned long)((unsigned int)((velocity - var5)));
        var11 = ret;
        var12 = (unsigned long)((unsigned int)(var18));
        if (((unsigned int)(arg3) == (unsigned int)(var18))) {
            return ret;
        }
    }
    *(int *)(((long)arg4)) = var12;
    return 0;
}

gcc -O0

2/2
kinetic_energy pass 13 lines
// glaurung: kinetic_energy @ 0x11d4
int32_t kinetic_energy(int32_t arg0, int32_t arg1) {
    extern int kin_mul_q16(int, int);
    int square;
    int var2;
    int var6;
    // x86-64 prologue: save rbp, frame 24 bytes
    var2 = kin_mul_q16((unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg1)));
    square = var2;
    var6 = kin_mul_q16((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(square)));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((int)((var6 + (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var6)) >> 31))))) >> 1));
}
projectile_step pass 49 lines
// glaurung: projectile_step @ 0x111c
int32_t projectile_step(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t * arg4) {
    extern int kin_mul_q16(int, int);
    int height;
    int velocity;
    int step;
    int var10;
    int var6;
    // x86-64 prologue: save rbp, frame 40 bytes
    height = arg0;
    velocity = arg1;
    if ((arg4 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if (((long)(arg3) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if (((((unsigned long)((unsigned int)(arg3)) == 32) | ((long)(arg3) < 32)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if ((((unsigned long)((unsigned int)(arg2)) == 0) | ((long)(arg2) < 0))) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if (((((unsigned long)((unsigned int)(arg2)) == 0x10000) | ((long)(arg2) < 0x10000)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    *(int *)((long)arg4) = -1;
    step = 0;
    while ((step < arg3)) {
        var6 = kin_mul_q16(0x9ccc5, (unsigned long)((unsigned int)(arg2)));
        velocity = (velocity - var6);
        var10 = kin_mul_q16((unsigned long)((unsigned int)(velocity)), (unsigned long)((unsigned int)(arg2)));
        height = (height + var10);
        if (((((unsigned long)((unsigned int)(height)) == 0) | ((long)(height) < 0)) != 0)) {
            *(int *)((long)arg4) = step;
            height = 0;
            velocity = 0;
            break;
        }
        step = (step + 1);
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(height);
}

← 213 fixtures