summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2008-01-27 17:42:27 +0000
committerChris Lattner <sabre@nondot.org>2008-01-27 17:42:27 +0000
commit888560d62cce384f0fe90f00f93b4c44851666db (patch)
tree574590dadd87201bbe75f29838bc52ba45ec525e /llvm
parent2e4719ec554494cfb6e4f97cc084437a993780bf (diff)
downloadbcm5719-llvm-888560d62cce384f0fe90f00f93b4c44851666db.tar.gz
bcm5719-llvm-888560d62cce384f0fe90f00f93b4c44851666db.zip
Implement some dag combines that allow doing fneg/fabs/fcopysign in integer
registers if used by a bitconvert or using a bitconvert. This allows us to avoid constant pool loads and use cheaper integer instructions when the values come from or end up in integer regs anyway. For example, we now compile CodeGen/X86/fp-in-intregs.ll to: _test1: movl $2147483648, %eax xorl 4(%esp), %eax ret _test2: movl $1065353216, %eax orl 4(%esp), %eax andl $3212836864, %eax ret Instead of: _test1: movss 4(%esp), %xmm0 xorps LCPI2_0, %xmm0 movd %xmm0, %eax ret _test2: movss 4(%esp), %xmm0 andps LCPI3_0, %xmm0 movss LCPI3_1, %xmm1 andps LCPI3_2, %xmm1 orps %xmm0, %xmm1 movd %xmm1, %eax ret bitconverts can happen due to various calling conventions that require fp values to passed in integer regs in some cases, e.g. when returning a complex. llvm-svn: 46414
Diffstat (limited to 'llvm')
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp81
-rw-r--r--llvm/test/CodeGen/X86/fp-in-intregs.ll21
2 files changed, 100 insertions, 2 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 473f9080ef3..2c2f5e95b06 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -1190,7 +1190,7 @@ SDOperand DAGCombiner::visitSDIV(SDNode *N) {
return DAG.getNode(ISD::SUB, VT, DAG.getConstant(0, VT), N0);
// If we know the sign bits of both operands are zero, strength reduce to a
// udiv instead. Handles (X&15) /s 4 -> X&15 >> 2
- uint64_t SignBit = 1ULL << (MVT::getSizeInBits(VT)-1);
+ uint64_t SignBit = MVT::getIntVTSignBit(VT);
if (DAG.MaskedValueIsZero(N1, SignBit) &&
DAG.MaskedValueIsZero(N0, SignBit))
return DAG.getNode(ISD::UDIV, N1.getValueType(), N0, N1);
@@ -1306,7 +1306,7 @@ SDOperand DAGCombiner::visitSREM(SDNode *N) {
return DAG.getNode(ISD::SREM, VT, N0, N1);
// If we know the sign bits of both operands are zero, strength reduce to a
// urem instead. Handles (X & 0x0FFFFFFF) %s 16 -> X&15
- uint64_t SignBit = 1ULL << (MVT::getSizeInBits(VT)-1);
+ uint64_t SignBit = MVT::getIntVTSignBit(VT);
if (DAG.MaskedValueIsZero(N1, SignBit) &&
DAG.MaskedValueIsZero(N0, SignBit))
return DAG.getNode(ISD::UREM, VT, N0, N1);
@@ -3276,6 +3276,57 @@ SDOperand DAGCombiner::visitBIT_CONVERT(SDNode *N) {
}
}
+ // Fold bitconvert(fneg(x)) -> xor(bitconvert(x), signbit)
+ // Fold bitconvert(fabs(x)) -> and(bitconvert(x), ~signbit)
+ // This often reduces constant pool loads.
+ if ((N0.getOpcode() == ISD::FNEG || N0.getOpcode() == ISD::FABS) &&
+ N0.Val->hasOneUse() && MVT::isInteger(VT) && !MVT::isVector(VT)) {
+ SDOperand NewConv = DAG.getNode(ISD::BIT_CONVERT, VT, N0.getOperand(0));
+ AddToWorkList(NewConv.Val);
+
+ uint64_t SignBit = MVT::getIntVTSignBit(VT);
+ if (N0.getOpcode() == ISD::FNEG)
+ return DAG.getNode(ISD::XOR, VT, NewConv, DAG.getConstant(SignBit, VT));
+ assert(N0.getOpcode() == ISD::FABS);
+ return DAG.getNode(ISD::AND, VT, NewConv, DAG.getConstant(~SignBit, VT));
+ }
+
+ // Fold bitconvert(fcopysign(cst, x)) -> bitconvert(x)&sign | cst&~sign'
+ // Note that we don't handle copysign(x,cst) because this can always be folded
+ // to an fneg or fabs.
+ if (N0.getOpcode() == ISD::FCOPYSIGN && N0.Val->hasOneUse() &&
+ isa<ConstantFPSDNode>(N0.getOperand(0))) {
+ unsigned OrigXWidth = MVT::getSizeInBits(N0.getOperand(1).getValueType());
+ SDOperand X = DAG.getNode(ISD::BIT_CONVERT, MVT::getIntegerType(OrigXWidth),
+ N0.getOperand(1));
+ AddToWorkList(X.Val);
+
+ // If X has a different width than the result/lhs, sext it or truncate it.
+ unsigned VTWidth = MVT::getSizeInBits(VT);
+ if (OrigXWidth < VTWidth) {
+ X = DAG.getNode(ISD::SIGN_EXTEND, VT, X);
+ AddToWorkList(X.Val);
+ } else if (OrigXWidth > VTWidth) {
+ // To get the sign bit in the right place, we have to shift it right
+ // before truncating.
+ X = DAG.getNode(ISD::SRL, X.getValueType(), X,
+ DAG.getConstant(OrigXWidth-VTWidth, X.getValueType()));
+ AddToWorkList(X.Val);
+ X = DAG.getNode(ISD::TRUNCATE, VT, X);
+ AddToWorkList(X.Val);
+ }
+
+ uint64_t SignBit = MVT::getIntVTSignBit(VT);
+ X = DAG.getNode(ISD::AND, VT, X, DAG.getConstant(SignBit, VT));
+ AddToWorkList(X.Val);
+
+ SDOperand Cst = DAG.getNode(ISD::BIT_CONVERT, VT, N0.getOperand(0));
+ Cst = DAG.getNode(ISD::AND, VT, Cst, DAG.getConstant(~SignBit, VT));
+ AddToWorkList(Cst.Val);
+
+ return DAG.getNode(ISD::OR, VT, X, Cst);
+ }
+
return SDOperand();
}
@@ -3732,6 +3783,19 @@ SDOperand DAGCombiner::visitFNEG(SDNode *N) {
if (isNegatibleForFree(N0))
return GetNegatedExpression(N0, DAG);
+ // Transform fneg(bitconvert(x)) -> bitconvert(x^sign) to avoid loading
+ // constant pool values.
+ if (N0.getOpcode() == ISD::BIT_CONVERT && N0.Val->hasOneUse()) {
+ SDOperand Int = N0.getOperand(0);
+ MVT::ValueType IntVT = Int.getValueType();
+ if (MVT::isInteger(IntVT) && !MVT::isVector(IntVT)) {
+ Int = DAG.getNode(ISD::XOR, IntVT, Int,
+ DAG.getConstant(MVT::getIntVTSignBit(IntVT), IntVT));
+ AddToWorkList(Int.Val);
+ return DAG.getNode(ISD::BIT_CONVERT, N->getValueType(0), Int);
+ }
+ }
+
return SDOperand();
}
@@ -3751,6 +3815,19 @@ SDOperand DAGCombiner::visitFABS(SDNode *N) {
if (N0.getOpcode() == ISD::FNEG || N0.getOpcode() == ISD::FCOPYSIGN)
return DAG.getNode(ISD::FABS, VT, N0.getOperand(0));
+ // Transform fabs(bitconvert(x)) -> bitconvert(x&~sign) to avoid loading
+ // constant pool values.
+ if (N0.getOpcode() == ISD::BIT_CONVERT && N0.Val->hasOneUse()) {
+ SDOperand Int = N0.getOperand(0);
+ MVT::ValueType IntVT = Int.getValueType();
+ if (MVT::isInteger(IntVT) && !MVT::isVector(IntVT)) {
+ Int = DAG.getNode(ISD::AND, IntVT, Int,
+ DAG.getConstant(~MVT::getIntVTSignBit(IntVT), IntVT));
+ AddToWorkList(Int.Val);
+ return DAG.getNode(ISD::BIT_CONVERT, N->getValueType(0), Int);
+ }
+ }
+
return SDOperand();
}
diff --git a/llvm/test/CodeGen/X86/fp-in-intregs.ll b/llvm/test/CodeGen/X86/fp-in-intregs.ll
new file mode 100644
index 00000000000..1e3ea8918dc
--- /dev/null
+++ b/llvm/test/CodeGen/X86/fp-in-intregs.ll
@@ -0,0 +1,21 @@
+; RUN: llvm-as < %s | llc -march=x86 -mcpu=yonah | not egrep {\(\(xor\|and\)ps\|movd\)}
+
+; These operations should be done in integer registers, eliminating constant
+; pool loads, movd's etc.
+
+define i32 @test1(float %x) nounwind {
+entry:
+ %tmp2 = sub float -0.000000e+00, %x ; <float> [#uses=1]
+ %tmp210 = bitcast float %tmp2 to i32 ; <i32> [#uses=1]
+ ret i32 %tmp210
+}
+
+define i32 @test2(float %x) nounwind {
+entry:
+ %tmp2 = tail call float @copysignf( float 1.000000e+00, float %x ) nounwind readnone ; <float> [#uses=1]
+ %tmp210 = bitcast float %tmp2 to i32 ; <i32> [#uses=1]
+ ret i32 %tmp210
+}
+
+declare float @copysignf(float, float) nounwind readnone
+
OpenPOWER on IntegriCloud