Hi, I'm recently trying to investigate ppc_fp128 related problem. Here is a minimal C++ test case that seems wrongly compiled: long double id(long double a) { return a; } bool f(long double x) { return id(__builtin_fabsl(x)) >= 0; } int main() { if (f(-123.l)) { return 0; } return 1; } The program compiled with command: clang++ -static -target powerpc64le-linux-gnu bad.cc Returns 1 on a ppc machine. I did some investigation, it turns out in lib/CodeGen/SelectionDAG/DAGCombiner.cpp, a combination is wrongly assuming the endianness for the i128 bitcasted from a ppc_fp128 (two doubles bit-concatenated together): // fold (bitconvert (fabs x)) -> (and (bitconvert x), (not signbit)) This reveals that endianness conversion concerning ppc_fp128 or i128, and big-endian or little-endian target is too confusing to me. I can certainly fix this case by using a "smarter signbit" (e.g. 0x00000000000000001000000000000000), but this seems more confusing. I wonder if anyone has the best background knowledge here? Background I found: http://llvm.org/klaus/llvm/commit/1ef2cec146099f4bf46c31b913c7f1538935a867/ Thanks! -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20151201/2faf9268/attachment.html>
Gao, Yunzhong via llvm-dev
2015-Dec-01 03:24 UTC
[llvm-dev] Endianness for multi-word types
According to http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html, "The high-order double-precision value (the one that comes first in storage) must have the larger magnitude." So the order of the two doubles in your fp128 is not affected by the endianness; although each individual double is. Hope that helps, - Gao ________________________________________ From: llvm-dev [llvm-dev-bounces at lists.llvm.org] on behalf of Tim Shen via llvm-dev [llvm-dev at lists.llvm.org] Sent: Monday, November 30, 2015 7:17 PM To: llvm-dev at lists.llvm.org Subject: [llvm-dev] Endianness for multi-word types Hi, I'm recently trying to investigate ppc_fp128 related problem. Here is a minimal C++ test case that seems wrongly compiled: long double id(long double a) { return a; } bool f(long double x) { return id(__builtin_fabsl(x)) >= 0; } int main() { if (f(-123.l)) { return 0; } return 1; } The program compiled with command: clang++ -static -target powerpc64le-linux-gnu bad.cc Returns 1 on a ppc machine. I did some investigation, it turns out in lib/CodeGen/SelectionDAG/DAGCombiner.cpp, a combination is wrongly assuming the endianness for the i128 bitcasted from a ppc_fp128 (two doubles bit-concatenated together): // fold (bitconvert (fabs x)) -> (and (bitconvert x), (not signbit)) This reveals that endianness conversion concerning ppc_fp128 or i128, and big-endian or little-endian target is too confusing to me. I can certainly fix this case by using a "smarter signbit" (e.g. 0x00000000000000001000000000000000), but this seems more confusing. I wonder if anyone has the best background knowledge here? Background I found: http://llvm.org/klaus/llvm/commit/1ef2cec146099f4bf46c31b913c7f1538935a867/ Thanks!
On Mon, Nov 30, 2015 at 7:24 PM Gao, Yunzhong < yunzhong_gao at playstation.sony.com> wrote:> According to > http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html, > "The high-order double-precision value (the one that comes first in > storage) must have the larger magnitude." > > So the order of the two doubles in your fp128 is not affected by the > endianness; although each individual double is. >Of this part it's pretty clear, so I guess my questions are, more specifically: 1) Why> Hope that helps, > - Gao > > > ________________________________________ > From: llvm-dev [llvm-dev-bounces at lists.llvm.org] on behalf of Tim Shen > via llvm-dev [llvm-dev at lists.llvm.org] > Sent: Monday, November 30, 2015 7:17 PM > To: llvm-dev at lists.llvm.org > Subject: [llvm-dev] Endianness for multi-word types > > Hi, > > I'm recently trying to investigate ppc_fp128 related problem. Here is a > minimal C++ test case that seems wrongly compiled: > > long double id(long double a) { > return a; > } > bool f(long double x) { > return id(__builtin_fabsl(x)) >= 0; > } > int main() { > if (f(-123.l)) { > return 0; > } > return 1; > } > > The program compiled with command: > clang++ -static -target powerpc64le-linux-gnu bad.cc > Returns 1 on a ppc machine. > > I did some investigation, it turns out in > lib/CodeGen/SelectionDAG/DAGCombiner.cpp, a combination is wrongly assuming > the endianness for the i128 bitcasted from a ppc_fp128 (two doubles > bit-concatenated together): > // fold (bitconvert (fabs x)) -> (and (bitconvert x), (not signbit)) > > This reveals that endianness conversion concerning ppc_fp128 or i128, and > big-endian or little-endian target is too confusing to me. > > I can certainly fix this case by using a "smarter signbit" (e.g. > 0x00000000000000001000000000000000), but this seems more confusing. I > wonder if anyone has the best background knowledge here? > > Background I found: > http://llvm.org/klaus/llvm/commit/1ef2cec146099f4bf46c31b913c7f1538935a867/ > > Thanks! >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20151201/3d2761a2/attachment.html>
On Mon, Nov 30, 2015 at 7:24 PM Gao, Yunzhong < yunzhong_gao at playstation.sony.com> wrote:> According to > http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html, > "The high-order double-precision value (the one that comes first in > storage) must have the larger magnitude." > > So the order of the two doubles in your fp128 is not affected by the > endianness; although each individual double is. >Well I'm still trying to understand the code base, so I may get this completely wrong, but here is my understanding: Looking at the comment of TargetLowering::hasBigEndianPartOrdering, it seems that, all "internal types" (e.g. ppc_fp128, i128) are assumed to be little-endian, and for non-ppc_fp128 external values (raw register tuples or memory), the endianness follows the data layout endianness; for ppc_fp128 external values (a pair of float registers or memory chunk), it's always "big-endian" due to the policy. The problem is when we bitcast from ppc_fp128 to i128, do we exchange the two registers? Today we do, because ppc_fp128 requires a mandatory big-endian representation, but at the same time it's a i128, which is interpreted as a little-endian 128-bit integer. That's why the combiner I previously mentioned gets confused. If we don't exchange the two registers, combiners are happy because they get a little-endian view of the two doubles (e.g. the most significant bit is indeed the sign bit); but if someone stores this casted i128 to memory, the two words are in little-endian, which breaks the ppc_fp128 layout policy. It also breaks the bitcast semantic: "The conversion is done as if the value had been stored to memory and read back as type ty2." -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20151201/5d4ca491/attachment.html>