Inconsistent result between GCC and Clang for __builtin_fmodf

Following simple program gives different answers when compiling with GCC (4.8.4) and ToT Clang:

$ cat builtin_fmodf_bugpoint.cpp

#include

int main(int argc, char** argv) {

const float a = 1.0f;

const float b = 0.1f;

printf("%f mod %f = %f\n", a, b, __builtin_fmodf(a, b));

return 0;

}

$ g++ -o builtin_fmodf_bugpoint_gcc builtin_fmodf_bugpoint.cpp
$ ./builtin_fmodf_bugpoint_gcc

1.000000 fmodf 0.100000 = 0.100000

$ clang++ -o builtin_fmodf_bugpoint_clang builtin_fmodf_bugpoint.cpp
1.000000 fmodf 0.100000 = 0.000000

Clang will compile __builtin_fmod() into LLVM’s “frem” [1]. Since both operands are constant, it is constant folded by IRBuilder at the time when “frem” was built. The exeuction finally goes to llvm::ConstantFoldBinaryInstruction() which uses APFloat::mod() to compute the result. As you can see from above, it gives us 0.000000 (hex: 0x0) which is different than the answer from std::fmodf() (0.100000, hex: 0x3dcccccb).

SelectionDAG also uses APFloat::mod() to fold “frem” when operands are constants. (see SelectionDAG::getNode()). However, lli interprets “frem” to a fmod() and therefore generates the same result as GCC’s.

$ lli -force-interpreter builtin_fmodf_bugpoint.ll
1.000000 fmodf 0.100000 = 0.100000

(Please refer to attachment for the .ll)

Are these expected? Which semantic does LLVM’s “frem” stick to? Any idea on how to fix it?

[1] http://llvm.org/docs/LangRef.html#i-frem

builtin_fmodf_bugpoint.ll (1.45 KB)

There is a rather unsettling comment above APFloat::mod which states “This is not currently correct in all cases.”

I wonder if this is a symptom of that.

Reading the implementation, that’s the understatement of the century. I’ll take a look at fixing it next weekend if no one else gets to it first.

– Steve