Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit 2a46e4c

Browse files
committed
LegalizeDAG: Fix and improve FCOPYSIGN/FABS legalization
- Factor out code to query and modify the sign bit of a floatingpoint value as an integer. This also works if none of the targets integer types is big enough to hold all bits of the floatingpoint value. - Legalize FABS(x) as FCOPYSIGN(x, 0.0) if FCOPYSIGN is available, otherwise perform bit manipulation on the sign bit. The previous code used "x >u 0 ? x : -x" which is incorrect for x being -0.0! It also takes 34 instructions on ARM Cortex-M4. With this patch we only require 5: vldr d0, LCPI0_0 vmov r2, r3, d0 lsrs r2, r3, #31 bfi r1, r2, #31, #1 bx lr (This could be further improved if the compiler would recognize that r2, r3 is zero). - Only lower FCOPYSIGN(x, y) = sign(x) ? -FABS(x) : FABS(x) if FABS is available otherwise perform bit manipulation on the sign bit. - Perform the sign(x) test by masking out the sign bit and comparing with 0 rather than shifting the sign bit to the highest position and testing for "<s 0". For x86 copysignl (on 80bit values) this gets us: testl $32768, %eax rather than: shlq $48, %rax sets %al testb %al, %al git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@242107 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent dbe7178 commit 2a46e4c

File tree

3 files changed

+157
-80
lines changed

3 files changed

+157
-80
lines changed

lib/CodeGen/SelectionDAG/LegalizeDAG.cpp

+150-74
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ using namespace llvm;
3939

4040
#define DEBUG_TYPE "legalizedag"
4141

