foo.ll TransformationThe source in foo.ll checks whether:
fabs(float(x) - float(y)) < Ccan be replaced with:
x == yThe concrete file uses:
uitofp i16 -> floatC = 1.0e-15Alive2 validates the original example with:
alive-tv --disable-undef-input --smt-to=30000 foo.ll
and reports:
Transformation seems to be correct!
For a binary floating-point format with precision p
bits, the rewrite is sound for:
%a = uitofp_or_sitofp iN %x to FP
%b = uitofp_or_sitofp iN %y to FP
%d = fsub FP %a, %b
%u = call FP @llvm.fabs(FP %d)
%cmp = fcmp olt FP-or-wider %u, Cto:
%eq = icmp eq iN %x, %ywhen both of these hold:
0 < C <= 1That injectivity condition becomes:
uitofp iN -> FP: require N <= psitofp iN -> FP: require
N <= p + 1Under those conditions:
FP.1.fabs(a - b) is:
0 when x == y1 when x != ySo fabs(a - b) < C is equivalent to
x == y exactly for 0 < C <= 1.
The fpext from float to double
in the original file does not change the argument; it only compares the
same nonnegative value in a wider format.
float BoundariesFor IEEE float, the precision is p = 24.
Therefore:
uitofp: safe up to i24sitofp: safe up to i25These checks were run with
--disable-undef-input --smt-to=30000.
uitofp i24 -> float, C = 1.0sitofp i25 -> float, C = 1.0uitofp i24 -> float, C = 1.000001
x = 1, y = 0fabs(float(x) - float(y)) = 1, so
< 1.000001 is true but x == y is
false.uitofp i25 -> float, C = 1.0
float.16779285 and 16779284 both
convert to 16779284.0f.For sitofp i26 -> float, the transformation is not
sound because conversion is no longer injective. A simple example
is:
16777216 and 16777217 both convert to the
same floatThe rewrite
fabs(uitofp_or_sitofp(x) - uitofp_or_sitofp(y)) < C
-> x == yis sound when:
0 < C <= 1, andFor float, that means:
i24i25