#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include <algorithm>
+#include <set>
using namespace llvm;
STATISTIC(NodesCombined , "Number of dag nodes combined");
void AddUsersToWorkList(SDNode *N) {
for (SDNode::use_iterator UI = N->use_begin(), UE = N->use_end();
UI != UE; ++UI)
- AddToWorkList(*UI);
+ AddToWorkList(UI->getUser());
}
/// visit - call the node-specific routine that knows how to fold each
SDOperand visitSIGN_EXTEND_INREG(SDNode *N);
SDOperand visitTRUNCATE(SDNode *N);
SDOperand visitBIT_CONVERT(SDNode *N);
+ SDOperand visitBUILD_PAIR(SDNode *N);
SDOperand visitFADD(SDNode *N);
SDOperand visitFSUB(SDNode *N);
SDOperand visitFMUL(SDNode *N);
ISD::CondCode Cond, bool foldBooleans = true);
SDOperand SimplifyNodeWithTwoResults(SDNode *N, unsigned LoOp,
unsigned HiOp);
+ SDOperand CombineConsecutiveLoads(SDNode *N, MVT::ValueType VT);
SDOperand ConstantFoldBIT_CONVERTofBUILD_VECTOR(SDNode *, MVT::ValueType);
SDOperand BuildSDIV(SDNode *N);
SDOperand BuildUDIV(SDNode *N);
case ISD::SIGN_EXTEND_INREG: return visitSIGN_EXTEND_INREG(N);
case ISD::TRUNCATE: return visitTRUNCATE(N);
case ISD::BIT_CONVERT: return visitBIT_CONVERT(N);
+ case ISD::BUILD_PAIR: return visitBUILD_PAIR(N);
case ISD::FADD: return visitFADD(N);
case ISD::FSUB: return visitFSUB(N);
case ISD::FMUL: return visitFMUL(N);
}
}
+ // If N is a commutative binary node, try commuting it to enable more
+ // sdisel CSE.
+ if (RV.Val == 0 &&
+ SelectionDAG::isCommutativeBinOp(N->getOpcode()) &&
+ N->getNumValues() == 1) {
+ SDOperand N0 = N->getOperand(0);
+ SDOperand N1 = N->getOperand(1);
+ // Constant operands are canonicalized to RHS.
+ if (isa<ConstantSDNode>(N0) || !isa<ConstantSDNode>(N1)) {
+ SDOperand Ops[] = { N1, N0 };
+ SDNode *CSENode = DAG.getNodeIfExists(N->getOpcode(), N->getVTList(),
+ Ops, 2);
+ if (CSENode)
+ return SDOperand(CSENode, 0);
+ }
+ }
+
return RV;
}
if (FoldedVOp.Val) return FoldedVOp;
}
+ // fold (xor undef, undef) -> 0. This is a common idiom (misuse).
+ if (N0.getOpcode() == ISD::UNDEF && N1.getOpcode() == ISD::UNDEF)
+ return DAG.getConstant(0, VT);
// fold (xor x, undef) -> undef
if (N0.getOpcode() == ISD::UNDEF)
return N0;
DAG.getConstant(Sum, N1C->getValueType(0)));
}
}
+
+ // fold sra (shl X, m), result_size - n
+ // -> (sign_extend (trunc (shl X, result_size - n - m))) for
+ // result_size - n != m.
+ // If truncate is free for the target sext(shl) is likely to result in better
+ // code.
+ if (N0.getOpcode() == ISD::SHL) {
+ // Get the two constanst of the shifts, CN0 = m, CN = n.
+ const ConstantSDNode *N01C = dyn_cast<ConstantSDNode>(N0.getOperand(1));
+ if (N01C && N1C) {
+ // Determine what the truncate's result bitsize and type would be.
+ unsigned VTValSize = MVT::getSizeInBits(VT);
+ MVT::ValueType TruncVT = MVT::getIntegerType(VTValSize - N1C->getValue());
+ // Determine the residual right-shift amount.
+ unsigned ShiftAmt = N1C->getValue() - N01C->getValue();
+
+ // If the shift is not a no-op (in which case this should be just a sign
+ // extend already), the truncated to type is legal, sign_extend is legal
+ // on that type, and the the truncate to that type is both legal and free,
+ // perform the transform.
+ if (ShiftAmt &&
+ TLI.isTypeLegal(TruncVT) &&
+ TLI.isOperationLegal(ISD::SIGN_EXTEND, TruncVT) &&
+ TLI.isOperationLegal(ISD::TRUNCATE, VT) &&
+ TLI.isTruncateFree(VT, TruncVT)) {
+
+ SDOperand Amt = DAG.getConstant(ShiftAmt, TLI.getShiftAmountTy());
+ SDOperand Shift = DAG.getNode(ISD::SRL, VT, N0.getOperand(0), Amt);
+ SDOperand Trunc = DAG.getNode(ISD::TRUNCATE, TruncVT, Shift);
+ return DAG.getNode(ISD::SIGN_EXTEND, N->getValueType(0), Trunc);
+ }
+ }
+ }
// Simplify, based on bits shifted out of the LHS.
if (N1C && SimplifyDemandedBits(SDOperand(N, 0)))
bool isTruncFree = TLI.isTruncateFree(N->getValueType(0), N0.getValueType());
for (SDNode::use_iterator UI = N0.Val->use_begin(), UE = N0.Val->use_end();
UI != UE; ++UI) {
- SDNode *User = *UI;
+ SDNode *User = UI->getUser();
if (User == N)
continue;
// FIXME: Only extend SETCC N, N and SETCC N, c for now.
bool BothLiveOut = false;
for (SDNode::use_iterator UI = N->use_begin(), UE = N->use_end();
UI != UE; ++UI) {
- SDNode *User = *UI;
+ SDNode *User = UI->getUser();
for (unsigned i = 0, e = User->getNumOperands(); i != e; ++i) {
SDOperand UseOp = User->getOperand(i);
if (UseOp.Val == N && UseOp.ResNo == 0) {
if (N0.getOpcode() == ISD::SIGN_EXTEND || N0.getOpcode() == ISD::ANY_EXTEND)
return DAG.getNode(ISD::SIGN_EXTEND, VT, N0.getOperand(0));
- // fold (sext (truncate (load x))) -> (sext (smaller load x))
- // fold (sext (truncate (srl (load x), c))) -> (sext (smaller load (x+c/n)))
if (N0.getOpcode() == ISD::TRUNCATE) {
+ // fold (sext (truncate (load x))) -> (sext (smaller load x))
+ // fold (sext (truncate (srl (load x), c))) -> (sext (smaller load (x+c/n)))
SDOperand NarrowLoad = ReduceLoadWidth(N0.Val);
if (NarrowLoad.Val) {
if (NarrowLoad.Val != N0.Val)
CombineTo(N0.Val, NarrowLoad);
return DAG.getNode(ISD::SIGN_EXTEND, VT, NarrowLoad);
}
- }
- // See if the value being truncated is already sign extended. If so, just
- // eliminate the trunc/sext pair.
- if (N0.getOpcode() == ISD::TRUNCATE) {
+ // See if the value being truncated is already sign extended. If so, just
+ // eliminate the trunc/sext pair.
SDOperand Op = N0.getOperand(0);
unsigned OpBits = MVT::getSizeInBits(Op.getValueType());
unsigned MidBits = MVT::getSizeInBits(N0.getValueType());
if (SCC.Val) return SCC;
}
+ // fold (sext x) -> (zext x) if the sign bit is known zero.
+ if ((!AfterLegalize || TLI.isOperationLegal(ISD::ZERO_EXTEND, VT)) &&
+ DAG.SignBitIsZero(N0))
+ return DAG.getNode(ISD::ZERO_EXTEND, VT, N0);
+
return SDOperand();
}
return ReduceLoadWidth(N);
}
+static SDNode *getBuildPairElt(SDNode *N, unsigned i) {
+ SDOperand Elt = N->getOperand(i);
+ if (Elt.getOpcode() != ISD::MERGE_VALUES)
+ return Elt.Val;
+ return Elt.getOperand(Elt.ResNo).Val;
+}
+
+/// CombineConsecutiveLoads - build_pair (load, load) -> load
+/// if load locations are consecutive.
+SDOperand DAGCombiner::CombineConsecutiveLoads(SDNode *N, MVT::ValueType VT) {
+ assert(N->getOpcode() == ISD::BUILD_PAIR);
+
+ SDNode *LD1 = getBuildPairElt(N, 0);
+ if (!ISD::isNON_EXTLoad(LD1) || !LD1->hasOneUse())
+ return SDOperand();
+ MVT::ValueType LD1VT = LD1->getValueType(0);
+ SDNode *LD2 = getBuildPairElt(N, 1);
+ const MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+ if (ISD::isNON_EXTLoad(LD2) &&
+ LD2->hasOneUse() &&
+ TLI.isConsecutiveLoad(LD2, LD1, MVT::getSizeInBits(LD1VT)/8, 1, MFI)) {
+ LoadSDNode *LD = cast<LoadSDNode>(LD1);
+ unsigned Align = LD->getAlignment();
+ unsigned NewAlign = TLI.getTargetMachine().getTargetData()->
+ getABITypeAlignment(MVT::getTypeForValueType(VT));
+ if ((!AfterLegalize || TLI.isTypeLegal(VT)) &&
+ TLI.isOperationLegal(ISD::LOAD, VT) && NewAlign <= Align)
+ return DAG.getLoad(VT, LD->getChain(), LD->getBasePtr(),
+ LD->getSrcValue(), LD->getSrcValueOffset(),
+ LD->isVolatile(), Align);
+ }
+ return SDOperand();
+}
+
SDOperand DAGCombiner::visitBIT_CONVERT(SDNode *N) {
SDOperand N0 = N->getOperand(0);
MVT::ValueType VT = N->getValueType(0);
return DAG.getNode(ISD::OR, VT, X, Cst);
}
+
+ // bitconvert(build_pair(ld, ld)) -> ld iff load locations are consecutive.
+ if (N0.getOpcode() == ISD::BUILD_PAIR) {
+ SDOperand CombineLD = CombineConsecutiveLoads(N0.Val, VT);
+ if (CombineLD.Val)
+ return CombineLD;
+ }
return SDOperand();
}
+SDOperand DAGCombiner::visitBUILD_PAIR(SDNode *N) {
+ MVT::ValueType VT = N->getValueType(0);
+ return CombineConsecutiveLoads(N, VT);
+}
+
/// ConstantFoldBIT_CONVERTofBUILD_VECTOR - We know that BV is a build_vector
/// node with Constant, ConstantFP or Undef operands. DstEltVT indicates the
/// destination element value type.
MVT::ValueType VT = N->getValueType(0);
// If this is fp_round(fpextend), don't fold it, allow ourselves to be folded.
- if (N->hasOneUse() && (*N->use_begin())->getOpcode() == ISD::FP_ROUND)
+ if (N->hasOneUse() &&
+ N->use_begin()->getSDOperand().getOpcode() == ISD::FP_ROUND)
return SDOperand();
// fold (fp_extend c1fp) -> c1fp
bool RealUse = false;
for (SDNode::use_iterator I = Ptr.Val->use_begin(),
E = Ptr.Val->use_end(); I != E; ++I) {
- SDNode *Use = *I;
+ SDNode *Use = I->getUser();
if (Use == N)
continue;
if (Use->isPredecessorOf(N))
for (SDNode::use_iterator I = Ptr.Val->use_begin(),
E = Ptr.Val->use_end(); I != E; ++I) {
- SDNode *Op = *I;
+ SDNode *Op = I->getUser();
if (Op == N ||
(Op->getOpcode() != ISD::ADD && Op->getOpcode() != ISD::SUB))
continue;
bool TryNext = false;
for (SDNode::use_iterator II = BasePtr.Val->use_begin(),
EE = BasePtr.Val->use_end(); II != EE; ++II) {
- SDNode *Use = *II;
+ SDNode *Use = II->getUser();
if (Use == Ptr.Val)
continue;
bool RealUse = false;
for (SDNode::use_iterator III = Use->use_begin(),
EEE = Use->use_end(); III != EEE; ++III) {
- SDNode *UseUse = *III;
+ SDNode *UseUse = III->getUser();
if (!((UseUse->getOpcode() == ISD::LOAD &&
cast<LoadSDNode>(UseUse)->getBasePtr().Val == Use) ||
(UseUse->getOpcode() == ISD::STORE &&
// value.
// TODO: Handle store large -> read small portion.
// TODO: Handle TRUNCSTORE/LOADEXT
- if (LD->getExtensionType() == ISD::NON_EXTLOAD) {
+ if (LD->getExtensionType() == ISD::NON_EXTLOAD &&
+ !LD->isVolatile()) {
if (ISD::isNON_TRUNCStore(Chain.Val)) {
StoreSDNode *PrevST = cast<StoreSDNode>(Chain);
if (PrevST->getBasePtr() == Ptr &&
}
SDOperand DAGCombiner::visitEXTRACT_VECTOR_ELT(SDNode *N) {
+ // (vextract (v4f32 load $addr), c) -> (f32 load $addr+c*size)
+ // (vextract (v4f32 s2v (f32 load $addr)), c) -> (f32 load $addr+c*size)
+ // (vextract (v4f32 shuffle (load $addr), <1,u,u,u>), 0) -> (f32 load $addr)
+
+ // Perform only after legalization to ensure build_vector / vector_shuffle
+ // optimizations have already been done.
+ if (!AfterLegalize) return SDOperand();
+
SDOperand InVec = N->getOperand(0);
SDOperand EltNo = N->getOperand(1);
- // (vextract (v4f32 s2v (f32 load $addr)), 0) -> (f32 load $addr)
- // (vextract (v4i32 bc (v4f32 s2v (f32 load $addr))), 0) -> (i32 load $addr)
if (isa<ConstantSDNode>(EltNo)) {
unsigned Elt = cast<ConstantSDNode>(EltNo)->getValue();
bool NewLoad = false;
- if (Elt == 0) {
- MVT::ValueType VT = InVec.getValueType();
- MVT::ValueType EVT = MVT::getVectorElementType(VT);
- MVT::ValueType LVT = EVT;
- unsigned NumElts = MVT::getVectorNumElements(VT);
- if (InVec.getOpcode() == ISD::BIT_CONVERT) {
- MVT::ValueType BCVT = InVec.getOperand(0).getValueType();
- if (!MVT::isVector(BCVT) ||
- NumElts != MVT::getVectorNumElements(BCVT))
- return SDOperand();
+ MVT::ValueType VT = InVec.getValueType();
+ MVT::ValueType EVT = MVT::getVectorElementType(VT);
+ MVT::ValueType LVT = EVT;
+ if (InVec.getOpcode() == ISD::BIT_CONVERT) {
+ MVT::ValueType BCVT = InVec.getOperand(0).getValueType();
+ if (!MVT::isVector(BCVT)
+ || (MVT::getSizeInBits(EVT) >
+ MVT::getSizeInBits(MVT::getVectorElementType(BCVT))))
+ return SDOperand();
+ InVec = InVec.getOperand(0);
+ EVT = MVT::getVectorElementType(BCVT);
+ NewLoad = true;
+ }
+
+ LoadSDNode *LN0 = NULL;
+ if (ISD::isNormalLoad(InVec.Val))
+ LN0 = cast<LoadSDNode>(InVec);
+ else if (InVec.getOpcode() == ISD::SCALAR_TO_VECTOR &&
+ InVec.getOperand(0).getValueType() == EVT &&
+ ISD::isNormalLoad(InVec.getOperand(0).Val)) {
+ LN0 = cast<LoadSDNode>(InVec.getOperand(0));
+ } else if (InVec.getOpcode() == ISD::VECTOR_SHUFFLE) {
+ // (vextract (vector_shuffle (load $addr), v2, <1, u, u, u>), 1)
+ // =>
+ // (load $addr+1*size)
+ unsigned Idx = cast<ConstantSDNode>(InVec.getOperand(2).
+ getOperand(Elt))->getValue();
+ unsigned NumElems = InVec.getOperand(2).getNumOperands();
+ InVec = (Idx < NumElems) ? InVec.getOperand(0) : InVec.getOperand(1);
+ if (InVec.getOpcode() == ISD::BIT_CONVERT)
InVec = InVec.getOperand(0);
- EVT = MVT::getVectorElementType(BCVT);
- NewLoad = true;
+ if (ISD::isNormalLoad(InVec.Val)) {
+ LN0 = cast<LoadSDNode>(InVec);
+ Elt = (Idx < NumElems) ? Idx : Idx - NumElems;
}
- if (InVec.getOpcode() == ISD::SCALAR_TO_VECTOR &&
- InVec.getOperand(0).getValueType() == EVT &&
- ISD::isNormalLoad(InVec.getOperand(0).Val) &&
- InVec.getOperand(0).hasOneUse()) {
- LoadSDNode *LN0 = cast<LoadSDNode>(InVec.getOperand(0));
- unsigned Align = LN0->getAlignment();
- if (NewLoad) {
- // Check the resultant load doesn't need a higher alignment than the
- // original load.
- unsigned NewAlign = TLI.getTargetMachine().getTargetData()->
- getABITypeAlignment(MVT::getTypeForValueType(LVT));
- if (!TLI.isOperationLegal(ISD::LOAD, LVT) || NewAlign > Align)
- return SDOperand();
- Align = NewAlign;
- }
+ }
+ if (!LN0 || !LN0->hasOneUse())
+ return SDOperand();
- return DAG.getLoad(LVT, LN0->getChain(), LN0->getBasePtr(),
- LN0->getSrcValue(), LN0->getSrcValueOffset(),
- LN0->isVolatile(), Align);
- }
+ unsigned Align = LN0->getAlignment();
+ if (NewLoad) {
+ // Check the resultant load doesn't need a higher alignment than the
+ // original load.
+ unsigned NewAlign = TLI.getTargetMachine().getTargetData()->
+ getABITypeAlignment(MVT::getTypeForValueType(LVT));
+ if (!TLI.isOperationLegal(ISD::LOAD, LVT) || NewAlign > Align)
+ return SDOperand();
+ Align = NewAlign;
+ }
+
+ SDOperand NewPtr = LN0->getBasePtr();
+ if (Elt) {
+ unsigned PtrOff = MVT::getSizeInBits(LVT) * Elt / 8;
+ MVT::ValueType PtrType = NewPtr.getValueType();
+ if (TLI.isBigEndian())
+ PtrOff = MVT::getSizeInBits(VT) / 8 - PtrOff;
+ NewPtr = DAG.getNode(ISD::ADD, PtrType, NewPtr,
+ DAG.getConstant(PtrOff, PtrType));
}
+ return DAG.getLoad(LVT, LN0->getChain(), NewPtr,
+ LN0->getSrcValue(), LN0->getSrcValueOffset(),
+ LN0->isVolatile(), Align);
}
return SDOperand();
}