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>