42+
namespace {
43+
44+
struct FloatSignAsInt;
45+
4246
//===----------------------------------------------------------------------===//
4347
/// This takes an arbitrary SelectionDAG as input and
4448
/// hacks on it until the target machine can handle it. This involves
@@ -51,7 +55,6 @@ using namespace llvm;
5155
/// 'setcc' instruction efficiently, but does support 'brcc' instruction, this
5256
/// will attempt merge setcc and brc instructions into brcc's.
5357
///
54-
namespace {
5558
class SelectionDAGLegalize {
5659
const TargetMachine &TM;
5760
const TargetLowering &TLI;
@@ -130,7 +133,11 @@ class SelectionDAGLegalize {
130133
SDValue ExpandSCALAR_TO_VECTOR(SDNode *Node);
131134
void ExpandDYNAMIC_STACKALLOC(SDNode *Node,
132135
SmallVectorImpl<SDValue> &Results);
133-
SDValue ExpandFCOPYSIGN(SDNode *Node);
136+
void getSignAsIntValue(FloatSignAsInt &State, SDLoc DL, SDValue Value) const;
137+
SDValue modifySignAsInt(const FloatSignAsInt &State, SDLoc DL,
138+
SDValue NewIntValue) const;
139+
SDValue ExpandFCOPYSIGN(SDNode *Node) const;
140+
SDValue ExpandFABS(SDNode *Node) const;
134141
SDValue ExpandLegalINT_TO_FP(bool isSigned, SDValue LegalOp, EVT DestVT,
135142
SDLoc dl);
136143
SDValue PromoteLegalINT_TO_FP(SDValue LegalOp, EVT DestVT, bool isSigned,
@@ -1568,69 +1575,147 @@ SDValue SelectionDAGLegalize::ExpandVectorBuildThroughStack(SDNode* Node) {
15681575
false, false, false, 0);
15691576
}
15701577

1571-
SDValue SelectionDAGLegalize::ExpandFCOPYSIGN(SDNode* Node) {
1572-
SDLoc dl(Node);
1573-
SDValue Tmp1 = Node->getOperand(0);
1574-
SDValue Tmp2 = Node->getOperand(1);
1575-
1576-
// Get the sign bit of the RHS. First obtain a value that has the same
1577-
// sign as the sign bit, i.e. negative if and only if the sign bit is 1.
1578-
SDValue SignBit;
1579-
EVT FloatVT = Tmp2.getValueType();
1580-
EVT IVT = EVT::getIntegerVT(*DAG.getContext(), FloatVT.getSizeInBits());
1578+
namespace {
1579+
/// Keeps track of state when getting the sign of a floatingpoint value as an
1580+
/// integer.
1581+
struct FloatSignAsInt {
1582+
EVT FloatVT;
1583+
SDValue Chain;
1584+
SDValue FloatPtr;
1585+
SDValue IntPtr;
1586+
MachinePointerInfo IntPointerInfo;
1587+
MachinePointerInfo FloatPointerInfo;
1588+
SDValue IntValue;
1589+
APInt SignMask;
1590+
};
1591+
}
1592+
1593+
/// Bitcast a floatingpoint value to an integer value. Only bitcast the part
1594+
/// containing the sign bit if the target has no integer value capable of
1595+
/// holding all bits of the floatingpoint value.
1596+
void SelectionDAGLegalize::getSignAsIntValue(FloatSignAsInt &State,
1597+
SDLoc DL, SDValue Value) const {
1598+
EVT FloatVT = Value.getValueType();
1599+
unsigned NumBits = FloatVT.getSizeInBits();
1600+
State.FloatVT = FloatVT;
1601+
EVT IVT = EVT::getIntegerVT(*DAG.getContext(), NumBits);
1602+
// Convert to an integer of the same size.
15811603
if (TLI.isTypeLegal(IVT)) {
1582-
// Convert to an integer with the same sign bit.
1583-
SignBit = DAG.getNode(ISD::BITCAST, dl, IVT, Tmp2);
1584-
} else {
1585-
auto &DL = DAG.getDataLayout();
1586-
// Store the float to memory, then load the sign part out as an integer.
1587-
MVT LoadTy = TLI.getPointerTy(DL);
1588-
// First create a temporary that is aligned for both the load and store.
1589-
SDValue StackPtr = DAG.CreateStackTemporary(FloatVT, LoadTy);
1590-
// Then store the float to it.
1591-
SDValue Ch =
1592-
DAG.getStore(DAG.getEntryNode(), dl, Tmp2, StackPtr, MachinePointerInfo(),
1593-
false, false, 0);
1594-
if (DL.isBigEndian()) {
1595-
assert(FloatVT.isByteSized() && "Unsupported floating point type!");
1596-
// Load out a legal integer with the same sign bit as the float.
1597-
SignBit = DAG.getLoad(LoadTy, dl, Ch, StackPtr, MachinePointerInfo(),
1598-
false, false, false, 0);
1599-
} else { // Little endian
1600-
SDValue LoadPtr = StackPtr;
1601-
// The float may be wider than the integer we are going to load. Advance
1602-
// the pointer so that the loaded integer will contain the sign bit.
1603-
unsigned Strides = (FloatVT.getSizeInBits()-1)/LoadTy.getSizeInBits();
1604-
unsigned ByteOffset = (Strides * LoadTy.getSizeInBits()) / 8;
1605-
LoadPtr = DAG.getNode(ISD::ADD, dl, LoadPtr.getValueType(), LoadPtr,
1606-
DAG.getConstant(ByteOffset, dl,
1607-
LoadPtr.getValueType()));
1608-
// Load a legal integer containing the sign bit.
1609-
SignBit = DAG.getLoad(LoadTy, dl, Ch, LoadPtr, MachinePointerInfo(),
1610-
false, false, false, 0);
1611-
// Move the sign bit to the top bit of the loaded integer.
1612-
unsigned BitShift = LoadTy.getSizeInBits() -
1613-
(FloatVT.getSizeInBits() - 8 * ByteOffset);
1614-
assert(BitShift < LoadTy.getSizeInBits() && "Pointer advanced wrong?");
1615-
if (BitShift)
1616-
SignBit = DAG.getNode(
1617-
ISD::SHL, dl, LoadTy, SignBit,
1618-
DAG.getConstant(BitShift, dl,
1619-
TLI.getShiftAmountTy(SignBit.getValueType(), DL)));
1620-
}
1604+
State.IntValue = DAG.getNode(ISD::BITCAST, DL, IVT, Value);
1605+
State.SignMask = APInt::getSignBit(NumBits);
1606+
return;
1607+
}
1608+
1609+
auto &DataLayout = DAG.getDataLayout();
1610+
// Store the float to memory, then load the sign part out as an integer.
1611+
MVT LoadTy = TLI.getPointerTy(DataLayout);
1612+
// First create a temporary that is aligned for both the load and store.
1613+
SDValue StackPtr = DAG.CreateStackTemporary(FloatVT, LoadTy);
1614+
int FI = cast<FrameIndexSDNode>(StackPtr.getNode())->getIndex();
1615+
// Then store the float to it.
1616+
State.FloatPtr = StackPtr;
1617+
State.FloatPointerInfo = MachinePointerInfo::getFixedStack(FI);
1618+
State.Chain = DAG.getStore(DAG.getEntryNode(), DL, Value, State.FloatPtr,
1619+
State.FloatPointerInfo, false, false, 0);
1620+
1621+
if (DataLayout.isBigEndian()) {
1622+
assert(FloatVT.isByteSized() && "Unsupported floating point type!");
1623+
// Load out a legal integer with the same sign bit as the float.
1624+
State.IntPtr = StackPtr;
1625+
State.IntPointerInfo = State.FloatPointerInfo;
1626+
State.IntValue = DAG.getLoad(LoadTy, DL, State.Chain, StackPtr,
1627+
State.IntPointerInfo, false, false, false, 0);
1628+
State.SignMask = APInt::getSignBit(LoadTy.getSizeInBits());
1629+
} else { // Little endian
1630+
// The float may be wider than the integer we are going to load. Advance
1631+
// the pointer so that the loaded integer will contain the sign bit.
1632+
unsigned Strides = (FloatVT.getSizeInBits()-1)/LoadTy.getSizeInBits();
1633+
unsigned ByteOffset = (Strides * LoadTy.getSizeInBits()) / 8;
1634+
SDValue LoadPtr
1635+
= DAG.getNode(ISD::ADD, DL, StackPtr.getValueType(), StackPtr,
1636+
DAG.getConstant(ByteOffset, DL, StackPtr.getValueType()));
1637+
// Load a legal integer containing the sign bit.
1638+
State.IntPtr = LoadPtr;
1639+
State.IntPointerInfo = MachinePointerInfo::getFixedStack(FI, ByteOffset);
1640+
State.IntValue = DAG.getLoad(LoadTy, DL, State.Chain, LoadPtr,
1641+
State.IntPointerInfo, false, false, false, 0);
1642+
unsigned NumBits = LoadTy.getSizeInBits();
1643+
unsigned SignBit = (FloatVT.getSizeInBits()-1) - 8*ByteOffset;
1644+
State.SignMask = APInt::getOneBitSet(NumBits, SignBit);
16211645
}
1622-
// Now get the sign bit proper, by seeing whether the value is negative.
1623-
SignBit = DAG.getSetCC(dl, getSetCCResultType(SignBit.getValueType()),
1624-
SignBit,
1625-
DAG.getConstant(0, dl, SignBit.getValueType()),
1626-
ISD::SETLT);
1627-
// Get the absolute value of the result.
1628-
SDValue AbsVal = DAG.getNode(ISD::FABS, dl, Tmp1.getValueType(), Tmp1);
1629-
// Select between the nabs and abs value based on the sign bit of
1630-
// the input.
1631-
return DAG.getSelect(dl, AbsVal.getValueType(), SignBit,
1632-
DAG.getNode(ISD::FNEG, dl, AbsVal.getValueType(), AbsVal),
1633-
AbsVal);
1646+
}
1647+
1648+
/// Replace the integer value produced by getSignAsIntValue() with a new value
1649+
/// and cast the result back to a floatingpoint type.
1650+
SDValue SelectionDAGLegalize::modifySignAsInt(const FloatSignAsInt &State,
1651+
SDLoc DL, SDValue NewIntValue) const {
1652+
if (!State.Chain) {
1653+
return DAG.getNode(ISD::BITCAST, DL, State.FloatVT, NewIntValue);
1654+
}
1655+
1656+
// Override the part containing the sign bit in the value stored on the stack.
1657+
SDValue Chain = DAG.getStore(State.Chain, DL, NewIntValue, State.IntPtr,
1658+
State.IntPointerInfo, false, false, 0);
1659+
return DAG.getLoad(State.FloatVT, DL, Chain, State.FloatPtr,
1660+
State.FloatPointerInfo, false, false, false, 0);
1661+
}
1662+
1663+
SDValue SelectionDAGLegalize::ExpandFCOPYSIGN(SDNode *Node) const {
1664+
SDLoc DL(Node);
1665+
SDValue Mag = Node->getOperand(0);
1666+
SDValue Sign = Node->getOperand(1);
1667+
1668+
// Get sign bit into an integer value.
1669+
FloatSignAsInt SignAsInt;
1670+
getSignAsIntValue(SignAsInt, DL, Sign);
1671+
1672+
EVT IntVT = SignAsInt.IntValue.getValueType();
1673+
SDValue SignMask = DAG.getConstant(SignAsInt.SignMask, DL, IntVT);
1674+
SDValue SignBit = DAG.getNode(ISD::AND, DL, IntVT, SignAsInt.IntValue,
1675+
SignMask);
1676+
1677+
// Transform FCOPYSIGN(x, y) => sign(x) ? -FABS(x) : FABS(X) if FABS is legal.
1678+
EVT FloatVT = Mag.getValueType();
1679+
if (TLI.isOperationLegalOrCustom(ISD::FABS, FloatVT) &&
1680+
TLI.isOperationLegalOrCustom(ISD::FNEG, FloatVT)) {
1681+
SDValue AbsValue = DAG.getNode(ISD::FABS, DL, FloatVT, Mag);
1682+
SDValue NegValue = DAG.getNode(ISD::FNEG, DL, FloatVT, AbsValue);
1683+
SDValue Cond = DAG.getSetCC(DL, getSetCCResultType(IntVT), SignBit,
1684+
DAG.getConstant(0, DL, IntVT), ISD::SETNE);
1685+
return DAG.getSelect(DL, FloatVT, Cond, NegValue, AbsValue);
1686+
}
1687+
1688+
// Transform values to integer, copy the sign bit and transform back.
1689+
FloatSignAsInt MagAsInt;
1690+
getSignAsIntValue(MagAsInt, DL, Mag);
1691+
assert(SignAsInt.SignMask == MagAsInt.SignMask);
1692+
SDValue ClearSignMask = DAG.getConstant(~SignAsInt.SignMask, DL, IntVT);
1693+
SDValue ClearedSign = DAG.getNode(ISD::AND, DL, IntVT, MagAsInt.IntValue,
1694+
ClearSignMask);
1695+
SDValue CopiedSign = DAG.getNode(ISD::OR, DL, IntVT, ClearedSign, SignBit);
1696+
1697+
return modifySignAsInt(MagAsInt, DL, CopiedSign);
1698+
}
1699+
1700+
SDValue SelectionDAGLegalize::ExpandFABS(SDNode *Node) const {
1701+
SDLoc DL(Node);
1702+
SDValue Value = Node->getOperand(0);
1703+
1704+
// Transform FABS(x) => FCOPYSIGN(x, 0.0) if FCOPYSIGN is legal.
1705+
EVT FloatVT = Value.getValueType();
1706+
if (TLI.isOperationLegalOrCustom(ISD::FCOPYSIGN, FloatVT)) {
1707+
SDValue Zero = DAG.getConstantFP(0.0, DL, FloatVT);
1708+
return DAG.getNode(ISD::FCOPYSIGN, DL, FloatVT, Value, Zero);
1709+
}
1710+
1711+
// Transform value to integer, clear the sign bit and transform back.
1712+
FloatSignAsInt ValueAsInt;
1713+
getSignAsIntValue(ValueAsInt, DL, Value);
1714+
EVT IntVT = ValueAsInt.IntValue.getValueType();
1715+
SDValue ClearSignMask = DAG.getConstant(~ValueAsInt.SignMask, DL, IntVT);
1716+
SDValue ClearedSign = DAG.getNode(ISD::AND, DL, IntVT, ValueAsInt.IntValue,
1717+
ClearSignMask);
1718+
return modifySignAsInt(ValueAsInt, DL, ClearedSign);
16341719
}
16351720

16361721
void SelectionDAGLegalize::ExpandDYNAMIC_STACKALLOC(SDNode* Node,
@@ -3312,18 +3397,9 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node) {
33123397
Node->getOperand(0));
33133398
Results.push_back(Tmp1);
33143399
break;
3315-
case ISD::FABS: {
3316-
// Expand Y = FABS(X) -> Y = (X >u 0.0) ? X : fneg(X).
3317-
EVT VT = Node->getValueType(0);
3318-
Tmp1 = Node->getOperand(0);
3319-
Tmp2 = DAG.getConstantFP(0.0, dl, VT);
3320-
Tmp2 = DAG.getSetCC(dl, getSetCCResultType(Tmp1.getValueType()),
3321-
Tmp1, Tmp2, ISD::SETUGT);
3322-
Tmp3 = DAG.getNode(ISD::FNEG, dl, VT, Tmp1);
3323-
Tmp1 = DAG.getSelect(dl, VT, Tmp2, Tmp1, Tmp3);
3324-
Results.push_back(Tmp1);
3400+
case ISD::FABS:
3401+
Results.push_back(ExpandFABS(Node));
33253402
break;
3326-
}
33273403
case ISD::SMIN:
33283404
case ISD::SMAX:
33293405
case ISD::UMIN:

test/CodeGen/Thumb2/float-intrinsics-double.ll

+6-3
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,12 @@ declare double @llvm.fabs.f64(double %Val)
109109
define double @abs_d(double %a) {
110110
; CHECK-LABEL: abs_d:
111111
; NONE: bic r1, r1, #-2147483648
112-
; SP: bl __aeabi_dcmpgt
113-
; SP: bl __aeabi_dcmpun
114-
; SP: bl __aeabi_dsub
112+
; SP: vldr d1, .LCPI{{.*}}
113+
; SP: vmov r0, r1, d0
114+
; SP: vmov r2, r3, d1
115+
; SP: lsrs r2, r3, #31
116+
; SP: bfi r1, r2, #31, #1
117+
; SP: vmov d0, r0, r1
115118
; DP: vabs.f64 d0, d0
116119
%1 = call double @llvm.fabs.f64(double %a)
117120
ret double %1

test/CodeGen/X86/pr13577.ll

+1-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77

88
; CHECK-LABEL: foo:
99
; CHECK: movq {{.*}}, %rax
10-
; CHECK: shlq $48, %rax
11-
; CHECK: sets %al
12-
; CHECK: testb %al, %al
10+
; CHECK: testl $32768, %eax
1311
; CHECK: flds LCPI0_0(%rip)
1412
; CHECK: flds LCPI0_1(%rip)
1513
; CHECK: fcmovne %st(1), %st(0)

0 commit comments

Comments
 (0)