From: Chris Lattner Date: Mon, 14 May 2007 22:04:50 +0000 (+0000) Subject: implement a simple fneg optimization/propagation thing. This compiles: X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=2944652569d1beb538f5a72ab1a4bb581ea5cf91;p=oota-llvm.git implement a simple fneg optimization/propagation thing. This compiles: CodeGen/PowerPC/fneg.ll into: _t4: fmul f0, f3, f4 fmadd f1, f1, f2, f0 blr instead of: _t4: fneg f0, f3 fmul f0, f0, f4 fmsub f1, f1, f2, f0 blr git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@37054 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 744a474ba4e..fd2ad5cd4c9 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -344,9 +344,114 @@ CombineTo(SDNode *N, SDOperand Res0, SDOperand Res1) { } +//===----------------------------------------------------------------------===// +// Helper Functions +//===----------------------------------------------------------------------===// +/// isNegatibleForFree - Return 1 if we can compute the negated form of the +/// specified expression for the same cost as the expression itself, or 2 if we +/// can compute the negated form more cheaply than the expression itself. +static char isNegatibleForFree(SDOperand Op) { + // fneg is removable even if it has multiple uses. + if (Op.getOpcode() == ISD::FNEG) return 2; + + // Don't allow anything with multiple uses. + if (!Op.hasOneUse()) return 0; + + switch (Op.getOpcode()) { + default: return false; + case ISD::ConstantFP: + return 1; + case ISD::FADD: + // FIXME: determine better conditions for this xform. + if (!UnsafeFPMath) return 0; + + // -(A+B) -> -A - B + if (char V = isNegatibleForFree(Op.getOperand(0))) + return V; + // -(A+B) -> -B - A + return isNegatibleForFree(Op.getOperand(1)); + case ISD::FSUB: + // We can't turn -(A-B) into B-A when we honor signed zeros. + if (!UnsafeFPMath) return 0; + + // -(A-B) -> B-A + return 1; + + case ISD::FMUL: + case ISD::FDIV: + if (HonorSignDependentRoundingFPMath()) return 0; + + // -(X*Y) -> (-X * Y) or (X*-Y) + if (char V = isNegatibleForFree(Op.getOperand(0))) + return V; + + return isNegatibleForFree(Op.getOperand(1)); + + case ISD::FP_EXTEND: + case ISD::FP_ROUND: + case ISD::FSIN: + return isNegatibleForFree(Op.getOperand(0)); + } +} -//===----------------------------------------------------------------------===// +/// GetNegatedExpression - If isNegatibleForFree returns true, this function +/// returns the newly negated expression. +static SDOperand GetNegatedExpression(SDOperand Op, SelectionDAG &DAG) { + // fneg is removable even if it has multiple uses. + if (Op.getOpcode() == ISD::FNEG) return Op.getOperand(0); + + // Don't allow anything with multiple uses. + assert(Op.hasOneUse() && "Unknown reuse!"); + + switch (Op.getOpcode()) { + default: assert(0 && "Unknown code"); + case ISD::ConstantFP: + return DAG.getConstantFP(-cast(Op)->getValue(), + Op.getValueType()); + case ISD::FADD: + // FIXME: determine better conditions for this xform. + assert(UnsafeFPMath); + + // -(A+B) -> -A - B + if (isNegatibleForFree(Op.getOperand(0))) + return DAG.getNode(ISD::FSUB, Op.getValueType(), + GetNegatedExpression(Op.getOperand(0), DAG), + Op.getOperand(1)); + // -(A+B) -> -B - A + return DAG.getNode(ISD::FSUB, Op.getValueType(), + GetNegatedExpression(Op.getOperand(1), DAG), + Op.getOperand(0)); + case ISD::FSUB: + // We can't turn -(A-B) into B-A when we honor signed zeros. + assert(UnsafeFPMath); + + // -(A-B) -> B-A + return DAG.getNode(ISD::FSUB, Op.getValueType(), Op.getOperand(1), + Op.getOperand(0)); + + case ISD::FMUL: + case ISD::FDIV: + assert(!HonorSignDependentRoundingFPMath()); + + // -(X*Y) -> -X * Y + if (isNegatibleForFree(Op.getOperand(0))) + return DAG.getNode(Op.getOpcode(), Op.getValueType(), + GetNegatedExpression(Op.getOperand(0), DAG), + Op.getOperand(1)); + + // -(X*Y) -> X * -Y + return DAG.getNode(Op.getOpcode(), Op.getValueType(), + Op.getOperand(0), + GetNegatedExpression(Op.getOperand(1), DAG)); + + case ISD::FP_EXTEND: + case ISD::FP_ROUND: + case ISD::FSIN: + return DAG.getNode(Op.getOpcode(), Op.getValueType(), + GetNegatedExpression(Op, DAG)); + } +} // isSetCCEquivalent - Return true if this node is a setcc, or is a select_cc @@ -416,6 +521,10 @@ SDOperand DAGCombiner::ReassociateOps(unsigned Opc, SDOperand N0, SDOperand N1){ return SDOperand(); } +//===----------------------------------------------------------------------===// +// Main DAG Combiner implementation +//===----------------------------------------------------------------------===// + void DAGCombiner::Run(bool RunningAfterLegalize) { // set the instance variable, so that the various visit routines may use it. AfterLegalize = RunningAfterLegalize; @@ -2743,11 +2852,11 @@ SDOperand DAGCombiner::visitFADD(SDNode *N) { if (N0CFP && !N1CFP) return DAG.getNode(ISD::FADD, VT, N1, N0); // fold (A + (-B)) -> A-B - if (N1.getOpcode() == ISD::FNEG) - return DAG.getNode(ISD::FSUB, VT, N0, N1.getOperand(0)); + if (isNegatibleForFree(N1) == 2) + return DAG.getNode(ISD::FSUB, VT, N0, GetNegatedExpression(N1, DAG)); // fold ((-A) + B) -> B-A - if (N0.getOpcode() == ISD::FNEG) - return DAG.getNode(ISD::FSUB, VT, N1, N0.getOperand(0)); + if (isNegatibleForFree(N0) == 2) + return DAG.getNode(ISD::FSUB, VT, N1, GetNegatedExpression(N0, DAG)); // If allowed, fold (fadd (fadd x, c1), c2) -> (fadd x, (fadd c1, c2)) if (UnsafeFPMath && N1CFP && N0.getOpcode() == ISD::FADD && @@ -2769,8 +2878,9 @@ SDOperand DAGCombiner::visitFSUB(SDNode *N) { if (N0CFP && N1CFP) return DAG.getNode(ISD::FSUB, VT, N0, N1); // fold (A-(-B)) -> A+B - if (N1.getOpcode() == ISD::FNEG) - return DAG.getNode(ISD::FADD, VT, N0, N1.getOperand(0)); + if (isNegatibleForFree(N1)) + return DAG.getNode(ISD::FADD, VT, N0, GetNegatedExpression(N1, DAG)); + return SDOperand(); } @@ -2790,6 +2900,20 @@ SDOperand DAGCombiner::visitFMUL(SDNode *N) { // fold (fmul X, 2.0) -> (fadd X, X) if (N1CFP && N1CFP->isExactlyValue(+2.0)) return DAG.getNode(ISD::FADD, VT, N0, N0); + // fold (fmul X, -1.0) -> (fneg X) + if (N1CFP && N1CFP->isExactlyValue(-1.0)) + return DAG.getNode(ISD::FNEG, VT, N0); + + // -X * -Y -> X*Y + if (char LHSNeg = isNegatibleForFree(N0)) { + if (char RHSNeg = isNegatibleForFree(N1)) { + // Both can be negated for free, check to see if at least one is cheaper + // negated. + if (LHSNeg == 2 || RHSNeg == 2) + return DAG.getNode(ISD::FMUL, VT, GetNegatedExpression(N0, DAG), + GetNegatedExpression(N1, DAG)); + } + } // If allowed, fold (fmul (fmul x, c1), c2) -> (fmul x, (fmul c1, c2)) if (UnsafeFPMath && N1CFP && N0.getOpcode() == ISD::FMUL && @@ -2810,6 +2934,19 @@ SDOperand DAGCombiner::visitFDIV(SDNode *N) { // fold (fdiv c1, c2) -> c1/c2 if (N0CFP && N1CFP) return DAG.getNode(ISD::FDIV, VT, N0, N1); + + + // -X / -Y -> X*Y + if (char LHSNeg = isNegatibleForFree(N0)) { + if (char RHSNeg = isNegatibleForFree(N1)) { + // Both can be negated for free, check to see if at least one is cheaper + // negated. + if (LHSNeg == 2 || RHSNeg == 2) + return DAG.getNode(ISD::FDIV, VT, GetNegatedExpression(N0, DAG), + GetNegatedExpression(N1, DAG)); + } + } + return SDOperand(); }