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.
#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/2kinetic_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/2kinetic_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/2kinetic_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/2kinetic_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);
}