Fixture 61
fixed point
C · 4 functions · 4 lanes · 16 of 16 function-lanes behave identically
All 4 lanes recompile and return the same results as the original.
Q16.16 fixed-point primitives. The harness executes integer signatures only, so the whole numeric half of this corpus is built on these: a multiply that rounds through a 64-bit intermediate, a divide that shifts before dividing, and an integer square root by digit-by-digit restoration.
#include <stdint.h>
/* Q16.16 fixed-point primitives. The harness executes integer signatures
* only, so the whole numeric half of this corpus is built on these: a multiply
* that rounds through a 64-bit intermediate, a divide that shifts before
* dividing, and an integer square root by digit-by-digit restoration. */
#define Q16_ONE 65536
#define Q16_LIMIT 1073741824
__attribute__((noinline)) int32_t fixed_multiply(int32_t left, int32_t right) {
int64_t product = (int64_t)left * (int64_t)right;
return (int32_t)(product >> 16);
}
__attribute__((noinline)) int32_t fixed_divide(int32_t numerator,
int32_t denominator) {
int64_t scaled;
if (denominator == 0) {
return 0;
}
scaled = ((int64_t)numerator << 16) / (int64_t)denominator;
if (scaled > 2147483647LL) {
return 2147483647;
}
if (scaled < -2147483648LL) {
return -2147483647 - 1;
}
return (int32_t)scaled;
}
__attribute__((noinline)) int32_t fixed_sqrt(int32_t value) {
uint64_t remainder;
uint64_t root = 0;
uint64_t bit = 1ULL << 46;
if (value < 0) {
return -1;
}
remainder = (uint64_t)value << 16;
while (bit > remainder) {
bit >>= 2;
}
while (bit != 0u) {
if (remainder >= root + bit) {
remainder -= root + bit;
root = (root >> 1) + bit;
} else {
root >>= 1;
}
bit >>= 2;
}
return (int32_t)root;
}
__attribute__((noinline)) int32_t fixed_lerp(int32_t from, int32_t to,
int32_t alpha) {
int64_t span;
if (alpha < 0) {
alpha = 0;
}
if (alpha > Q16_ONE) {
alpha = Q16_ONE;
}
span = ((int64_t)(to - from) * (int64_t)alpha) >> 16;
return (int32_t)((int64_t)from + span);
} 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/4fixed_divide pass 21 lines
// glaurung: fixed_divide @ 0x1130
int32_t fixed_divide(int32_t arg0, int32_t arg1) {
long scaled;
long var1;
// x86-64 prologue: save rbp
if (((unsigned long)((unsigned int)(arg1)) != 0)) {
var1 = ((long)(arg0) << 16);
scaled = ((long)((((__int128)(long)(((long)(var1) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(var1)) / (long)((long)(arg1))));
if ((scaled <= 0x7fffffff)) {
if ((-0x80000000LL <= scaled)) {
return (unsigned int)(scaled);
} else {
return (unsigned int)(-0x80000000LL);
}
} else {
return 0x7fffffff;
}
} else {
return 0;
}
} fixed_lerp pass 16 lines
// glaurung: fixed_lerp @ 0x1290
int32_t fixed_lerp(int32_t arg0, int32_t arg1, int32_t arg2) {
long span;
int local_c;
// x86-64 prologue: save rbp
local_c = arg2;
if (((long)(local_c) < 0)) {
local_c = 0;
}
if (((((unsigned long)((unsigned int)(local_c)) == 0x10000) | ((long)(local_c) < 0x10000)) == 0)) {
local_c = 0x10000;
}
span = ((long)(((long)((int)(((unsigned long)((unsigned int)(arg1)) - arg0))) * (long)(local_c))) >> 16);
// x86-64 epilogue: restore rbp
return ((long)(arg0) + span);
} fixed_multiply pass 8 lines
// glaurung: fixed_multiply @ 0x1100
int32_t fixed_multiply(int32_t arg0, int32_t arg1) {
long product;
// x86-64 prologue: save rbp
product = ((long)(arg0) * (long)(arg1));
// x86-64 epilogue: restore rbp
return ((long)(product) >> 16);
} fixed_sqrt pass 27 lines
// glaurung: fixed_sqrt @ 0x11b0
int32_t fixed_sqrt(int32_t arg0) {
unsigned long root;
unsigned long bit;
unsigned long remainder;
// x86-64 prologue: save rbp
root = 0;
bit = 0x400000000000;
if ((0 <= (long)(arg0))) {
remainder = ((long)(arg0) << 16);
while (((unsigned long)(remainder) < (unsigned long)(bit))) {
bit = ((unsigned long)(bit) >> 2);
}
while ((bit != 0)) {
if (((unsigned long)(remainder) < (unsigned long)((root + bit)))) {
root = ((unsigned long)(root) >> 1);
} else {
remainder = (remainder - (root + bit));
root = (((unsigned long)(root) >> 1) + bit);
}
bit = ((unsigned long)(bit) >> 2);
}
return (unsigned int)(root);
} else {
return (unsigned int)(-1);
}
} clang -O2
4/4fixed_divide pass 16 lines
// glaurung: fixed_divide @ 0x1110
int32_t fixed_divide(int32_t arg0, int32_t arg1) {
long scaled;
int var15;
long var2;
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
return 0;
}
var2 = ((long)(arg0) << 16);
scaled = ((((unsigned long)((var2 | (long)(arg1))) >> 32) == 0) ? ((unsigned int)(((((unsigned long long)(unsigned int)((unsigned long)((unsigned int)(0))) << 32) | (unsigned int)(var2)) / (unsigned int)(arg1)))) : ((long)((((__int128)(long)(((long)(var2) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(var2)) / (long)((long)(arg1)))));
var15 = 0x7fffffff;
if ((scaled <= 0x7fffffff)) {
var15 = ((-0x7fffffffLL <= scaled) ? scaled : 0x80000000);
}
return (unsigned int)(var15);
} fixed_lerp pass 6 lines
// glaurung: fixed_lerp @ 0x11e0
int32_t fixed_lerp(int32_t arg0, int32_t arg1, int32_t arg2) {
int var2;
var2 = ((0 <= (long)(arg2)) ? arg2 : 0);
return (unsigned int)((((unsigned long)(((((unsigned long)((unsigned long)((unsigned int)(var2))) < (unsigned long)(0x10000)) ? var2 : 0x10000) * (long)((int)((arg1 - arg0))))) >> 16) + arg0));
} fixed_multiply pass 5 lines
// glaurung: fixed_multiply @ 0x1100
int32_t fixed_multiply(int32_t arg0, int32_t arg1) {
long product;
return ((unsigned long)(((long)(arg1) * (long)(arg0))) >> 16);
} fixed_sqrt pass 42 lines
// glaurung: fixed_sqrt @ 0x1160
int32_t fixed_sqrt(int32_t arg0) {
unsigned long bit;
unsigned long remainder;
unsigned long root;
long ret;
long t134;
long var1;
long var11;
long var13;
long var14;
long var19;
long var3;
long var7;
if (((long)(arg0) < 0)) {
return 0xffffffff;
}
var1 = ((unsigned long)((unsigned int)(arg0)) << 16);
var3 = 0x400000000000;
do {
bit = var3;
var3 = ((unsigned long)(var3) >> 2);
} while (((unsigned long)(var1) < (unsigned long)(bit)));
if ((bit == 0)) {
return 0;
}
var7 = 0;
var11 = 0;
remainder = var1;
var13 = bit;
do {
var14 = (bit + var11);
var19 = (((unsigned long)(remainder) < (unsigned long)(var14)) ? var7 : bit);
remainder = (remainder - (((unsigned long)(remainder) < (unsigned long)(var14)) ? var7 : var14));
ret = (var19 + ((unsigned long)(var11) >> 1));
var13 = ((unsigned long)(var13) >> 2);
t134 = ((unsigned long)(bit) <= (unsigned long)(3));
var11 = ret;
bit = var13;
} while ((t134 == 0));
return ret;
} gcc -O0
4/4fixed_divide pass 21 lines
// glaurung: fixed_divide @ 0x1124
int32_t fixed_divide(int32_t arg0, int32_t arg1) {
long scaled;
long var2;
// x86-64 prologue: save rbp
if (((unsigned long)((unsigned int)(arg1)) != 0)) {
var2 = ((long)(arg0) << 16);
scaled = ((long)((((__int128)(long)(((long)(var2) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(var2)) / (long)((long)((int)((unsigned long)((unsigned int)(arg1)))))));
if ((scaled < 0x80000000)) {
if ((-0x80000001LL < scaled)) {
return scaled;
} else {
return 0x80000000;
}
} else {
return 0x7fffffff;
}
} else {
return 0;
}
} fixed_lerp pass 16 lines
// glaurung: fixed_lerp @ 0x1221
int32_t fixed_lerp(int32_t arg0, int32_t arg1, int32_t arg2) {
long span;
int local_1c;
// x86-64 prologue: save rbp
local_1c = arg2;
if (((long)(local_1c) < 0)) {
local_1c = 0;
}
if (((((unsigned long)((unsigned int)(local_1c)) == 0x10000) | ((long)(local_1c) < 0x10000)) == 0)) {
local_1c = 0x10000;
}
span = ((long)(((long)(local_1c) * (long)((int)(((unsigned long)((unsigned int)(arg1)) - arg0))))) >> 16);
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned long)((unsigned int)(arg0)) + (unsigned long)((unsigned int)(span))));
} fixed_multiply pass 8 lines
// glaurung: fixed_multiply @ 0x10f9
int32_t fixed_multiply(int32_t arg0, int32_t arg1) {
long product;
// x86-64 prologue: save rbp
product = ((long)(arg1) * (long)(arg0));
// x86-64 epilogue: restore rbp
return ((long)(product) >> 16);
} fixed_sqrt pass 27 lines
// glaurung: fixed_sqrt @ 0x1186
int32_t fixed_sqrt(int32_t arg0) {
unsigned long root;
unsigned long bit;
unsigned long remainder;
// x86-64 prologue: save rbp
root = 0;
bit = 0x400000000000;
if ((0 <= (long)(arg0))) {
remainder = ((long)(arg0) << 16);
while (((unsigned long)(remainder) < (unsigned long)(bit))) {
bit = ((unsigned long)(bit) >> 2);
}
while ((bit != 0)) {
if (((unsigned long)(remainder) < (unsigned long)((bit + root)))) {
root = ((unsigned long)(root) >> 1);
} else {
remainder = (remainder - (bit + root));
root = (bit + ((unsigned long)(root) >> 1));
}
bit = ((unsigned long)(bit) >> 2);
}
return root;
} else {
return 0xffffffff;
}
} gcc -O2
4/4fixed_divide pass 16 lines
// glaurung: fixed_divide @ 0x1120
int32_t fixed_divide(int32_t arg0, int32_t arg1) {
long scaled;
long var2;
long var6;
var2 = 0;
if (((unsigned long)((unsigned int)(arg1)) != 0)) {
var6 = ((long)(arg0) << 16);
scaled = ((long)((((__int128)(long)(((long)(var6) >> 63)) * (((__int128)1) << 64)) + (unsigned long)(var6)) / (long)((long)(arg1))));
var2 = 0x7fffffff;
if ((scaled <= 0x7fffffff)) {
var2 = ((-0x80000000LL <= scaled) ? scaled : 0x80000000);
}
}
return (unsigned int)(var2);
} fixed_lerp pass 6 lines
// glaurung: fixed_lerp @ 0x11d0
int32_t fixed_lerp(int32_t arg0, int32_t arg1, int32_t arg2) {
long var1;
var1 = (((((unsigned long)((unsigned int)(arg2)) == 0x10000) | ((long)(arg2) < 0x10000)) == 0) ? 0x10000 : arg2);
return (unsigned int)((arg0 + ((long)(((long)((int)((((long)((int)(var1)) < 0) ? 0 : var1))) * (long)((int)((arg1 - arg0))))) >> 16)));
} fixed_multiply pass 5 lines
// glaurung: fixed_multiply @ 0x1100
int32_t fixed_multiply(int32_t arg0, int32_t arg1) {
long product;
return ((long)(((long)(arg0) * (long)(arg1))) >> 16);
} fixed_sqrt pass 37 lines
// glaurung: fixed_sqrt @ 0x1160
int32_t fixed_sqrt(int32_t arg0) {
unsigned long remainder;
unsigned long bit;
unsigned long root;
long var0;
long var8;
long var9;
if (((long)(arg0) < 0)) {
return 0xffffffff;
}
var0 = 0x400000000000;
remainder = ((long)(arg0) << 16);
if ((((unsigned long)(remainder) >> 46) == 0)) {
bit = var0;
do {
bit = ((unsigned long)(bit) >> 2);
} while (((unsigned long)(remainder) < (unsigned long)(bit)));
var0 = bit;
if ((bit == 0)) {
return 0;
}
}
root = 0;
do {
var8 = (root + var0);
root = (root >> 1);
var9 = remainder;
if (((unsigned long)(var8) <= (unsigned long)(remainder))) {
var9 = (remainder - var8);
root = (root + var0);
}
var0 = ((unsigned long)(var0) >> 2);
remainder = var9;
} while ((var0 != 0));
return root;
}