Fix PR6522: implement copysign expansion for x86 long double

(it seems that FreeBSD doesn't have copysignl).  Done by
removing a bunch of assumptions from the code.  This may also
help with sparc 128 bit floats.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@98346 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Duncan Sands
2010-03-12 11:45:06 +00:00
parent 0b6cb50738
commit 5d54b4112d

View File

@ -1585,35 +1585,51 @@ SDValue SelectionDAGLegalize::ExpandFCOPYSIGN(SDNode* Node) {
DebugLoc dl = Node->getDebugLoc(); DebugLoc dl = Node->getDebugLoc();
SDValue Tmp1 = Node->getOperand(0); SDValue Tmp1 = Node->getOperand(0);
SDValue Tmp2 = Node->getOperand(1); SDValue Tmp2 = Node->getOperand(1);
assert((Tmp2.getValueType() == MVT::f32 ||
Tmp2.getValueType() == MVT::f64) && // Get the sign bit of the RHS. First obtain a value that has the same
"Ugly special-cased code!"); // sign as the sign bit, i.e. negative if and only if the sign bit is 1.
// Get the sign bit of the RHS.
SDValue SignBit; SDValue SignBit;
EVT IVT = Tmp2.getValueType() == MVT::f64 ? MVT::i64 : MVT::i32; EVT FloatVT = Tmp2.getValueType();
EVT IVT = EVT::getIntegerVT(*DAG.getContext(), FloatVT.getSizeInBits());
if (isTypeLegal(IVT)) { if (isTypeLegal(IVT)) {
// Convert to an integer with the same sign bit.
SignBit = DAG.getNode(ISD::BIT_CONVERT, dl, IVT, Tmp2); SignBit = DAG.getNode(ISD::BIT_CONVERT, dl, IVT, Tmp2);
} else { } else {
assert(isTypeLegal(TLI.getPointerTy()) && // Store the float to memory, then load the sign part out as an integer.
(TLI.getPointerTy() == MVT::i32 || MVT LoadTy = TLI.getPointerTy();
TLI.getPointerTy() == MVT::i64) && // First create a temporary that is aligned for both the load and store.
"Legal type for load?!"); SDValue StackPtr = DAG.CreateStackTemporary(FloatVT, LoadTy);
SDValue StackPtr = DAG.CreateStackTemporary(Tmp2.getValueType()); // Then store the float to it.
SDValue StorePtr = StackPtr, LoadPtr = StackPtr;
SDValue Ch = SDValue Ch =
DAG.getStore(DAG.getEntryNode(), dl, Tmp2, StorePtr, NULL, 0, DAG.getStore(DAG.getEntryNode(), dl, Tmp2, StackPtr, NULL, 0,
false, false, 0); false, false, 0);
if (Tmp2.getValueType() == MVT::f64 && TLI.isLittleEndian()) if (TLI.isBigEndian()) {
LoadPtr = DAG.getNode(ISD::ADD, dl, StackPtr.getValueType(), assert(FloatVT.isByteSized() && "Unsupported floating point type!");
LoadPtr, DAG.getIntPtrConstant(4)); // Load out a legal integer with the same sign bit as the float.
SignBit = DAG.getExtLoad(ISD::SEXTLOAD, dl, TLI.getPointerTy(), SignBit = DAG.getLoad(LoadTy, dl, Ch, StackPtr, NULL, 0, false, false, 0);
Ch, LoadPtr, NULL, 0, MVT::i32, } else { // Little endian
false, false, 0); SDValue LoadPtr = StackPtr;
// The float may be wider than the integer we are going to load. Advance
// the pointer so that the loaded integer will contain the sign bit.
unsigned Strides = (FloatVT.getSizeInBits()-1)/LoadTy.getSizeInBits();
unsigned ByteOffset = (Strides * LoadTy.getSizeInBits()) / 8;
LoadPtr = DAG.getNode(ISD::ADD, dl, LoadPtr.getValueType(),
LoadPtr, DAG.getIntPtrConstant(ByteOffset));
// Load a legal integer containing the sign bit.
SignBit = DAG.getLoad(LoadTy, dl, Ch, LoadPtr, NULL, 0, false, false, 0);
// Move the sign bit to the top bit of the loaded integer.
unsigned BitShift = LoadTy.getSizeInBits() -
(FloatVT.getSizeInBits() - 8 * ByteOffset);
assert(BitShift < LoadTy.getSizeInBits() && "Pointer advanced wrong?");
if (BitShift)
SignBit = DAG.getNode(ISD::SHL, dl, LoadTy, SignBit,
DAG.getConstant(BitShift,TLI.getShiftAmountTy()));
}
} }
SignBit = // Now get the sign bit proper, by seeing whether the value is negative.
DAG.getSetCC(dl, TLI.getSetCCResultType(SignBit.getValueType()), SignBit = DAG.getSetCC(dl, TLI.getSetCCResultType(SignBit.getValueType()),
SignBit, DAG.getConstant(0, SignBit.getValueType()), SignBit, DAG.getConstant(0, SignBit.getValueType()),
ISD::SETLT); ISD::SETLT);
// Get the absolute value of the result. // Get the absolute value of the result.
SDValue AbsVal = DAG.getNode(ISD::FABS, dl, Tmp1.getValueType(), Tmp1); SDValue AbsVal = DAG.getNode(ISD::FABS, dl, Tmp1.getValueType(), Tmp1);
// Select between the nabs and abs value based on the sign bit of // Select between the nabs and abs value based on the sign bit of