Fixture 67
elastic collision
C · 3 functions · 4 lanes · 11 of 12 function-lanes behave identically
One lane has a function that returns a different result after decompilation: clang-O2 (2/3).
One-dimensional elastic and inelastic collisions in Q16.16, plus a momentum conservation residual. All three read the same four parameters, so a mis-assigned argument register is caught by comparing their results.
#include <stdint.h>
/* One-dimensional elastic and inelastic collisions in Q16.16, plus a momentum
* conservation residual. All three read the same four parameters, so a
* mis-assigned argument register is caught by comparing their results. */
static int32_t collide_mul_q16(int32_t left, int32_t right) {
return (int32_t)(((int64_t)left * (int64_t)right) >> 16);
}
static int32_t collide_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
elastic_velocity_a(int32_t mass_a, int32_t mass_b, int32_t velocity_a,
int32_t velocity_b) {
int32_t total;
int32_t term;
if (mass_a <= 0 || mass_b <= 0) {
return 0;
}
total = mass_a + mass_b;
term = collide_mul_q16(mass_a - mass_b, velocity_a) +
collide_mul_q16(2 * mass_b, velocity_b);
return collide_div_q16(term, total);
}
__attribute__((noinline)) int32_t
inelastic_velocity(int32_t mass_a, int32_t mass_b, int32_t velocity_a,
int32_t velocity_b) {
int32_t momentum;
if (mass_a <= 0 || mass_b <= 0) {
return 0;
}
momentum = collide_mul_q16(mass_a, velocity_a) +
collide_mul_q16(mass_b, velocity_b);
return collide_div_q16(momentum, mass_a + mass_b);
}
__attribute__((noinline)) int32_t
momentum_residual(int32_t mass_a, int32_t mass_b, int32_t velocity_a,
int32_t velocity_b) {
int32_t before = collide_mul_q16(mass_a, velocity_a) +
collide_mul_q16(mass_b, velocity_b);
int32_t after_a = elastic_velocity_a(mass_a, mass_b, velocity_a, velocity_b);
int32_t after_b = elastic_velocity_a(mass_b, mass_a, velocity_b, velocity_a);
int32_t after = collide_mul_q16(mass_a, after_a) +
collide_mul_q16(mass_b, after_b);
return before - after;
} 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 -O2
2/3elastic_velocity_a fail 19 lines
// glaurung: elastic_velocity_a @ 0x1110
int32_t elastic_velocity_a(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
int total;
long ret;
long var17;
ret = 0;
if ((((unsigned long)((unsigned int)(arg0)) == 0) | ((long)(arg0) < 0))) {
return ret;
}
if ((((unsigned long)((unsigned int)(arg1)) == 0) | ((long)(arg1) < 0))) {
return ret;
}
total = (unsigned long)((unsigned int)((arg1 + arg0)));
var17 = ((long)((int)((((unsigned long)(((long)(arg3) * (long)((int)((arg1 + arg1))))) >> 16) + ((unsigned long)(((long)(arg2) * (long)((int)((arg0 - arg1))))) >> 16)))) << 16);
if ((((unsigned long)(var17) >> 32) == 0)) {
return ((unsigned int)(((((unsigned long long)(unsigned int)((unsigned long)((unsigned int)(0))) << 32) | (unsigned int)(var17)) / (unsigned int)(total))));
}
return ((long)((((__int128)(long)(((long)(var17) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(var17)) / (long)(total)));
} inelastic_velocity pass 19 lines
// glaurung: inelastic_velocity @ 0x1160
int32_t inelastic_velocity(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
long ret;
long var12;
long var14;
ret = 0;
if ((((unsigned long)((unsigned int)(arg0)) == 0) | ((long)(arg0) < 0))) {
return ret;
}
if ((((unsigned long)((unsigned int)(arg1)) == 0) | ((long)(arg1) < 0))) {
return ret;
}
var12 = (unsigned long)((unsigned int)((arg1 + arg0)));
var14 = ((long)((int)((((unsigned long)(((long)(arg3) * (unsigned long)((unsigned int)(arg1)))) >> 16) + ((unsigned long)(((long)(arg2) * (unsigned long)((unsigned int)(arg0)))) >> 16)))) << 16);
if ((((unsigned long)(var14) >> 32) == 0)) {
return ((unsigned int)(((((unsigned long long)(unsigned int)((unsigned long)((unsigned int)(0))) << 32) | (unsigned int)(var14)) / (unsigned int)(var12))));
}
return ((long)((((__int128)(long)(((long)(var14) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(var14)) / (long)(var12)));
} momentum_residual pass 26 lines
// glaurung: momentum_residual @ 0x11b0
__attribute__((no_stack_protector)) int32_t momentum_residual(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
extern int elastic_velocity_a(int, int, int, int);
int after_b;
unsigned char local_38[56];
long var0;
long var1;
int var10;
int var12;
long var4;
long var5;
long var6;
long var9;
// x86-64 prologue: save callee registers, frame 56 bytes
var0 = (long)(arg0);
var1 = (long)(arg2);
var4 = ((unsigned long)(((long)(arg2) * (long)(arg0))) >> 16);
var5 = (long)(arg1);
var6 = (long)(arg3);
var9 = ((unsigned long)(((long)(arg3) * (long)(arg1))) >> 16);
var10 = elastic_velocity_a((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg2)), (unsigned long)((unsigned int)(arg3)));
*(int *)((&local_38[0] + 4)) = var10;
var12 = elastic_velocity_a((unsigned long)((unsigned int)(var5)), (unsigned long)((unsigned int)(var0)), (unsigned long)((unsigned int)(var6)), (unsigned long)((unsigned int)(var1)));
// x86-64 epilogue: restore callee registers
return (unsigned int)(((unsigned long)((unsigned int)((var9 + var4))) - (unsigned long)((unsigned int)((((unsigned long)(((long)((int)(var12)) * var5)) >> 16) + ((unsigned long)(((long)((int)(*(int *)((&local_38[0] + 4)))) * var0)) >> 16))))));
} clang -O0
3/3elastic_velocity_a pass 30 lines
// glaurung: elastic_velocity_a @ 0x1110
int32_t elastic_velocity_a(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
extern int collide_div_q16(int, int);
extern int collide_mul_q16(int, int);
int total;
int term;
int local_20;
int local_4;
int var15;
int var5;
int var9;
// x86-64 prologue: save rbp, frame 32 bytes
if ((((unsigned long)((unsigned int)(arg0)) == 0) | ((long)(arg0) < 0))) {
// x86-64 epilogue: restore rbp
return 0;
}
if (((((unsigned long)((unsigned int)(arg1)) == 0) | ((long)(arg1) < 0)) != 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
total = ((unsigned int)(arg0) + arg1);
var5 = collide_mul_q16((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - arg1))), (unsigned long)((unsigned int)(arg2)));
local_20 = var5;
var9 = collide_mul_q16((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) << 1))), (unsigned long)((unsigned int)(arg3)));
term = ((unsigned int)(local_20) + (unsigned int)(var9));
var15 = collide_div_q16((unsigned long)((unsigned int)(term)), (unsigned long)((unsigned int)(total)));
local_4 = var15;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} inelastic_velocity pass 28 lines
// glaurung: inelastic_velocity @ 0x11f0
int32_t inelastic_velocity(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
extern int collide_div_q16(int, int);
extern int collide_mul_q16(int, int);
int momentum;
int local_1c;
int local_4;
int var0;
int var10;
int var2;
// x86-64 prologue: save rbp, frame 32 bytes
if ((((unsigned long)((unsigned int)(arg0)) == 0) | ((long)(arg0) < 0))) {
// x86-64 epilogue: restore rbp
return 0;
}
if (((((unsigned long)((unsigned int)(arg1)) == 0) | ((long)(arg1) < 0)) != 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
var0 = collide_mul_q16((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg2)));
local_1c = var0;
var2 = collide_mul_q16((unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg3)));
momentum = ((unsigned int)(local_1c) + (unsigned int)(var2));
var10 = collide_div_q16((unsigned long)((unsigned int)(momentum)), (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) + arg1))));
local_4 = var10;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} momentum_residual pass 32 lines
// glaurung: momentum_residual @ 0x1270
int32_t momentum_residual(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
extern int collide_mul_q16(int, int);
extern int elastic_velocity_a(int, int, int, int);
int before;
int after_a;
int after_b;
int after;
int local_24;
int local_28;
int var0;
int var10;
int var12;
int var14;
int var2;
int var8;
// x86-64 prologue: save rbp, frame 48 bytes
var0 = collide_mul_q16((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg2)));
local_28 = var0;
var2 = collide_mul_q16((unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg3)));
before = ((unsigned int)(local_28) + (unsigned int)(var2));
var8 = elastic_velocity_a((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg2)), (unsigned long)((unsigned int)(arg3)));
after_a = var8;
var10 = elastic_velocity_a((unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg3)), (unsigned long)((unsigned int)(arg2)));
after_b = var10;
var12 = collide_mul_q16((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(after_a)));
local_24 = var12;
var14 = collide_mul_q16((unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(after_b)));
after = ((unsigned int)(local_24) + (unsigned int)(var14));
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned long)((unsigned int)(before)) - after));
} gcc -O0
3/3elastic_velocity_a pass 28 lines
// glaurung: elastic_velocity_a @ 0x116d
int32_t elastic_velocity_a(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
extern int collide_div_q16(int, int);
extern int collide_mul_q16(int, int);
int total;
int term;
int ret;
long var11;
int var15;
int var9;
// x86-64 prologue: save rbp, frame 8 bytes
if ((((unsigned long)((unsigned int)(arg0)) == 0) | ((long)(arg0) < 0))) {
// x86-64 epilogue: restore rbp
return 0;
}
if (((((unsigned long)((unsigned int)(arg1)) == 0) | ((long)(arg1) < 0)) != 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
total = ((unsigned int)(arg1) + (unsigned int)(arg0));
var9 = collide_mul_q16((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - arg1))), (unsigned long)((unsigned int)(arg2)));
var11 = (unsigned long)((unsigned int)(var9));
var15 = collide_mul_q16((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) + (unsigned long)((unsigned int)(arg1))))), (unsigned long)((unsigned int)(arg3)));
term = (var15 + var11);
ret = collide_div_q16((unsigned long)((unsigned int)(term)), (unsigned long)((unsigned int)(total)));
// x86-64 epilogue: restore rbp
return ret;
} inelastic_velocity pass 26 lines
// glaurung: inelastic_velocity @ 0x11e4
int32_t inelastic_velocity(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
extern int collide_div_q16(int, int);
extern int collide_mul_q16(int, int);
int momentum;
int ret;
int var3;
long var5;
int var8;
// x86-64 prologue: save rbp, frame 8 bytes
if ((((unsigned long)((unsigned int)(arg0)) == 0) | ((long)(arg0) < 0))) {
// x86-64 epilogue: restore rbp
return 0;
}
if (((((unsigned long)((unsigned int)(arg1)) == 0) | ((long)(arg1) < 0)) != 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
var3 = collide_mul_q16((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg2)));
var5 = (unsigned long)((unsigned int)(var3));
var8 = collide_mul_q16((unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg3)));
momentum = (var8 + var5);
ret = collide_div_q16((unsigned long)((unsigned int)(momentum)), (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) + (unsigned long)((unsigned int)(arg1))))));
// x86-64 epilogue: restore rbp
return ret;
} momentum_residual pass 32 lines
// glaurung: momentum_residual @ 0x124f
int32_t momentum_residual(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
extern int collide_mul_q16(int, int);
extern int elastic_velocity_a(int, int, int, int);
int before;
int after_a;
int after_b;
int after;
int var12;
int var15;
int var19;
int var2;
long var21;
int var24;
long var4;
int var7;
// x86-64 prologue: save rbp, frame 8 bytes
var2 = collide_mul_q16((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg2)));
var4 = (unsigned long)((unsigned int)(var2));
var7 = collide_mul_q16((unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg3)));
before = (var7 + var4);
var12 = elastic_velocity_a((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg2)), (unsigned long)((unsigned int)(arg3)));
after_a = var12;
var15 = elastic_velocity_a((unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg3)), (unsigned long)((unsigned int)(arg2)));
after_b = var15;
var19 = collide_mul_q16((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(after_a)));
var21 = (unsigned long)((unsigned int)(var19));
var24 = collide_mul_q16((unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(after_b)));
after = (var24 + var21);
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned long)((unsigned int)(before)) - after));
} gcc -O2
3/3elastic_velocity_a pass 14 lines
// glaurung: elastic_velocity_a @ 0x1120
int32_t elastic_velocity_a(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
int total;
long var0;
long var19;
var0 = (long)(arg2);
if ((((unsigned long)((unsigned int)(arg0)) != 0) && (0 <= (long)(arg0)))) {
if (((((unsigned long)((unsigned int)(arg1)) == 0) | ((long)(arg1) < 0)) == 0)) {
var19 = ((long)((int)((((long)(((long)((int)((arg1 + arg1))) * (long)(arg3))) >> 16) + ((long)(((long)((int)(((unsigned long)((unsigned int)(arg0)) - arg1))) * var0)) >> 16)))) << 16);
return ((long)((((__int128)(long)(((long)(var19) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(var19)) / (long)((long)((int)((unsigned long)((unsigned int)((arg0 + arg1))))))));
}
}
return 0;
} inelastic_velocity pass 11 lines
// glaurung: inelastic_velocity @ 0x1170
int32_t inelastic_velocity(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
long var15;
if ((((unsigned long)((unsigned int)(arg0)) != 0) && (0 <= (long)(arg0)))) {
if (((((unsigned long)((unsigned int)(arg1)) == 0) | ((long)(arg1) < 0)) == 0)) {
var15 = ((long)((int)((((long)(((long)(arg1) * (long)(arg3))) >> 16) + ((long)(((long)(arg2) * (long)(arg0))) >> 16)))) << 16);
return ((long)((((__int128)(long)(((long)(var15) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(var15)) / (long)((long)((int)((unsigned long)((unsigned int)((arg0 + arg1))))))));
}
}
return 0;
} momentum_residual pass 27 lines
// glaurung: momentum_residual @ 0x11c0
int32_t momentum_residual(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
extern int elastic_velocity_a(int, int, int, int);
int after_b;
int before;
int local_40;
long var1;
long var12;
int var13;
int var15;
long var2;
long var5;
long var7;
long var8;
var1 = (long)(arg0);
var2 = (long)(arg2);
var5 = (long)(arg1);
var7 = ((long)(((long)(arg2) * (long)(arg0))) >> 16);
var8 = (long)(arg3);
arg2 = (long)(arg2);
var12 = (unsigned long)((unsigned int)((((long)(((long)(arg3) * (long)(arg1))) >> 16) + var7)));
var13 = elastic_velocity_a(arg0, (unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(var2)), (unsigned long)((unsigned int)(arg3)));
local_40 = var13;
var15 = elastic_velocity_a((unsigned long)((unsigned int)(var5)), (unsigned long)((unsigned int)(var1)), (unsigned long)((unsigned int)(var8)), (unsigned long)((unsigned int)(arg2)));
// x86-64 epilogue: tear down frame
return (unsigned int)(((unsigned long)((unsigned int)(var12)) - (unsigned long)((unsigned int)((((long)(((long)((int)(var15)) * var5)) >> 16) + ((long)(((long)(local_40) * var1)) >> 16))))));
}