#define DEBUG_TYPE "dagcombine"
#include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
+#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetLowering.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/CommandLine.h"
#include <algorithm>
-#include <cmath>
-#include <iostream>
-#include <algorithm>
using namespace llvm;
+STATISTIC(NodesCombined , "Number of dag nodes combined");
+STATISTIC(PreIndexedNodes , "Number of pre-indexed nodes created");
+STATISTIC(PostIndexedNodes, "Number of post-indexed nodes created");
+
namespace {
- static Statistic<> NodesCombined ("dagcombiner",
- "Number of dag nodes combined");
-
-
-static cl::opt<bool>
- CombinerAA("combiner-alias-analysis", cl::Hidden,
- cl::desc("Turn on alias analysis turning testing"));
-
-
-/// FindBaseOffset - Return true if base is known not to alias with anything
-/// but itself. Provides base object and offset as results.
-bool FindBaseOffset(SDOperand Ptr, SDOperand &Object, int64_t &Offset) {
- // If it's an adding or subtracting a simple constant then add the constant
- // to the offset.
- if (Ptr.getOpcode() == ISD::ADD) {
- if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Ptr.getOperand(1))) {
- bool IsNonAliasing = FindBaseOffset(Ptr.getOperand(0), Object, Offset);
- Offset += C->getValue();
- return IsNonAliasing;
- }
- } else if (Ptr.getOpcode() == ISD::SUB) {
- // FIXME - Aren't all subtract constants converted to add negative constant.
- if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Ptr.getOperand(1))) {
- bool IsNonAliasing = FindBaseOffset(Ptr.getOperand(0), Object, Offset);
- Offset -= C->getValue();
- return IsNonAliasing;
- }
- }
-
- // Primitive operation.
- Object = Ptr; Offset = 0;
+#ifndef NDEBUG
+ static cl::opt<bool>
+ ViewDAGCombine1("view-dag-combine1-dags", cl::Hidden,
+ cl::desc("Pop up a window to show dags before the first "
+ "dag combine pass"));
+ static cl::opt<bool>
+ ViewDAGCombine2("view-dag-combine2-dags", cl::Hidden,
+ cl::desc("Pop up a window to show dags before the second "
+ "dag combine pass"));
+#else
+ static const bool ViewDAGCombine1 = false;
+ static const bool ViewDAGCombine2 = false;
+#endif
- // If it's any of the following then it can't alias with anything but itself.
- return isa<FrameIndexSDNode>(Ptr) ||
- isa<ConstantPoolSDNode>(Ptr) ||
- isa<GlobalAddressSDNode>(Ptr);
-}
+ static cl::opt<bool>
+ CombinerAA("combiner-alias-analysis", cl::Hidden,
+ cl::desc("Turn on alias analysis during testing"));
-/// isAlias - Return true if there is any possibility that the two addresses
-/// overlap.
-bool isAlias(SDOperand Ptr1, int64_t Size1, SDOperand SrcValue1,
- SDOperand Ptr2, int64_t Size2, SDOperand SrcValue2) {
- // If they are the same then they must be aliases.
- if (Ptr1 == Ptr2) return true;
-
- // Gather base node and offset information.
- SDOperand Object1, Object2;
- int64_t Offset1, Offset2;
- bool IsNonAliasing1 = FindBaseOffset(Ptr1, Object1, Offset1);
- bool IsNonAliasing2 = FindBaseOffset(Ptr2, Object2, Offset2);
-
- // If they have a same base address then...
- if (Object1 == Object2) {
- // Check to see if the addresses overlap.
- return !((Offset1 + Size1) <= Offset2 || (Offset2 + Size2) <= Offset1);
- }
-
- // Otherwise they alias if they are both non aliasing.
- return !IsNonAliasing1 && IsNonAliasing2;
-}
-
-/// FindAliasInfo - Extracts the relevant alias information from the memory
-/// node. Returns true if the operand was a load.
-bool FindAliasInfo(SDNode *N,
- SDOperand &Ptr, int64_t &Size, SDOperand &SrcValue) {
- switch (N->getOpcode()) {
- case ISD::LOAD:
- Ptr = N->getOperand(1);
- Size = MVT::getSizeInBits(N->getValueType(0)) >> 3;
- SrcValue = N->getOperand(2);
- return true;
- case ISD::STORE:
- Ptr = N->getOperand(2);
- Size = MVT::getSizeInBits(N->getOperand(1).getValueType()) >> 3;
- SrcValue = N->getOperand(3);
- return false;
- default:
- assert(0 && "FindAliasInfo expected a memory operand");
- return false;
- }
-
- return false;
-}
+ static cl::opt<bool>
+ CombinerGlobalAA("combiner-global-alias-analysis", cl::Hidden,
+ cl::desc("Include global information in alias analysis"));
//------------------------------ DAGCombiner ---------------------------------//
-class VISIBILITY_HIDDEN DAGCombiner {
+ class VISIBILITY_HIDDEN DAGCombiner {
SelectionDAG &DAG;
TargetLowering &TLI;
bool AfterLegalize;
// Worklist of all of the nodes that need to be simplified.
std::vector<SDNode*> WorkList;
+ // AA - Used for DAG load/store alias analysis.
+ AliasAnalysis &AA;
+
/// AddUsersToWorkList - When an instruction is simplified, add all users of
/// the instruction to the work lists because they might get more simplified
/// now.
WorkList.push_back(N);
}
- SDOperand CombineTo(SDNode *N, const SDOperand *To, unsigned NumTo) {
+ SDOperand CombineTo(SDNode *N, const SDOperand *To, unsigned NumTo,
+ bool AddTo = true) {
assert(N->getNumValues() == NumTo && "Broken CombineTo call!");
++NodesCombined;
- DEBUG(std::cerr << "\nReplacing.1 "; N->dump();
- std::cerr << "\nWith: "; To[0].Val->dump(&DAG);
- std::cerr << " and " << NumTo-1 << " other values\n");
+ DOUT << "\nReplacing.1 "; DEBUG(N->dump());
+ DOUT << "\nWith: "; DEBUG(To[0].Val->dump(&DAG));
+ DOUT << " and " << NumTo-1 << " other values\n";
std::vector<SDNode*> NowDead;
DAG.ReplaceAllUsesWith(N, To, &NowDead);
- // Push the new nodes and any users onto the worklist
- for (unsigned i = 0, e = NumTo; i != e; ++i) {
- AddToWorkList(To[i].Val);
- AddUsersToWorkList(To[i].Val);
+ if (AddTo) {
+ // Push the new nodes and any users onto the worklist
+ for (unsigned i = 0, e = NumTo; i != e; ++i) {
+ AddToWorkList(To[i].Val);
+ AddUsersToWorkList(To[i].Val);
+ }
}
// Nodes can be reintroduced into the worklist. Make sure we do not
return SDOperand(N, 0);
}
- SDOperand CombineTo(SDNode *N, SDOperand Res) {
- return CombineTo(N, &Res, 1);
+ SDOperand CombineTo(SDNode *N, SDOperand Res, bool AddTo = true) {
+ return CombineTo(N, &Res, 1, AddTo);
}
- SDOperand CombineTo(SDNode *N, SDOperand Res0, SDOperand Res1) {
+ SDOperand CombineTo(SDNode *N, SDOperand Res0, SDOperand Res1,
+ bool AddTo = true) {
SDOperand To[] = { Res0, Res1 };
- return CombineTo(N, To, 2);
+ return CombineTo(N, To, 2, AddTo);
}
private:
// Replace the old value with the new one.
++NodesCombined;
- DEBUG(std::cerr << "\nReplacing.2 "; TLO.Old.Val->dump();
- std::cerr << "\nWith: "; TLO.New.Val->dump(&DAG);
- std::cerr << '\n');
+ DOUT << "\nReplacing.2 "; DEBUG(TLO.Old.Val->dump());
+ DOUT << "\nWith: "; DEBUG(TLO.New.Val->dump(&DAG));
+ DOUT << '\n';
std::vector<SDNode*> NowDead;
DAG.ReplaceAllUsesOfValueWith(TLO.Old, TLO.New, NowDead);
// something else needing this node.
if (TLO.Old.Val->use_empty()) {
removeFromWorkList(TLO.Old.Val);
+
+ // If the operands of this node are only used by the node, they will now
+ // be dead. Make sure to visit them first to delete dead nodes early.
+ for (unsigned i = 0, e = TLO.Old.Val->getNumOperands(); i != e; ++i)
+ if (TLO.Old.Val->getOperand(i).Val->hasOneUse())
+ AddToWorkList(TLO.Old.Val->getOperand(i).Val);
+
DAG.DeleteNode(TLO.Old.Val);
}
return true;
}
+ bool CombineToPreIndexedLoadStore(SDNode *N);
+ bool CombineToPostIndexedLoadStore(SDNode *N);
+
+
/// visit - call the node-specific routine that knows how to fold each
/// particular type of node.
SDOperand visit(SDNode *N);
SDOperand visitTokenFactor(SDNode *N);
SDOperand visitADD(SDNode *N);
SDOperand visitSUB(SDNode *N);
+ SDOperand visitADDC(SDNode *N);
+ SDOperand visitADDE(SDNode *N);
SDOperand visitMUL(SDNode *N);
SDOperand visitSDIV(SDNode *N);
SDOperand visitUDIV(SDNode *N);
SDOperand visitBRCOND(SDNode *N);
SDOperand visitBR_CC(SDNode *N);
SDOperand visitLOAD(SDNode *N);
- SDOperand visitLOADX(SDNode *N);
SDOperand visitSTORE(SDNode *N);
SDOperand visitINSERT_VECTOR_ELT(SDNode *N);
SDOperand visitVINSERT_VECTOR_ELT(SDNode *N);
SDOperand SimplifyBinOpWithSameOpcodeHands(SDNode *N);
SDOperand SimplifySelect(SDOperand N0, SDOperand N1, SDOperand N2);
SDOperand SimplifySelectCC(SDOperand N0, SDOperand N1, SDOperand N2,
- SDOperand N3, ISD::CondCode CC);
+ SDOperand N3, ISD::CondCode CC,
+ bool NotExtCompare = false);
SDOperand SimplifySetCC(MVT::ValueType VT, SDOperand N0, SDOperand N1,
ISD::CondCode Cond, bool foldBooleans = true);
SDOperand ConstantFoldVBIT_CONVERTofVBUILD_VECTOR(SDNode *, MVT::ValueType);
SDOperand BuildSDIV(SDNode *N);
SDOperand BuildUDIV(SDNode *N);
SDNode *MatchRotate(SDOperand LHS, SDOperand RHS);
+ SDOperand ReduceLoadWidth(SDNode *N);
/// GatherAllAliases - Walk up chain skipping non-aliasing memory nodes,
/// looking for aliasing nodes and adding them to the Aliases vector.
void GatherAllAliases(SDNode *N, SDOperand OriginalChain,
SmallVector<SDOperand, 8> &Aliases);
+ /// isAlias - Return true if there is any possibility that the two addresses
+ /// overlap.
+ bool isAlias(SDOperand Ptr1, int64_t Size1,
+ const Value *SrcValue1, int SrcValueOffset1,
+ SDOperand Ptr2, int64_t Size2,
+ const Value *SrcValue2, int SrcValueOffset2);
+
+ /// FindAliasInfo - Extracts the relevant alias information from the memory
+ /// node. Returns true if the operand was a load.
+ bool FindAliasInfo(SDNode *N,
+ SDOperand &Ptr, int64_t &Size,
+ const Value *&SrcValue, int &SrcValueOffset);
+
/// FindBetterChain - Walk up chain skipping non-aliasing memory nodes,
/// looking for a better chain (aliasing node.)
SDOperand FindBetterChain(SDNode *N, SDOperand Chain);
public:
- DAGCombiner(SelectionDAG &D)
- : DAG(D), TLI(D.getTargetLoweringInfo()), AfterLegalize(false) {}
+ DAGCombiner(SelectionDAG &D, AliasAnalysis &A)
+ : DAG(D),
+ TLI(D.getTargetLoweringInfo()),
+ AfterLegalize(false),
+ AA(A) {}
/// Run - runs the dag combiner on all nodes in the work list
void Run(bool RunningAfterLegalize);
// changes of the root.
HandleSDNode Dummy(DAG.getRoot());
+ // The root of the dag may dangle to deleted nodes until the dag combiner is
+ // done. Set it to null to avoid confusion.
+ DAG.setRoot(SDOperand());
/// DagCombineInfo - Expose the DAG combiner to the target combiner impls.
TargetLowering::DAGCombinerInfo
- DagCombineInfo(DAG, !RunningAfterLegalize, this);
+ DagCombineInfo(DAG, !RunningAfterLegalize, false, this);
// while the worklist isn't empty, inspect the node on the end of it and
// try and combine it.
RV.Val->getOpcode() != ISD::DELETED_NODE &&
"Node was deleted but visit returned new node!");
- DEBUG(std::cerr << "\nReplacing.3 "; N->dump();
- std::cerr << "\nWith: "; RV.Val->dump(&DAG);
- std::cerr << '\n');
+ DOUT << "\nReplacing.3 "; DEBUG(N->dump());
+ DOUT << "\nWith: "; DEBUG(RV.Val->dump(&DAG));
+ DOUT << '\n';
std::vector<SDNode*> NowDead;
if (N->getNumValues() == RV.Val->getNumValues())
DAG.ReplaceAllUsesWith(N, RV.Val, &NowDead);
case ISD::TokenFactor: return visitTokenFactor(N);
case ISD::ADD: return visitADD(N);
case ISD::SUB: return visitSUB(N);
+ case ISD::ADDC: return visitADDC(N);
+ case ISD::ADDE: return visitADDE(N);
case ISD::MUL: return visitMUL(N);
case ISD::SDIV: return visitSDIV(N);
case ISD::UDIV: return visitUDIV(N);
case ISD::BRCOND: return visitBRCOND(N);
case ISD::BR_CC: return visitBR_CC(N);
case ISD::LOAD: return visitLOAD(N);
- case ISD::LOADX: return visitLOADX(N);
case ISD::STORE: return visitSTORE(N);
case ISD::INSERT_VECTOR_ELT: return visitINSERT_VECTOR_ELT(N);
case ISD::VINSERT_VECTOR_ELT: return visitVINSERT_VECTOR_ELT(N);
return SDOperand();
}
+/// getInputChainForNode - Given a node, return its input chain if it has one,
+/// otherwise return a null sd operand.
+static SDOperand getInputChainForNode(SDNode *N) {
+ if (unsigned NumOps = N->getNumOperands()) {
+ if (N->getOperand(0).getValueType() == MVT::Other)
+ return N->getOperand(0);
+ else if (N->getOperand(NumOps-1).getValueType() == MVT::Other)
+ return N->getOperand(NumOps-1);
+ for (unsigned i = 1; i < NumOps-1; ++i)
+ if (N->getOperand(i).getValueType() == MVT::Other)
+ return N->getOperand(i);
+ }
+ return SDOperand(0, 0);
+}
+
SDOperand DAGCombiner::visitTokenFactor(SDNode *N) {
+ // If N has two operands, where one has an input chain equal to the other,
+ // the 'other' chain is redundant.
+ if (N->getNumOperands() == 2) {
+ if (getInputChainForNode(N->getOperand(0).Val) == N->getOperand(1))
+ return N->getOperand(0);
+ if (getInputChainForNode(N->getOperand(1).Val) == N->getOperand(0))
+ return N->getOperand(1);
+ }
+
+
SmallVector<SDNode *, 8> TFs; // List of token factors to visit.
SmallVector<SDOperand, 8> Ops; // Ops for replacing token factor.
bool Changed = false; // If we should replace this token factor.
// Start out with this token factor.
TFs.push_back(N);
- // Iterate through token factors. The TFs grows a new token factors are
+ // Iterate through token factors. The TFs grows when new token factors are
// encountered.
for (unsigned i = 0; i < TFs.size(); ++i) {
SDNode *TF = TFs[i];
// New and improved token factor.
Result = DAG.getNode(ISD::TokenFactor, MVT::Other, &Ops[0], Ops.size());
}
+
+ // Don't add users to work list.
+ return CombineTo(N, Result, false);
}
return Result;
}
+static
+SDOperand combineShlAddConstant(SDOperand N0, SDOperand N1, SelectionDAG &DAG) {
+ MVT::ValueType VT = N0.getValueType();
+ SDOperand N00 = N0.getOperand(0);
+ SDOperand N01 = N0.getOperand(1);
+ ConstantSDNode *N01C = dyn_cast<ConstantSDNode>(N01);
+ if (N01C && N00.getOpcode() == ISD::ADD && N00.Val->hasOneUse() &&
+ isa<ConstantSDNode>(N00.getOperand(1))) {
+ N0 = DAG.getNode(ISD::ADD, VT,
+ DAG.getNode(ISD::SHL, VT, N00.getOperand(0), N01),
+ DAG.getNode(ISD::SHL, VT, N00.getOperand(1), N01));
+ return DAG.getNode(ISD::ADD, VT, N0, N1);
+ }
+ return SDOperand();
+}
+
SDOperand DAGCombiner::visitADD(SDNode *N) {
SDOperand N0 = N->getOperand(0);
SDOperand N1 = N->getOperand(1);
return DAG.getNode(ISD::OR, VT, N0, N1);
}
}
+
+ // fold (add (shl (add x, c1), c2), ) -> (add (add (shl x, c2), c1<<c2), )
+ if (N0.getOpcode() == ISD::SHL && N0.Val->hasOneUse()) {
+ SDOperand Result = combineShlAddConstant(N0, N1, DAG);
+ if (Result.Val) return Result;
+ }
+ if (N1.getOpcode() == ISD::SHL && N1.Val->hasOneUse()) {
+ SDOperand Result = combineShlAddConstant(N1, N0, DAG);
+ if (Result.Val) return Result;
+ }
+
+ return SDOperand();
+}
+
+SDOperand DAGCombiner::visitADDC(SDNode *N) {
+ SDOperand N0 = N->getOperand(0);
+ SDOperand N1 = N->getOperand(1);
+ ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0);
+ ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1);
+ MVT::ValueType VT = N0.getValueType();
+
+ // If the flag result is dead, turn this into an ADD.
+ if (N->hasNUsesOfValue(0, 1))
+ return CombineTo(N, DAG.getNode(ISD::ADD, VT, N1, N0),
+ DAG.getNode(ISD::CARRY_FALSE, MVT::Flag));
+
+ // canonicalize constant to RHS.
+ if (N0C && !N1C) {
+ SDOperand Ops[] = { N1, N0 };
+ return DAG.getNode(ISD::ADDC, N->getVTList(), Ops, 2);
+ }
+
+ // fold (addc x, 0) -> x + no carry out
+ if (N1C && N1C->isNullValue())
+ return CombineTo(N, N0, DAG.getNode(ISD::CARRY_FALSE, MVT::Flag));
+
+ // fold (addc a, b) -> (or a, b), CARRY_FALSE iff a and b share no bits.
+ uint64_t LHSZero, LHSOne;
+ uint64_t RHSZero, RHSOne;
+ uint64_t Mask = MVT::getIntVTBitMask(VT);
+ TLI.ComputeMaskedBits(N0, Mask, LHSZero, LHSOne);
+ if (LHSZero) {
+ TLI.ComputeMaskedBits(N1, Mask, RHSZero, RHSOne);
+
+ // If all possibly-set bits on the LHS are clear on the RHS, return an OR.
+ // If all possibly-set bits on the RHS are clear on the LHS, return an OR.
+ if ((RHSZero & (~LHSZero & Mask)) == (~LHSZero & Mask) ||
+ (LHSZero & (~RHSZero & Mask)) == (~RHSZero & Mask))
+ return CombineTo(N, DAG.getNode(ISD::OR, VT, N0, N1),
+ DAG.getNode(ISD::CARRY_FALSE, MVT::Flag));
+ }
return SDOperand();
}
+SDOperand DAGCombiner::visitADDE(SDNode *N) {
+ SDOperand N0 = N->getOperand(0);
+ SDOperand N1 = N->getOperand(1);
+ SDOperand CarryIn = N->getOperand(2);
+ ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0);
+ ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1);
+ //MVT::ValueType VT = N0.getValueType();
+
+ // canonicalize constant to RHS
+ if (N0C && !N1C) {
+ SDOperand Ops[] = { N1, N0, CarryIn };
+ return DAG.getNode(ISD::ADDE, N->getVTList(), Ops, 3);
+ }
+
+ // fold (adde x, y, false) -> (addc x, y)
+ if (CarryIn.getOpcode() == ISD::CARRY_FALSE) {
+ SDOperand Ops[] = { N1, N0 };
+ return DAG.getNode(ISD::ADDC, N->getVTList(), Ops, 2);
+ }
+
+ return SDOperand();
+}
+
+
+
SDOperand DAGCombiner::visitSUB(SDNode *N) {
SDOperand N0 = N->getOperand(0);
SDOperand N1 = N->getOperand(1);
if (TLI.MaskedValueIsZero(N1, SignBit) &&
TLI.MaskedValueIsZero(N0, SignBit))
return DAG.getNode(ISD::UREM, VT, N0, N1);
+
+ // Unconditionally lower X%C -> X-X/C*C. This allows the X/C logic to hack on
+ // the remainder operation.
+ if (N1C && !N1C->isNullValue()) {
+ SDOperand Div = DAG.getNode(ISD::SDIV, VT, N0, N1);
+ SDOperand Mul = DAG.getNode(ISD::MUL, VT, Div, N1);
+ SDOperand Sub = DAG.getNode(ISD::SUB, VT, N0, Mul);
+ AddToWorkList(Div.Val);
+ AddToWorkList(Mul.Val);
+ return Sub;
+ }
+
return SDOperand();
}
}
}
}
+
+ // Unconditionally lower X%C -> X-X/C*C. This allows the X/C logic to hack on
+ // the remainder operation.
+ if (N1C && !N1C->isNullValue()) {
+ SDOperand Div = DAG.getNode(ISD::UDIV, VT, N0, N1);
+ SDOperand Mul = DAG.getNode(ISD::MUL, VT, Div, N1);
+ SDOperand Sub = DAG.getNode(ISD::SUB, VT, N0, Mul);
+ AddToWorkList(Div.Val);
+ AddToWorkList(Mul.Val);
+ return Sub;
+ }
+
return SDOperand();
}
ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0);
ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1);
MVT::ValueType VT = N1.getValueType();
- unsigned OpSizeInBits = MVT::getSizeInBits(VT);
// fold (and c1, c2) -> c1&c2
if (N0C && N1C)
SimplifyDemandedBits(SDOperand(N, 0)))
return SDOperand(N, 0);
// fold (zext_inreg (extload x)) -> (zextload x)
- if (ISD::isEXTLoad(N0.Val)) {
- MVT::ValueType EVT = cast<VTSDNode>(N0.getOperand(3))->getVT();
+ if (ISD::isEXTLoad(N0.Val) && ISD::isUNINDEXEDLoad(N0.Val)) {
+ LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ MVT::ValueType EVT = LN0->getLoadedVT();
// If we zero all the possible extended bits, then we can turn this into
// a zextload if we are running before legalize or the operation is legal.
if (TLI.MaskedValueIsZero(N1, ~0ULL << MVT::getSizeInBits(EVT)) &&
(!AfterLegalize || TLI.isLoadXLegal(ISD::ZEXTLOAD, EVT))) {
- SDOperand ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, N0.getOperand(0),
- N0.getOperand(1), N0.getOperand(2),
- EVT);
+ SDOperand ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, LN0->getChain(),
+ LN0->getBasePtr(), LN0->getSrcValue(),
+ LN0->getSrcValueOffset(), EVT,
+ LN0->isVolatile(),
+ LN0->getAlignment());
AddToWorkList(N);
CombineTo(N0.Val, ExtLoad, ExtLoad.getValue(1));
return SDOperand(N, 0); // Return N so it doesn't get rechecked!
}
}
// fold (zext_inreg (sextload x)) -> (zextload x) iff load has one use
- if (ISD::isSEXTLoad(N0.Val) && N0.hasOneUse()) {
- MVT::ValueType EVT = cast<VTSDNode>(N0.getOperand(3))->getVT();
+ if (ISD::isSEXTLoad(N0.Val) && ISD::isUNINDEXEDLoad(N0.Val) &&
+ N0.hasOneUse()) {
+ LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ MVT::ValueType EVT = LN0->getLoadedVT();
// If we zero all the possible extended bits, then we can turn this into
// a zextload if we are running before legalize or the operation is legal.
if (TLI.MaskedValueIsZero(N1, ~0ULL << MVT::getSizeInBits(EVT)) &&
(!AfterLegalize || TLI.isLoadXLegal(ISD::ZEXTLOAD, EVT))) {
- SDOperand ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, N0.getOperand(0),
- N0.getOperand(1), N0.getOperand(2),
- EVT);
+ SDOperand ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, LN0->getChain(),
+ LN0->getBasePtr(), LN0->getSrcValue(),
+ LN0->getSrcValueOffset(), EVT,
+ LN0->isVolatile(),
+ LN0->getAlignment());
AddToWorkList(N);
CombineTo(N0.Val, ExtLoad, ExtLoad.getValue(1));
return SDOperand(N, 0); // Return N so it doesn't get rechecked!
// fold (and (load x), 255) -> (zextload x, i8)
// fold (and (extload x, i16), 255) -> (zextload x, i8)
- if (N1C &&
- (N0.getOpcode() == ISD::LOAD || ISD::isEXTLoad(N0.Val) ||
- ISD::isZEXTLoad(N0.Val)) &&
- N0.hasOneUse()) {
- MVT::ValueType EVT, LoadedVT;
- if (N1C->getValue() == 255)
- EVT = MVT::i8;
- else if (N1C->getValue() == 65535)
- EVT = MVT::i16;
- else if (N1C->getValue() == ~0U)
- EVT = MVT::i32;
- else
- EVT = MVT::Other;
+ if (N1C && N0.getOpcode() == ISD::LOAD) {
+ LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ if (LN0->getExtensionType() != ISD::SEXTLOAD &&
+ LN0->getAddressingMode() == ISD::UNINDEXED &&
+ N0.hasOneUse()) {
+ MVT::ValueType EVT, LoadedVT;
+ if (N1C->getValue() == 255)
+ EVT = MVT::i8;
+ else if (N1C->getValue() == 65535)
+ EVT = MVT::i16;
+ else if (N1C->getValue() == ~0U)
+ EVT = MVT::i32;
+ else
+ EVT = MVT::Other;
- LoadedVT = N0.getOpcode() == ISD::LOAD ? VT :
- cast<VTSDNode>(N0.getOperand(3))->getVT();
- if (EVT != MVT::Other && LoadedVT > EVT &&
- (!AfterLegalize || TLI.isLoadXLegal(ISD::ZEXTLOAD, EVT))) {
- MVT::ValueType PtrType = N0.getOperand(1).getValueType();
- // For big endian targets, we need to add an offset to the pointer to load
- // the correct bytes. For little endian systems, we merely need to read
- // fewer bytes from the same pointer.
- unsigned PtrOff =
- (MVT::getSizeInBits(LoadedVT) - MVT::getSizeInBits(EVT)) / 8;
- SDOperand NewPtr = N0.getOperand(1);
- if (!TLI.isLittleEndian())
- NewPtr = DAG.getNode(ISD::ADD, PtrType, NewPtr,
- DAG.getConstant(PtrOff, PtrType));
- AddToWorkList(NewPtr.Val);
- SDOperand Load =
- DAG.getExtLoad(ISD::ZEXTLOAD, VT, N0.getOperand(0), NewPtr,
- N0.getOperand(2), EVT);
- AddToWorkList(N);
- CombineTo(N0.Val, Load, Load.getValue(1));
- return SDOperand(N, 0); // Return N so it doesn't get rechecked!
+ LoadedVT = LN0->getLoadedVT();
+ if (EVT != MVT::Other && LoadedVT > EVT &&
+ (!AfterLegalize || TLI.isLoadXLegal(ISD::ZEXTLOAD, EVT))) {
+ MVT::ValueType PtrType = N0.getOperand(1).getValueType();
+ // For big endian targets, we need to add an offset to the pointer to
+ // load the correct bytes. For little endian systems, we merely need to
+ // read fewer bytes from the same pointer.
+ unsigned PtrOff =
+ (MVT::getSizeInBits(LoadedVT) - MVT::getSizeInBits(EVT)) / 8;
+ SDOperand NewPtr = LN0->getBasePtr();
+ if (!TLI.isLittleEndian())
+ NewPtr = DAG.getNode(ISD::ADD, PtrType, NewPtr,
+ DAG.getConstant(PtrOff, PtrType));
+ AddToWorkList(NewPtr.Val);
+ SDOperand Load =
+ DAG.getExtLoad(ISD::ZEXTLOAD, VT, LN0->getChain(), NewPtr,
+ LN0->getSrcValue(), LN0->getSrcValueOffset(), EVT,
+ LN0->isVolatile(), LN0->getAlignment());
+ AddToWorkList(N);
+ CombineTo(N0.Val, Load, Load.getValue(1));
+ return SDOperand(N, 0); // Return N so it doesn't get rechecked!
+ }
}
}
/// MatchRotateHalf - Match "(X shl/srl V1) & V2" where V2 may not be present.
static bool MatchRotateHalf(SDOperand Op, SDOperand &Shift, SDOperand &Mask) {
if (Op.getOpcode() == ISD::AND) {
- if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(Op.getOperand(1))) {
+ if (isa<ConstantSDNode>(Op.getOperand(1))) {
Mask = Op.getOperand(1);
Op = Op.getOperand(0);
} else {
}
unsigned OpSizeInBits = MVT::getSizeInBits(VT);
+ SDOperand LHSShiftArg = LHSShift.getOperand(0);
+ SDOperand LHSShiftAmt = LHSShift.getOperand(1);
+ SDOperand RHSShiftAmt = RHSShift.getOperand(1);
// fold (or (shl x, C1), (srl x, C2)) -> (rotl x, C1)
// fold (or (shl x, C1), (srl x, C2)) -> (rotr x, C2)
- if (LHSShift.getOperand(1).getOpcode() == ISD::Constant &&
- RHSShift.getOperand(1).getOpcode() == ISD::Constant) {
- uint64_t LShVal = cast<ConstantSDNode>(LHSShift.getOperand(1))->getValue();
- uint64_t RShVal = cast<ConstantSDNode>(RHSShift.getOperand(1))->getValue();
+ if (LHSShiftAmt.getOpcode() == ISD::Constant &&
+ RHSShiftAmt.getOpcode() == ISD::Constant) {
+ uint64_t LShVal = cast<ConstantSDNode>(LHSShiftAmt)->getValue();
+ uint64_t RShVal = cast<ConstantSDNode>(RHSShiftAmt)->getValue();
if ((LShVal + RShVal) != OpSizeInBits)
return 0;
SDOperand Rot;
if (HasROTL)
- Rot = DAG.getNode(ISD::ROTL, VT, LHSShift.getOperand(0),
- LHSShift.getOperand(1));
+ Rot = DAG.getNode(ISD::ROTL, VT, LHSShiftArg, LHSShiftAmt);
else
- Rot = DAG.getNode(ISD::ROTR, VT, LHSShift.getOperand(0),
- RHSShift.getOperand(1));
+ Rot = DAG.getNode(ISD::ROTR, VT, LHSShiftArg, RHSShiftAmt);
// If there is an AND of either shifted operand, apply it to the result.
if (LHSMask.Val || RHSMask.Val) {
// fold (or (shl x, y), (srl x, (sub 32, y))) -> (rotl x, y)
// fold (or (shl x, y), (srl x, (sub 32, y))) -> (rotr x, (sub 32, y))
- if (RHSShift.getOperand(1).getOpcode() == ISD::SUB &&
- LHSShift.getOperand(1) == RHSShift.getOperand(1).getOperand(1)) {
+ if (RHSShiftAmt.getOpcode() == ISD::SUB &&
+ LHSShiftAmt == RHSShiftAmt.getOperand(1)) {
if (ConstantSDNode *SUBC =
- dyn_cast<ConstantSDNode>(RHSShift.getOperand(1).getOperand(0))) {
+ dyn_cast<ConstantSDNode>(RHSShiftAmt.getOperand(0))) {
if (SUBC->getValue() == OpSizeInBits)
if (HasROTL)
- return DAG.getNode(ISD::ROTL, VT, LHSShift.getOperand(0),
- LHSShift.getOperand(1)).Val;
+ return DAG.getNode(ISD::ROTL, VT, LHSShiftArg, LHSShiftAmt).Val;
else
- return DAG.getNode(ISD::ROTR, VT, LHSShift.getOperand(0),
- LHSShift.getOperand(1)).Val;
+ return DAG.getNode(ISD::ROTR, VT, LHSShiftArg, RHSShiftAmt).Val;
}
}
// fold (or (shl x, (sub 32, y)), (srl x, r)) -> (rotr x, y)
// fold (or (shl x, (sub 32, y)), (srl x, r)) -> (rotl x, (sub 32, y))
- if (LHSShift.getOperand(1).getOpcode() == ISD::SUB &&
- RHSShift.getOperand(1) == LHSShift.getOperand(1).getOperand(1)) {
+ if (LHSShiftAmt.getOpcode() == ISD::SUB &&
+ RHSShiftAmt == LHSShiftAmt.getOperand(1)) {
if (ConstantSDNode *SUBC =
- dyn_cast<ConstantSDNode>(LHSShift.getOperand(1).getOperand(0))) {
+ dyn_cast<ConstantSDNode>(LHSShiftAmt.getOperand(0))) {
if (SUBC->getValue() == OpSizeInBits)
if (HasROTL)
- return DAG.getNode(ISD::ROTL, VT, LHSShift.getOperand(0),
- LHSShift.getOperand(1)).Val;
+ return DAG.getNode(ISD::ROTL, VT, LHSShiftArg, LHSShiftAmt).Val;
else
- return DAG.getNode(ISD::ROTR, VT, LHSShift.getOperand(0),
- RHSShift.getOperand(1)).Val;
+ return DAG.getNode(ISD::ROTR, VT, LHSShiftArg, RHSShiftAmt).Val;
+ }
+ }
+
+ // Look for sign/zext/any-extended cases:
+ if ((LHSShiftAmt.getOpcode() == ISD::SIGN_EXTEND
+ || LHSShiftAmt.getOpcode() == ISD::ZERO_EXTEND
+ || LHSShiftAmt.getOpcode() == ISD::ANY_EXTEND) &&
+ (RHSShiftAmt.getOpcode() == ISD::SIGN_EXTEND
+ || RHSShiftAmt.getOpcode() == ISD::ZERO_EXTEND
+ || RHSShiftAmt.getOpcode() == ISD::ANY_EXTEND)) {
+ SDOperand LExtOp0 = LHSShiftAmt.getOperand(0);
+ SDOperand RExtOp0 = RHSShiftAmt.getOperand(0);
+ if (RExtOp0.getOpcode() == ISD::SUB &&
+ RExtOp0.getOperand(1) == LExtOp0) {
+ // fold (or (shl x, (*ext y)), (srl x, (*ext (sub 32, y)))) ->
+ // (rotr x, y)
+ // fold (or (shl x, (*ext y)), (srl x, (*ext (sub 32, y)))) ->
+ // (rotl x, (sub 32, y))
+ if (ConstantSDNode *SUBC = cast<ConstantSDNode>(RExtOp0.getOperand(0))) {
+ if (SUBC->getValue() == OpSizeInBits) {
+ if (HasROTL)
+ return DAG.getNode(ISD::ROTL, VT, LHSShiftArg, LHSShiftAmt).Val;
+ else
+ return DAG.getNode(ISD::ROTR, VT, LHSShiftArg, RHSShiftAmt).Val;
+ }
+ }
+ } else if (LExtOp0.getOpcode() == ISD::SUB &&
+ RExtOp0 == LExtOp0.getOperand(1)) {
+ // fold (or (shl x, (*ext (sub 32, y))), (srl x, (*ext r))) ->
+ // (rotl x, y)
+ // fold (or (shl x, (*ext (sub 32, y))), (srl x, (*ext r))) ->
+ // (rotr x, (sub 32, y))
+ if (ConstantSDNode *SUBC = cast<ConstantSDNode>(LExtOp0.getOperand(0))) {
+ if (SUBC->getValue() == OpSizeInBits) {
+ if (HasROTL)
+ return DAG.getNode(ISD::ROTL, VT, LHSShiftArg, RHSShiftAmt).Val;
+ else
+ return DAG.getNode(ISD::ROTL, VT, LHSShiftArg, LHSShiftAmt).Val;
+ }
+ }
}
}
abort();
}
// fold !(x or y) -> (!x and !y) iff x or y are setcc
- if (N1C && N1C->getValue() == 1 &&
+ if (N1C && N1C->getValue() == 1 && VT == MVT::i1 &&
(N0.getOpcode() == ISD::OR || N0.getOpcode() == ISD::AND)) {
SDOperand LHS = N0.getOperand(0), RHS = N0.getOperand(1);
if (isOneUseSetCC(RHS) || isOneUseSetCC(LHS)) {
// if (shl x, c) is known to be zero, return 0
if (TLI.MaskedValueIsZero(SDOperand(N, 0), MVT::getIntVTBitMask(VT)))
return DAG.getConstant(0, VT);
- if (SimplifyDemandedBits(SDOperand(N, 0)))
+ if (N1C && SimplifyDemandedBits(SDOperand(N, 0)))
return SDOperand(N, 0);
// fold (shl (shl x, c1), c2) -> 0 or (shl x, c1+c2)
if (N1C && N0.getOpcode() == ISD::SHL &&
if (N1C && N0.getOpcode() == ISD::SRA && N1 == N0.getOperand(1))
return DAG.getNode(ISD::AND, VT, N0.getOperand(0),
DAG.getConstant(~0ULL << N1C->getValue(), VT));
- // fold (shl (add x, c1), c2) -> (add (shl x, c2), c1<<c2)
- if (N1C && N0.getOpcode() == ISD::ADD && N0.Val->hasOneUse() &&
- isa<ConstantSDNode>(N0.getOperand(1))) {
- return DAG.getNode(ISD::ADD, VT,
- DAG.getNode(ISD::SHL, VT, N0.getOperand(0), N1),
- DAG.getNode(ISD::SHL, VT, N0.getOperand(1), N1));
- }
return SDOperand();
}
// if (srl x, c) is known to be zero, return 0
if (N1C && TLI.MaskedValueIsZero(SDOperand(N, 0), ~0ULL >> (64-OpSizeInBits)))
return DAG.getConstant(0, VT);
+
// fold (srl (srl x, c1), c2) -> 0 or (srl x, c1+c2)
if (N1C && N0.getOpcode() == ISD::SRL &&
N0.getOperand(1).getOpcode() == ISD::Constant) {
return DAG.getNode(ISD::ANY_EXTEND, VT, SmallShift);
}
+ // fold (srl (sra X, Y), 31) -> (srl X, 31). This srl only looks at the sign
+ // bit, which is unmodified by sra.
+ if (N1C && N1C->getValue()+1 == MVT::getSizeInBits(VT)) {
+ if (N0.getOpcode() == ISD::SRA)
+ return DAG.getNode(ISD::SRL, VT, N0.getOperand(0), N1);
+ }
+
// fold (srl (ctlz x), "5") -> x iff x has one bit set (the low bit).
if (N1C && N0.getOpcode() == ISD::CTLZ &&
N1C->getValue() == Log2_32(MVT::getSizeInBits(VT))) {
}
}
+ // fold operands of srl based on knowledge that the low bits are not
+ // demanded.
+ if (N1C && SimplifyDemandedBits(SDOperand(N, 0)))
+ return SDOperand(N, 0);
+
return SDOperand();
}
SDOperand N2 = N->getOperand(2);
SDOperand N3 = N->getOperand(3);
SDOperand N4 = N->getOperand(4);
- ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0);
- ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1);
- ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2);
ISD::CondCode CC = cast<CondCodeSDNode>(N4)->get();
// fold select_cc lhs, rhs, x, x, cc -> x
// Determine if the condition we're dealing with is constant
SDOperand SCC = SimplifySetCC(TLI.getSetCCResultTy(), N0, N1, CC, false);
+ if (SCC.Val) AddToWorkList(SCC.Val);
if (ConstantSDNode *SCCC = dyn_cast_or_null<ConstantSDNode>(SCC.Val)) {
if (SCCC->getValue())
MVT::ValueType VT = N->getValueType(0);
// fold (sext c1) -> c1
- if (ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0))
+ if (isa<ConstantSDNode>(N0))
return DAG.getNode(ISD::SIGN_EXTEND, VT, N0);
// fold (sext (sext x)) -> (sext x)
if (N0.getOpcode() == ISD::SIGN_EXTEND || N0.getOpcode() == ISD::ANY_EXTEND)
return DAG.getNode(ISD::SIGN_EXTEND, VT, N0.getOperand(0));
- // fold (sext (truncate x)) -> (sextinreg x).
- if (N0.getOpcode() == ISD::TRUNCATE &&
- (!AfterLegalize || TLI.isOperationLegal(ISD::SIGN_EXTEND_INREG,
- N0.getValueType()))) {
+ // 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) {
+ 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) {
SDOperand Op = N0.getOperand(0);
- if (Op.getValueType() < VT) {
- Op = DAG.getNode(ISD::ANY_EXTEND, VT, Op);
- } else if (Op.getValueType() > VT) {
- Op = DAG.getNode(ISD::TRUNCATE, VT, Op);
+ unsigned OpBits = MVT::getSizeInBits(Op.getValueType());
+ unsigned MidBits = MVT::getSizeInBits(N0.getValueType());
+ unsigned DestBits = MVT::getSizeInBits(VT);
+ unsigned NumSignBits = TLI.ComputeNumSignBits(Op);
+
+ if (OpBits == DestBits) {
+ // Op is i32, Mid is i8, and Dest is i32. If Op has more than 24 sign
+ // bits, it is already ready.
+ if (NumSignBits > DestBits-MidBits)
+ return Op;
+ } else if (OpBits < DestBits) {
+ // Op is i32, Mid is i8, and Dest is i64. If Op has more than 24 sign
+ // bits, just sext from i32.
+ if (NumSignBits > OpBits-MidBits)
+ return DAG.getNode(ISD::SIGN_EXTEND, VT, Op);
+ } else {
+ // Op is i64, Mid is i8, and Dest is i32. If Op has more than 56 sign
+ // bits, just truncate to i32.
+ if (NumSignBits > OpBits-MidBits)
+ return DAG.getNode(ISD::TRUNCATE, VT, Op);
+ }
+
+ // fold (sext (truncate x)) -> (sextinreg x).
+ if (!AfterLegalize || TLI.isOperationLegal(ISD::SIGN_EXTEND_INREG,
+ N0.getValueType())) {
+ if (Op.getValueType() < VT)
+ Op = DAG.getNode(ISD::ANY_EXTEND, VT, Op);
+ else if (Op.getValueType() > VT)
+ Op = DAG.getNode(ISD::TRUNCATE, VT, Op);
+ return DAG.getNode(ISD::SIGN_EXTEND_INREG, VT, Op,
+ DAG.getValueType(N0.getValueType()));
}
- return DAG.getNode(ISD::SIGN_EXTEND_INREG, VT, Op,
- DAG.getValueType(N0.getValueType()));
}
// fold (sext (load x)) -> (sext (truncate (sextload x)))
- if (N0.getOpcode() == ISD::LOAD && N0.hasOneUse() &&
+ if (ISD::isNON_EXTLoad(N0.Val) && N0.hasOneUse() &&
(!AfterLegalize||TLI.isLoadXLegal(ISD::SEXTLOAD, N0.getValueType()))){
- SDOperand ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, N0.getOperand(0),
- N0.getOperand(1), N0.getOperand(2),
- N0.getValueType());
+ LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ SDOperand ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, LN0->getChain(),
+ LN0->getBasePtr(), LN0->getSrcValue(),
+ LN0->getSrcValueOffset(),
+ N0.getValueType(),
+ LN0->isVolatile());
CombineTo(N, ExtLoad);
CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
ExtLoad.getValue(1));
// fold (sext (sextload x)) -> (sext (truncate (sextload x)))
// fold (sext ( extload x)) -> (sext (truncate (sextload x)))
- if ((ISD::isSEXTLoad(N0.Val) || ISD::isEXTLoad(N0.Val)) && N0.hasOneUse()) {
- MVT::ValueType EVT = cast<VTSDNode>(N0.getOperand(3))->getVT();
- SDOperand ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, N0.getOperand(0),
- N0.getOperand(1), N0.getOperand(2), EVT);
- CombineTo(N, ExtLoad);
- CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
- ExtLoad.getValue(1));
- return SDOperand(N, 0); // Return N so it doesn't get rechecked!
+ if ((ISD::isSEXTLoad(N0.Val) || ISD::isEXTLoad(N0.Val)) &&
+ ISD::isUNINDEXEDLoad(N0.Val) && N0.hasOneUse()) {
+ LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ MVT::ValueType EVT = LN0->getLoadedVT();
+ if (!AfterLegalize || TLI.isLoadXLegal(ISD::SEXTLOAD, EVT)) {
+ SDOperand ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, LN0->getChain(),
+ LN0->getBasePtr(), LN0->getSrcValue(),
+ LN0->getSrcValueOffset(), EVT,
+ LN0->isVolatile(),
+ LN0->getAlignment());
+ CombineTo(N, ExtLoad);
+ CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
+ ExtLoad.getValue(1));
+ return SDOperand(N, 0); // Return N so it doesn't get rechecked!
+ }
+ }
+
+ // sext(setcc x,y,cc) -> select_cc x, y, -1, 0, cc
+ if (N0.getOpcode() == ISD::SETCC) {
+ SDOperand SCC =
+ SimplifySelectCC(N0.getOperand(0), N0.getOperand(1),
+ DAG.getConstant(~0ULL, VT), DAG.getConstant(0, VT),
+ cast<CondCodeSDNode>(N0.getOperand(2))->get(), true);
+ if (SCC.Val) return SCC;
}
return SDOperand();
MVT::ValueType VT = N->getValueType(0);
// fold (zext c1) -> c1
- if (ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0))
+ if (isa<ConstantSDNode>(N0))
return DAG.getNode(ISD::ZERO_EXTEND, VT, N0);
// fold (zext (zext x)) -> (zext x)
// fold (zext (aext x)) -> (zext x)
if (N0.getOpcode() == ISD::ZERO_EXTEND || N0.getOpcode() == ISD::ANY_EXTEND)
return DAG.getNode(ISD::ZERO_EXTEND, VT, N0.getOperand(0));
+ // fold (zext (truncate (load x))) -> (zext (smaller load x))
+ // fold (zext (truncate (srl (load x), c))) -> (zext (small load (x+c/n)))
+ if (N0.getOpcode() == ISD::TRUNCATE) {
+ SDOperand NarrowLoad = ReduceLoadWidth(N0.Val);
+ if (NarrowLoad.Val) {
+ if (NarrowLoad.Val != N0.Val)
+ CombineTo(N0.Val, NarrowLoad);
+ return DAG.getNode(ISD::ZERO_EXTEND, VT, NarrowLoad);
+ }
+ }
+
// fold (zext (truncate x)) -> (and x, mask)
if (N0.getOpcode() == ISD::TRUNCATE &&
(!AfterLegalize || TLI.isOperationLegal(ISD::AND, VT))) {
}
// fold (zext (load x)) -> (zext (truncate (zextload x)))
- if (N0.getOpcode() == ISD::LOAD && N0.hasOneUse() &&
+ if (ISD::isNON_EXTLoad(N0.Val) && N0.hasOneUse() &&
(!AfterLegalize||TLI.isLoadXLegal(ISD::ZEXTLOAD, N0.getValueType()))) {
- SDOperand ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, N0.getOperand(0),
- N0.getOperand(1), N0.getOperand(2),
- N0.getValueType());
+ LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ SDOperand ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, LN0->getChain(),
+ LN0->getBasePtr(), LN0->getSrcValue(),
+ LN0->getSrcValueOffset(),
+ N0.getValueType(),
+ LN0->isVolatile(),
+ LN0->getAlignment());
CombineTo(N, ExtLoad);
CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
ExtLoad.getValue(1));
// fold (zext (zextload x)) -> (zext (truncate (zextload x)))
// fold (zext ( extload x)) -> (zext (truncate (zextload x)))
- if ((ISD::isZEXTLoad(N0.Val) || ISD::isEXTLoad(N0.Val)) && N0.hasOneUse()) {
- MVT::ValueType EVT = cast<VTSDNode>(N0.getOperand(3))->getVT();
- SDOperand ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, N0.getOperand(0),
- N0.getOperand(1), N0.getOperand(2), EVT);
+ if ((ISD::isZEXTLoad(N0.Val) || ISD::isEXTLoad(N0.Val)) &&
+ ISD::isUNINDEXEDLoad(N0.Val) && N0.hasOneUse()) {
+ LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ MVT::ValueType EVT = LN0->getLoadedVT();
+ SDOperand ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, LN0->getChain(),
+ LN0->getBasePtr(), LN0->getSrcValue(),
+ LN0->getSrcValueOffset(), EVT,
+ LN0->isVolatile(),
+ LN0->getAlignment());
CombineTo(N, ExtLoad);
CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
ExtLoad.getValue(1));
return SDOperand(N, 0); // Return N so it doesn't get rechecked!
}
+
+ // zext(setcc x,y,cc) -> select_cc x, y, 1, 0, cc
+ if (N0.getOpcode() == ISD::SETCC) {
+ SDOperand SCC =
+ SimplifySelectCC(N0.getOperand(0), N0.getOperand(1),
+ DAG.getConstant(1, VT), DAG.getConstant(0, VT),
+ cast<CondCodeSDNode>(N0.getOperand(2))->get(), true);
+ if (SCC.Val) return SCC;
+ }
+
return SDOperand();
}
N0.getOpcode() == ISD::SIGN_EXTEND)
return DAG.getNode(N0.getOpcode(), VT, N0.getOperand(0));
+ // fold (aext (truncate (load x))) -> (aext (smaller load x))
+ // fold (aext (truncate (srl (load x), c))) -> (aext (small load (x+c/n)))
+ if (N0.getOpcode() == ISD::TRUNCATE) {
+ SDOperand NarrowLoad = ReduceLoadWidth(N0.Val);
+ if (NarrowLoad.Val) {
+ if (NarrowLoad.Val != N0.Val)
+ CombineTo(N0.Val, NarrowLoad);
+ return DAG.getNode(ISD::ANY_EXTEND, VT, NarrowLoad);
+ }
+ }
+
// fold (aext (truncate x))
if (N0.getOpcode() == ISD::TRUNCATE) {
SDOperand TruncOp = N0.getOperand(0);
}
// fold (aext (load x)) -> (aext (truncate (extload x)))
- if (N0.getOpcode() == ISD::LOAD && N0.hasOneUse() &&
+ if (ISD::isNON_EXTLoad(N0.Val) && N0.hasOneUse() &&
(!AfterLegalize||TLI.isLoadXLegal(ISD::EXTLOAD, N0.getValueType()))) {
- SDOperand ExtLoad = DAG.getExtLoad(ISD::EXTLOAD, VT, N0.getOperand(0),
- N0.getOperand(1), N0.getOperand(2),
- N0.getValueType());
+ LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ SDOperand ExtLoad = DAG.getExtLoad(ISD::EXTLOAD, VT, LN0->getChain(),
+ LN0->getBasePtr(), LN0->getSrcValue(),
+ LN0->getSrcValueOffset(),
+ N0.getValueType(),
+ LN0->isVolatile(),
+ LN0->getAlignment());
CombineTo(N, ExtLoad);
CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
ExtLoad.getValue(1));
// fold (aext (zextload x)) -> (aext (truncate (zextload x)))
// fold (aext (sextload x)) -> (aext (truncate (sextload x)))
// fold (aext ( extload x)) -> (aext (truncate (extload x)))
- if (N0.getOpcode() == ISD::LOADX && N0.hasOneUse()) {
- MVT::ValueType EVT = cast<VTSDNode>(N0.getOperand(3))->getVT();
- unsigned LType = N0.getConstantOperandVal(4);
- SDOperand ExtLoad = DAG.getExtLoad((ISD::LoadExtType)LType, VT,
- N0.getOperand(0), N0.getOperand(1),
- N0.getOperand(2), EVT);
+ if (N0.getOpcode() == ISD::LOAD &&
+ !ISD::isNON_EXTLoad(N0.Val) && ISD::isUNINDEXEDLoad(N0.Val) &&
+ N0.hasOneUse()) {
+ LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ MVT::ValueType EVT = LN0->getLoadedVT();
+ SDOperand ExtLoad = DAG.getExtLoad(LN0->getExtensionType(), VT,
+ LN0->getChain(), LN0->getBasePtr(),
+ LN0->getSrcValue(),
+ LN0->getSrcValueOffset(), EVT,
+ LN0->isVolatile(),
+ LN0->getAlignment());
CombineTo(N, ExtLoad);
CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
ExtLoad.getValue(1));
return SDOperand(N, 0); // Return N so it doesn't get rechecked!
}
+
+ // aext(setcc x,y,cc) -> select_cc x, y, 1, 0, cc
+ if (N0.getOpcode() == ISD::SETCC) {
+ SDOperand SCC =
+ SimplifySelectCC(N0.getOperand(0), N0.getOperand(1),
+ DAG.getConstant(1, VT), DAG.getConstant(0, VT),
+ cast<CondCodeSDNode>(N0.getOperand(2))->get(), true);
+ if (SCC.Val)
+ return SCC;
+ }
+
+ return SDOperand();
+}
+
+/// ReduceLoadWidth - If the result of a wider load is shifted to right of N
+/// bits and then truncated to a narrower type and where N is a multiple
+/// of number of bits of the narrower type, transform it to a narrower load
+/// from address + N / num of bits of new type. If the result is to be
+/// extended, also fold the extension to form a extending load.
+SDOperand DAGCombiner::ReduceLoadWidth(SDNode *N) {
+ unsigned Opc = N->getOpcode();
+ ISD::LoadExtType ExtType = ISD::NON_EXTLOAD;
+ SDOperand N0 = N->getOperand(0);
+ MVT::ValueType VT = N->getValueType(0);
+ MVT::ValueType EVT = N->getValueType(0);
+
+ // Special case: SIGN_EXTEND_INREG is basically truncating to EVT then
+ // extended to VT.
+ if (Opc == ISD::SIGN_EXTEND_INREG) {
+ ExtType = ISD::SEXTLOAD;
+ EVT = cast<VTSDNode>(N->getOperand(1))->getVT();
+ if (AfterLegalize && !TLI.isLoadXLegal(ISD::SEXTLOAD, EVT))
+ return SDOperand();
+ }
+
+ unsigned EVTBits = MVT::getSizeInBits(EVT);
+ unsigned ShAmt = 0;
+ bool CombineSRL = false;
+ if (N0.getOpcode() == ISD::SRL && N0.hasOneUse()) {
+ if (ConstantSDNode *N01 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) {
+ ShAmt = N01->getValue();
+ // Is the shift amount a multiple of size of VT?
+ if ((ShAmt & (EVTBits-1)) == 0) {
+ N0 = N0.getOperand(0);
+ if (MVT::getSizeInBits(N0.getValueType()) <= EVTBits)
+ return SDOperand();
+ CombineSRL = true;
+ }
+ }
+ }
+
+ if (ISD::isNON_EXTLoad(N0.Val) && N0.hasOneUse() &&
+ // Do not allow folding to i1 here. i1 is implicitly stored in memory in
+ // zero extended form: by shrinking the load, we lose track of the fact
+ // that it is already zero extended.
+ // FIXME: This should be reevaluated.
+ VT != MVT::i1) {
+ assert(MVT::getSizeInBits(N0.getValueType()) > EVTBits &&
+ "Cannot truncate to larger type!");
+ LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ MVT::ValueType PtrType = N0.getOperand(1).getValueType();
+ // For big endian targets, we need to adjust the offset to the pointer to
+ // load the correct bytes.
+ if (!TLI.isLittleEndian())
+ ShAmt = MVT::getSizeInBits(N0.getValueType()) - ShAmt - EVTBits;
+ uint64_t PtrOff = ShAmt / 8;
+ SDOperand NewPtr = DAG.getNode(ISD::ADD, PtrType, LN0->getBasePtr(),
+ DAG.getConstant(PtrOff, PtrType));
+ AddToWorkList(NewPtr.Val);
+ SDOperand Load = (ExtType == ISD::NON_EXTLOAD)
+ ? DAG.getLoad(VT, LN0->getChain(), NewPtr,
+ LN0->getSrcValue(), LN0->getSrcValueOffset(),
+ LN0->isVolatile(), LN0->getAlignment())
+ : DAG.getExtLoad(ExtType, VT, LN0->getChain(), NewPtr,
+ LN0->getSrcValue(), LN0->getSrcValueOffset(), EVT,
+ LN0->isVolatile(), LN0->getAlignment());
+ AddToWorkList(N);
+ if (CombineSRL) {
+ std::vector<SDNode*> NowDead;
+ DAG.ReplaceAllUsesOfValueWith(N0.getValue(1), Load.getValue(1), NowDead);
+ CombineTo(N->getOperand(0).Val, Load);
+ } else
+ CombineTo(N0.Val, Load, Load.getValue(1));
+ if (ShAmt) {
+ if (Opc == ISD::SIGN_EXTEND_INREG)
+ return DAG.getNode(Opc, VT, Load, N->getOperand(1));
+ else
+ return DAG.getNode(Opc, VT, Load);
+ }
+ return SDOperand(N, 0); // Return N so it doesn't get rechecked!
+ }
+
return SDOperand();
}
return DAG.getNode(ISD::SIGN_EXTEND_INREG, VT, N0.getOperand(0), N1);
}
- // fold (sext_in_reg x) -> (zext_in_reg x) if the sign bit is zero
+ // fold (sext_in_reg x) -> (zext_in_reg x) if the sign bit is known zero.
if (TLI.MaskedValueIsZero(N0, 1ULL << (EVTBits-1)))
return DAG.getZeroExtendInReg(N0, EVT);
+ // fold operands of sext_in_reg based on knowledge that the top bits are not
+ // demanded.
+ if (SimplifyDemandedBits(SDOperand(N, 0)))
+ return SDOperand(N, 0);
+
+ // fold (sext_in_reg (load x)) -> (smaller sextload x)
+ // fold (sext_in_reg (srl (load x), c)) -> (smaller sextload (x+c/evtbits))
+ SDOperand NarrowLoad = ReduceLoadWidth(N);
+ if (NarrowLoad.Val)
+ return NarrowLoad;
+
// fold (sext_in_reg (srl X, 24), i8) -> sra X, 24
// fold (sext_in_reg (srl X, 23), i8) -> sra X, 23 iff possible.
// We already fold "(sext_in_reg (srl X, 25), i8) -> srl X, 25" above.
return DAG.getNode(ISD::SRA, VT, N0.getOperand(0), N0.getOperand(1));
}
}
-
+
// fold (sext_inreg (extload x)) -> (sextload x)
if (ISD::isEXTLoad(N0.Val) &&
- EVT == cast<VTSDNode>(N0.getOperand(3))->getVT() &&
+ ISD::isUNINDEXEDLoad(N0.Val) &&
+ EVT == cast<LoadSDNode>(N0)->getLoadedVT() &&
(!AfterLegalize || TLI.isLoadXLegal(ISD::SEXTLOAD, EVT))) {
- SDOperand ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, N0.getOperand(0),
- N0.getOperand(1), N0.getOperand(2),
- EVT);
+ LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ SDOperand ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, LN0->getChain(),
+ LN0->getBasePtr(), LN0->getSrcValue(),
+ LN0->getSrcValueOffset(), EVT,
+ LN0->isVolatile(),
+ LN0->getAlignment());
CombineTo(N, ExtLoad);
CombineTo(N0.Val, ExtLoad, ExtLoad.getValue(1));
return SDOperand(N, 0); // Return N so it doesn't get rechecked!
}
// fold (sext_inreg (zextload x)) -> (sextload x) iff load has one use
- if (ISD::isZEXTLoad(N0.Val) && N0.hasOneUse() &&
- EVT == cast<VTSDNode>(N0.getOperand(3))->getVT() &&
+ if (ISD::isZEXTLoad(N0.Val) && ISD::isUNINDEXEDLoad(N0.Val) &&
+ N0.hasOneUse() &&
+ EVT == cast<LoadSDNode>(N0)->getLoadedVT() &&
(!AfterLegalize || TLI.isLoadXLegal(ISD::SEXTLOAD, EVT))) {
- SDOperand ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, N0.getOperand(0),
- N0.getOperand(1), N0.getOperand(2),
- EVT);
+ LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ SDOperand ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, LN0->getChain(),
+ LN0->getBasePtr(), LN0->getSrcValue(),
+ LN0->getSrcValueOffset(), EVT,
+ LN0->isVolatile(),
+ LN0->getAlignment());
CombineTo(N, ExtLoad);
CombineTo(N0.Val, ExtLoad, ExtLoad.getValue(1));
return SDOperand(N, 0); // Return N so it doesn't get rechecked!
// fold (truncate (ext x)) -> (ext x) or (truncate x) or x
if (N0.getOpcode() == ISD::ZERO_EXTEND || N0.getOpcode() == ISD::SIGN_EXTEND||
N0.getOpcode() == ISD::ANY_EXTEND) {
- if (N0.getValueType() < VT)
+ if (N0.getOperand(0).getValueType() < VT)
// if the source is smaller than the dest, we still need an extend
return DAG.getNode(N0.getOpcode(), VT, N0.getOperand(0));
- else if (N0.getValueType() > VT)
+ else if (N0.getOperand(0).getValueType() > VT)
// if the source is larger than the dest, than we just need the truncate
return DAG.getNode(ISD::TRUNCATE, VT, N0.getOperand(0));
else
// and the truncate
return N0.getOperand(0);
}
+
// fold (truncate (load x)) -> (smaller load x)
- if (N0.getOpcode() == ISD::LOAD && N0.hasOneUse()) {
- assert(MVT::getSizeInBits(N0.getValueType()) > MVT::getSizeInBits(VT) &&
- "Cannot truncate to larger type!");
- MVT::ValueType PtrType = N0.getOperand(1).getValueType();
- // For big endian targets, we need to add an offset to the pointer to load
- // the correct bytes. For little endian systems, we merely need to read
- // fewer bytes from the same pointer.
- uint64_t PtrOff =
- (MVT::getSizeInBits(N0.getValueType()) - MVT::getSizeInBits(VT)) / 8;
- SDOperand NewPtr = TLI.isLittleEndian() ? N0.getOperand(1) :
- DAG.getNode(ISD::ADD, PtrType, N0.getOperand(1),
- DAG.getConstant(PtrOff, PtrType));
- AddToWorkList(NewPtr.Val);
- SDOperand Load = DAG.getLoad(VT, N0.getOperand(0), NewPtr,N0.getOperand(2));
- AddToWorkList(N);
- CombineTo(N0.Val, Load, Load.getValue(1));
- return SDOperand(N, 0); // Return N so it doesn't get rechecked!
- }
- return SDOperand();
+ // fold (truncate (srl (load x), c)) -> (smaller load (x+c/evtbits))
+ return ReduceLoadWidth(N);
}
SDOperand DAGCombiner::visitBIT_CONVERT(SDNode *N) {
return DAG.getNode(ISD::BIT_CONVERT, VT, N0.getOperand(0));
// fold (conv (load x)) -> (load (conv*)x)
- // FIXME: These xforms need to know that the resultant load doesn't need a
- // higher alignment than the original!
- if (0 && N0.getOpcode() == ISD::LOAD && N0.hasOneUse()) {
- SDOperand Load = DAG.getLoad(VT, N0.getOperand(0), N0.getOperand(1),
- N0.getOperand(2));
- AddToWorkList(N);
- CombineTo(N0.Val, DAG.getNode(ISD::BIT_CONVERT, N0.getValueType(), Load),
- Load.getValue(1));
- return Load;
+ // If the resultant load doesn't need a higher alignment than the original!
+ if (ISD::isNON_EXTLoad(N0.Val) && N0.hasOneUse() &&
+ TLI.isOperationLegal(ISD::LOAD, VT)) {
+ LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ unsigned Align = TLI.getTargetMachine().getTargetData()->
+ getPrefTypeAlignment(getTypeForValueType(VT));
+ unsigned OrigAlign = LN0->getAlignment();
+ if (Align <= OrigAlign) {
+ SDOperand Load = DAG.getLoad(VT, LN0->getChain(), LN0->getBasePtr(),
+ LN0->getSrcValue(), LN0->getSrcValueOffset(),
+ LN0->isVolatile(), LN0->getAlignment());
+ AddToWorkList(N);
+ CombineTo(N0.Val, DAG.getNode(ISD::BIT_CONVERT, N0.getValueType(), Load),
+ Load.getValue(1));
+ return Load;
+ }
}
return SDOperand();
// fold ((-A) + B) -> B-A
if (N0.getOpcode() == ISD::FNEG)
return DAG.getNode(ISD::FSUB, VT, N1, N0.getOperand(0));
+
+ // If allowed, fold (fadd (fadd x, c1), c2) -> (fadd x, (fadd c1, c2))
+ if (UnsafeFPMath && N1CFP && N0.getOpcode() == ISD::FADD &&
+ N0.Val->hasOneUse() && isa<ConstantFPSDNode>(N0.getOperand(1)))
+ return DAG.getNode(ISD::FADD, VT, N0.getOperand(0),
+ DAG.getNode(ISD::FADD, VT, N0.getOperand(1), N1));
+
return SDOperand();
}
// fold (fmul X, 2.0) -> (fadd X, X)
if (N1CFP && N1CFP->isExactlyValue(+2.0))
return DAG.getNode(ISD::FADD, VT, N0, N0);
+
+ // If allowed, fold (fmul (fmul x, c1), c2) -> (fmul x, (fmul c1, c2))
+ if (UnsafeFPMath && N1CFP && N0.getOpcode() == ISD::FMUL &&
+ N0.Val->hasOneUse() && isa<ConstantFPSDNode>(N0.getOperand(1)))
+ return DAG.getNode(ISD::FMUL, VT, N0.getOperand(0),
+ DAG.getNode(ISD::FMUL, VT, N0.getOperand(1), N1));
+
return SDOperand();
}
return DAG.getNode(ISD::FP_EXTEND, VT, N0);
// fold (fpext (load x)) -> (fpext (fpround (extload x)))
- if (N0.getOpcode() == ISD::LOAD && N0.hasOneUse() &&
+ if (ISD::isNON_EXTLoad(N0.Val) && N0.hasOneUse() &&
(!AfterLegalize||TLI.isLoadXLegal(ISD::EXTLOAD, N0.getValueType()))) {
- SDOperand ExtLoad = DAG.getExtLoad(ISD::EXTLOAD, VT, N0.getOperand(0),
- N0.getOperand(1), N0.getOperand(2),
- N0.getValueType());
+ LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ SDOperand ExtLoad = DAG.getExtLoad(ISD::EXTLOAD, VT, LN0->getChain(),
+ LN0->getBasePtr(), LN0->getSrcValue(),
+ LN0->getSrcValueOffset(),
+ N0.getValueType(),
+ LN0->isVolatile(),
+ LN0->getAlignment());
CombineTo(N, ExtLoad);
CombineTo(N0.Val, DAG.getNode(ISD::FP_ROUND, N0.getValueType(), ExtLoad),
ExtLoad.getValue(1));
// Use SimplifySetCC to simplify SETCC's.
SDOperand Simp = SimplifySetCC(MVT::i1, CondLHS, CondRHS, CC->get(), false);
+ if (Simp.Val) AddToWorkList(Simp.Val);
+
ConstantSDNode *SCCC = dyn_cast_or_null<ConstantSDNode>(Simp.Val);
// fold br_cc true, dest -> br dest (unconditional branch)
// fold br_cc false, dest -> unconditional fall through
if (SCCC && SCCC->isNullValue())
return N->getOperand(0);
+
// fold to a simpler setcc
if (Simp.Val && Simp.getOpcode() == ISD::SETCC)
return DAG.getNode(ISD::BR_CC, MVT::Other, N->getOperand(0),
return SDOperand();
}
-SDOperand DAGCombiner::visitLOAD(SDNode *N) {
- SDOperand Chain = N->getOperand(0);
- SDOperand Ptr = N->getOperand(1);
- SDOperand SrcValue = N->getOperand(2);
+
+/// CombineToPreIndexedLoadStore - Try turning a load / store and a
+/// pre-indexed load / store when the base pointer is a add or subtract
+/// and it has other uses besides the load / store. After the
+/// transformation, the new indexed load / store has effectively folded
+/// the add / subtract in and all of its other uses are redirected to the
+/// new load / store.
+bool DAGCombiner::CombineToPreIndexedLoadStore(SDNode *N) {
+ if (!AfterLegalize)
+ return false;
+
+ bool isLoad = true;
+ SDOperand Ptr;
+ MVT::ValueType VT;
+ if (LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
+ if (LD->getAddressingMode() != ISD::UNINDEXED)
+ return false;
+ VT = LD->getLoadedVT();
+ if (!TLI.isIndexedLoadLegal(ISD::PRE_INC, VT) &&
+ !TLI.isIndexedLoadLegal(ISD::PRE_DEC, VT))
+ return false;
+ Ptr = LD->getBasePtr();
+ } else if (StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) {
+ if (ST->getAddressingMode() != ISD::UNINDEXED)
+ return false;
+ VT = ST->getStoredVT();
+ if (!TLI.isIndexedStoreLegal(ISD::PRE_INC, VT) &&
+ !TLI.isIndexedStoreLegal(ISD::PRE_DEC, VT))
+ return false;
+ Ptr = ST->getBasePtr();
+ isLoad = false;
+ } else
+ return false;
+
+ // If the pointer is not an add/sub, or if it doesn't have multiple uses, bail
+ // out. There is no reason to make this a preinc/predec.
+ if ((Ptr.getOpcode() != ISD::ADD && Ptr.getOpcode() != ISD::SUB) ||
+ Ptr.Val->hasOneUse())
+ return false;
+
+ // Ask the target to do addressing mode selection.
+ SDOperand BasePtr;
+ SDOperand Offset;
+ ISD::MemIndexedMode AM = ISD::UNINDEXED;
+ if (!TLI.getPreIndexedAddressParts(N, BasePtr, Offset, AM, DAG))
+ return false;
+ // Don't create a indexed load / store with zero offset.
+ if (isa<ConstantSDNode>(Offset) &&
+ cast<ConstantSDNode>(Offset)->getValue() == 0)
+ return false;
- // If there are no uses of the loaded value, change uses of the chain value
- // into uses of the chain input (i.e. delete the dead load).
- if (N->hasNUsesOfValue(0, 0))
- return CombineTo(N, DAG.getNode(ISD::UNDEF, N->getValueType(0)), Chain);
+ // Try turning it into a pre-indexed load / store except when:
+ // 1) The base is a frame index.
+ // 2) If N is a store and the ptr is either the same as or is a
+ // predecessor of the value being stored.
+ // 3) Another use of base ptr is a predecessor of N. If ptr is folded
+ // that would create a cycle.
+ // 4) All uses are load / store ops that use it as base ptr.
+
+ // Check #1. Preinc'ing a frame index would require copying the stack pointer
+ // (plus the implicit offset) to a register to preinc anyway.
+ if (isa<FrameIndexSDNode>(BasePtr))
+ return false;
+
+ // Check #2.
+ if (!isLoad) {
+ SDOperand Val = cast<StoreSDNode>(N)->getValue();
+ if (Val == Ptr || Ptr.Val->isPredecessor(Val.Val))
+ return false;
+ }
+
+ // Now check for #2 and #3.
+ bool RealUse = false;
+ for (SDNode::use_iterator I = Ptr.Val->use_begin(),
+ E = Ptr.Val->use_end(); I != E; ++I) {
+ SDNode *Use = *I;
+ if (Use == N)
+ continue;
+ if (Use->isPredecessor(N))
+ return false;
+
+ if (!((Use->getOpcode() == ISD::LOAD &&
+ cast<LoadSDNode>(Use)->getBasePtr() == Ptr) ||
+ (Use->getOpcode() == ISD::STORE) &&
+ cast<StoreSDNode>(Use)->getBasePtr() == Ptr))
+ RealUse = true;
+ }
+ if (!RealUse)
+ return false;
+
+ SDOperand Result;
+ if (isLoad)
+ Result = DAG.getIndexedLoad(SDOperand(N,0), BasePtr, Offset, AM);
+ else
+ Result = DAG.getIndexedStore(SDOperand(N,0), BasePtr, Offset, AM);
+ ++PreIndexedNodes;
+ ++NodesCombined;
+ DOUT << "\nReplacing.4 "; DEBUG(N->dump());
+ DOUT << "\nWith: "; DEBUG(Result.Val->dump(&DAG));
+ DOUT << '\n';
+ std::vector<SDNode*> NowDead;
+ if (isLoad) {
+ DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 0), Result.getValue(0),
+ NowDead);
+ DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 1), Result.getValue(2),
+ NowDead);
+ } else {
+ DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 0), Result.getValue(1),
+ NowDead);
+ }
+
+ // Nodes can end up on the worklist more than once. Make sure we do
+ // not process a node that has been replaced.
+ for (unsigned i = 0, e = NowDead.size(); i != e; ++i)
+ removeFromWorkList(NowDead[i]);
+ // Finally, since the node is now dead, remove it from the graph.
+ DAG.DeleteNode(N);
+
+ // Replace the uses of Ptr with uses of the updated base value.
+ DAG.ReplaceAllUsesOfValueWith(Ptr, Result.getValue(isLoad ? 1 : 0),
+ NowDead);
+ removeFromWorkList(Ptr.Val);
+ for (unsigned i = 0, e = NowDead.size(); i != e; ++i)
+ removeFromWorkList(NowDead[i]);
+ DAG.DeleteNode(Ptr.Val);
+
+ return true;
+}
+
+/// CombineToPostIndexedLoadStore - Try combine a load / store with a
+/// add / sub of the base pointer node into a post-indexed load / store.
+/// The transformation folded the add / subtract into the new indexed
+/// load / store effectively and all of its uses are redirected to the
+/// new load / store.
+bool DAGCombiner::CombineToPostIndexedLoadStore(SDNode *N) {
+ if (!AfterLegalize)
+ return false;
+
+ bool isLoad = true;
+ SDOperand Ptr;
+ MVT::ValueType VT;
+ if (LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
+ if (LD->getAddressingMode() != ISD::UNINDEXED)
+ return false;
+ VT = LD->getLoadedVT();
+ if (!TLI.isIndexedLoadLegal(ISD::POST_INC, VT) &&
+ !TLI.isIndexedLoadLegal(ISD::POST_DEC, VT))
+ return false;
+ Ptr = LD->getBasePtr();
+ } else if (StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) {
+ if (ST->getAddressingMode() != ISD::UNINDEXED)
+ return false;
+ VT = ST->getStoredVT();
+ if (!TLI.isIndexedStoreLegal(ISD::POST_INC, VT) &&
+ !TLI.isIndexedStoreLegal(ISD::POST_DEC, VT))
+ return false;
+ Ptr = ST->getBasePtr();
+ isLoad = false;
+ } else
+ return false;
+
+ if (Ptr.Val->hasOneUse())
+ return false;
+
+ for (SDNode::use_iterator I = Ptr.Val->use_begin(),
+ E = Ptr.Val->use_end(); I != E; ++I) {
+ SDNode *Op = *I;
+ if (Op == N ||
+ (Op->getOpcode() != ISD::ADD && Op->getOpcode() != ISD::SUB))
+ continue;
+
+ SDOperand BasePtr;
+ SDOperand Offset;
+ ISD::MemIndexedMode AM = ISD::UNINDEXED;
+ if (TLI.getPostIndexedAddressParts(N, Op, BasePtr, Offset, AM, DAG)) {
+ if (Ptr == Offset)
+ std::swap(BasePtr, Offset);
+ if (Ptr != BasePtr)
+ continue;
+ // Don't create a indexed load / store with zero offset.
+ if (isa<ConstantSDNode>(Offset) &&
+ cast<ConstantSDNode>(Offset)->getValue() == 0)
+ continue;
+
+ // Try turning it into a post-indexed load / store except when
+ // 1) All uses are load / store ops that use it as base ptr.
+ // 2) Op must be independent of N, i.e. Op is neither a predecessor
+ // nor a successor of N. Otherwise, if Op is folded that would
+ // create a cycle.
+
+ // Check for #1.
+ bool TryNext = false;
+ for (SDNode::use_iterator II = BasePtr.Val->use_begin(),
+ EE = BasePtr.Val->use_end(); II != EE; ++II) {
+ SDNode *Use = *II;
+ if (Use == Ptr.Val)
+ continue;
+
+ // If all the uses are load / store addresses, then don't do the
+ // transformation.
+ if (Use->getOpcode() == ISD::ADD || Use->getOpcode() == ISD::SUB){
+ bool RealUse = false;
+ for (SDNode::use_iterator III = Use->use_begin(),
+ EEE = Use->use_end(); III != EEE; ++III) {
+ SDNode *UseUse = *III;
+ if (!((UseUse->getOpcode() == ISD::LOAD &&
+ cast<LoadSDNode>(UseUse)->getBasePtr().Val == Use) ||
+ (UseUse->getOpcode() == ISD::STORE) &&
+ cast<StoreSDNode>(UseUse)->getBasePtr().Val == Use))
+ RealUse = true;
+ }
+
+ if (!RealUse) {
+ TryNext = true;
+ break;
+ }
+ }
+ }
+ if (TryNext)
+ continue;
+
+ // Check for #2
+ if (!Op->isPredecessor(N) && !N->isPredecessor(Op)) {
+ SDOperand Result = isLoad
+ ? DAG.getIndexedLoad(SDOperand(N,0), BasePtr, Offset, AM)
+ : DAG.getIndexedStore(SDOperand(N,0), BasePtr, Offset, AM);
+ ++PostIndexedNodes;
+ ++NodesCombined;
+ DOUT << "\nReplacing.5 "; DEBUG(N->dump());
+ DOUT << "\nWith: "; DEBUG(Result.Val->dump(&DAG));
+ DOUT << '\n';
+ std::vector<SDNode*> NowDead;
+ if (isLoad) {
+ DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 0), Result.getValue(0),
+ NowDead);
+ DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 1), Result.getValue(2),
+ NowDead);
+ } else {
+ DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 0), Result.getValue(1),
+ NowDead);
+ }
+
+ // Nodes can end up on the worklist more than once. Make sure we do
+ // not process a node that has been replaced.
+ for (unsigned i = 0, e = NowDead.size(); i != e; ++i)
+ removeFromWorkList(NowDead[i]);
+ // Finally, since the node is now dead, remove it from the graph.
+ DAG.DeleteNode(N);
+
+ // Replace the uses of Use with uses of the updated base value.
+ DAG.ReplaceAllUsesOfValueWith(SDOperand(Op, 0),
+ Result.getValue(isLoad ? 1 : 0),
+ NowDead);
+ removeFromWorkList(Op);
+ for (unsigned i = 0, e = NowDead.size(); i != e; ++i)
+ removeFromWorkList(NowDead[i]);
+ DAG.DeleteNode(Op);
+
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+SDOperand DAGCombiner::visitLOAD(SDNode *N) {
+ LoadSDNode *LD = cast<LoadSDNode>(N);
+ SDOperand Chain = LD->getChain();
+ SDOperand Ptr = LD->getBasePtr();
+
+ // If load is not volatile and there are no uses of the loaded value (and
+ // the updated indexed value in case of indexed loads), change uses of the
+ // chain value into uses of the chain input (i.e. delete the dead load).
+ if (!LD->isVolatile()) {
+ if (N->getValueType(1) == MVT::Other) {
+ // Unindexed loads.
+ if (N->hasNUsesOfValue(0, 0))
+ return CombineTo(N, DAG.getNode(ISD::UNDEF, N->getValueType(0)), Chain);
+ } else {
+ // Indexed loads.
+ assert(N->getValueType(2) == MVT::Other && "Malformed indexed loads?");
+ if (N->hasNUsesOfValue(0, 0) && N->hasNUsesOfValue(0, 1)) {
+ SDOperand Undef0 = DAG.getNode(ISD::UNDEF, N->getValueType(0));
+ SDOperand Undef1 = DAG.getNode(ISD::UNDEF, N->getValueType(1));
+ SDOperand To[] = { Undef0, Undef1, Chain };
+ return CombineTo(N, To, 3);
+ }
+ }
+ }
// If this load is directly stored, replace the load value with the stored
// value.
// TODO: Handle store large -> read small portion.
- // TODO: Handle TRUNCSTORE/EXTLOAD
- if (Chain.getOpcode() == ISD::STORE && Chain.getOperand(2) == Ptr &&
- Chain.getOperand(1).getValueType() == N->getValueType(0))
- return CombineTo(N, Chain.getOperand(1), Chain);
+ // TODO: Handle TRUNCSTORE/LOADEXT
+ if (LD->getExtensionType() == ISD::NON_EXTLOAD) {
+ if (ISD::isNON_TRUNCStore(Chain.Val)) {
+ StoreSDNode *PrevST = cast<StoreSDNode>(Chain);
+ if (PrevST->getBasePtr() == Ptr &&
+ PrevST->getValue().getValueType() == N->getValueType(0))
+ return CombineTo(N, Chain.getOperand(1), Chain);
+ }
+ }
- if (CombinerAA) {
+ if (CombinerAA) {
// Walk up chain skipping non-aliasing memory nodes.
SDOperand BetterChain = FindBetterChain(N, Chain);
// If there is a better chain.
if (Chain != BetterChain) {
+ SDOperand ReplLoad;
+
// Replace the chain to void dependency.
- SDOperand ReplLoad = DAG.getLoad(N->getValueType(0), BetterChain, Ptr,
- SrcValue);
+ if (LD->getExtensionType() == ISD::NON_EXTLOAD) {
+ ReplLoad = DAG.getLoad(N->getValueType(0), BetterChain, Ptr,
+ LD->getSrcValue(), LD->getSrcValueOffset(),
+ LD->isVolatile(), LD->getAlignment());
+ } else {
+ ReplLoad = DAG.getExtLoad(LD->getExtensionType(),
+ LD->getValueType(0),
+ BetterChain, Ptr, LD->getSrcValue(),
+ LD->getSrcValueOffset(),
+ LD->getLoadedVT(),
+ LD->isVolatile(),
+ LD->getAlignment());
+ }
// Create token factor to keep old chain connected.
SDOperand Token = DAG.getNode(ISD::TokenFactor, MVT::Other,
Chain, ReplLoad.getValue(1));
- // Replace uses with load result and token factor.
- return CombineTo(N, ReplLoad.getValue(0), Token);
+ // Replace uses with load result and token factor. Don't add users
+ // to work list.
+ return CombineTo(N, ReplLoad.getValue(0), Token, false);
}
}
- return SDOperand();
-}
+ // Try transforming N to an indexed load.
+ if (CombineToPreIndexedLoadStore(N) || CombineToPostIndexedLoadStore(N))
+ return SDOperand(N, 0);
-/// visitLOADX - Handle EXTLOAD/ZEXTLOAD/SEXTLOAD.
-SDOperand DAGCombiner::visitLOADX(SDNode *N) {
- SDOperand Chain = N->getOperand(0);
- SDOperand Ptr = N->getOperand(1);
- SDOperand SrcValue = N->getOperand(2);
- SDOperand EVT = N->getOperand(3);
-
- // If there are no uses of the loaded value, change uses of the chain value
- // into uses of the chain input (i.e. delete the dead load).
- if (N->hasNUsesOfValue(0, 0))
- return CombineTo(N, DAG.getNode(ISD::UNDEF, N->getValueType(0)), Chain);
-
return SDOperand();
}
SDOperand DAGCombiner::visitSTORE(SDNode *N) {
- SDOperand Chain = N->getOperand(0);
- SDOperand Value = N->getOperand(1);
- SDOperand Ptr = N->getOperand(2);
- SDOperand SrcValue = N->getOperand(3);
-
- // If this is a store that kills a previous store, remove the previous store.
- if (Chain.getOpcode() == ISD::STORE && Chain.getOperand(2) == Ptr &&
- Chain.Val->hasOneUse() /* Avoid introducing DAG cycles */ &&
- // Make sure that these stores are the same value type:
- // FIXME: we really care that the second store is >= size of the first.
- Value.getValueType() == Chain.getOperand(1).getValueType()) {
- // Create a new store of Value that replaces both stores.
- SDNode *PrevStore = Chain.Val;
- if (PrevStore->getOperand(1) == Value) // Same value multiply stored.
- return Chain;
- SDOperand NewStore = DAG.getStore(PrevStore->getOperand(0), Value, Ptr,
- SrcValue);
- CombineTo(N, NewStore); // Nuke this store.
- CombineTo(PrevStore, NewStore); // Nuke the previous store.
- return SDOperand(N, 0);
- }
-
- // If this is a store of a bit convert, store the input value.
- // FIXME: This needs to know that the resultant store does not need a
- // higher alignment than the original.
- if (0 && Value.getOpcode() == ISD::BIT_CONVERT) {
- return DAG.getStore(Chain, Value.getOperand(0), Ptr, SrcValue);
+ StoreSDNode *ST = cast<StoreSDNode>(N);
+ SDOperand Chain = ST->getChain();
+ SDOperand Value = ST->getValue();
+ SDOperand Ptr = ST->getBasePtr();
+
+ // If this is a store of a bit convert, store the input value if the
+ // resultant store does not need a higher alignment than the original.
+ if (Value.getOpcode() == ISD::BIT_CONVERT && !ST->isTruncatingStore()) {
+ unsigned Align = ST->getAlignment();
+ MVT::ValueType SVT = Value.getOperand(0).getValueType();
+ unsigned OrigAlign = TLI.getTargetMachine().getTargetData()->
+ getPrefTypeAlignment(getTypeForValueType(SVT));
+ if (Align <= OrigAlign && TLI.isOperationLegal(ISD::STORE, SVT))
+ return DAG.getStore(Chain, Value.getOperand(0), Ptr, ST->getSrcValue(),
+ ST->getSrcValueOffset());
}
- if (CombinerAA) {
- // If the store ptr is a frame index and the frame index has a use of one
- // and this is a return block, then the store is redundant.
- if (Ptr.hasOneUse() && isa<FrameIndexSDNode>(Ptr) &&
- DAG.getRoot().getOpcode() == ISD::RET) {
- return Chain;
+ // Turn 'store float 1.0, Ptr' -> 'store int 0x12345678, Ptr'
+ if (ConstantFPSDNode *CFP = dyn_cast<ConstantFPSDNode>(Value)) {
+ if (Value.getOpcode() != ISD::TargetConstantFP) {
+ SDOperand Tmp;
+ switch (CFP->getValueType(0)) {
+ default: assert(0 && "Unknown FP type");
+ case MVT::f32:
+ if (!AfterLegalize || TLI.isTypeLegal(MVT::i32)) {
+ Tmp = DAG.getConstant(FloatToBits(CFP->getValue()), MVT::i32);
+ return DAG.getStore(Chain, Tmp, Ptr, ST->getSrcValue(),
+ ST->getSrcValueOffset());
+ }
+ break;
+ case MVT::f64:
+ if (!AfterLegalize || TLI.isTypeLegal(MVT::i64)) {
+ Tmp = DAG.getConstant(DoubleToBits(CFP->getValue()), MVT::i64);
+ return DAG.getStore(Chain, Tmp, Ptr, ST->getSrcValue(),
+ ST->getSrcValueOffset());
+ } else if (TLI.isTypeLegal(MVT::i32)) {
+ // Many FP stores are not make apparent until after legalize, e.g. for
+ // argument passing. Since this is so common, custom legalize the
+ // 64-bit integer store into two 32-bit stores.
+ uint64_t Val = DoubleToBits(CFP->getValue());
+ SDOperand Lo = DAG.getConstant(Val & 0xFFFFFFFF, MVT::i32);
+ SDOperand Hi = DAG.getConstant(Val >> 32, MVT::i32);
+ if (!TLI.isLittleEndian()) std::swap(Lo, Hi);
+
+ SDOperand St0 = DAG.getStore(Chain, Lo, Ptr, ST->getSrcValue(),
+ ST->getSrcValueOffset());
+ Ptr = DAG.getNode(ISD::ADD, Ptr.getValueType(), Ptr,
+ DAG.getConstant(4, Ptr.getValueType()));
+ SDOperand St1 = DAG.getStore(Chain, Hi, Ptr, ST->getSrcValue(),
+ ST->getSrcValueOffset()+4);
+ return DAG.getNode(ISD::TokenFactor, MVT::Other, St0, St1);
+ }
+ break;
+ }
}
+ }
+ if (CombinerAA) {
// Walk up chain skipping non-aliasing memory nodes.
SDOperand BetterChain = FindBetterChain(N, Chain);
// If there is a better chain.
if (Chain != BetterChain) {
// Replace the chain to avoid dependency.
- SDOperand ReplStore = DAG.getStore(BetterChain, Value, Ptr, SrcValue);
+ SDOperand ReplStore;
+ if (ST->isTruncatingStore()) {
+ ReplStore = DAG.getTruncStore(BetterChain, Value, Ptr,
+ ST->getSrcValue(),ST->getSrcValueOffset(), ST->getStoredVT());
+ } else {
+ ReplStore = DAG.getStore(BetterChain, Value, Ptr,
+ ST->getSrcValue(), ST->getSrcValueOffset());
+ }
+
// Create token to keep both nodes around.
- return DAG.getNode(ISD::TokenFactor, MVT::Other, Chain, ReplStore);
+ SDOperand Token =
+ DAG.getNode(ISD::TokenFactor, MVT::Other, Chain, ReplStore);
+
+ // Don't add users to work list.
+ return CombineTo(N, Token, false);
}
}
+ // Try transforming N to an indexed store.
+ if (CombineToPreIndexedLoadStore(N) || CombineToPostIndexedLoadStore(N))
+ return SDOperand(N, 0);
+
return SDOperand();
}
SmallVector<SDOperand, 8> BuildVecIndices;
for (unsigned i = 0; i != NumInScalars; ++i) {
if (N->getOperand(i).getOpcode() == ISD::UNDEF) {
- BuildVecIndices.push_back(DAG.getNode(ISD::UNDEF, MVT::i32));
+ BuildVecIndices.push_back(DAG.getNode(ISD::UNDEF, TLI.getPointerTy()));
continue;
}
// Otherwise, use InIdx + VecSize
unsigned Idx = cast<ConstantSDNode>(Extract.getOperand(1))->getValue();
- BuildVecIndices.push_back(DAG.getConstant(Idx+NumInScalars, MVT::i32));
+ BuildVecIndices.push_back(DAG.getConstant(Idx+NumInScalars,
+ TLI.getPointerTy()));
}
// Add count and size info.
BuildVecIndices.push_back(NumElts);
- BuildVecIndices.push_back(DAG.getValueType(MVT::i32));
+ BuildVecIndices.push_back(DAG.getValueType(TLI.getPointerTy()));
// Return the new VVECTOR_SHUFFLE node.
SDOperand Ops[5];
// all scalar elements the same.
if (isSplat) {
SDNode *V = N0.Val;
- if (V->getOpcode() == ISD::VBIT_CONVERT)
- V = V->getOperand(0).Val;
+
+ // If this is a vbit convert that changes the element type of the vector but
+ // not the number of vector elements, look through it. Be careful not to
+ // look though conversions that change things like v4f32 to v2f64.
+ if (V->getOpcode() == ISD::VBIT_CONVERT) {
+ SDOperand ConvInput = V->getOperand(0);
+ if (ConvInput.getValueType() == MVT::Vector &&
+ NumElts ==
+ ConvInput.getConstantOperandVal(ConvInput.getNumOperands()-2))
+ V = ConvInput.Val;
+ }
+
if (V->getOpcode() == ISD::VBUILD_VECTOR) {
unsigned NumElems = V->getNumOperands()-2;
if (NumElems > BaseIdx) {
// If this is a select from two identical things, try to pull the operation
// through the select.
if (LHS.getOpcode() == RHS.getOpcode() && LHS.hasOneUse() && RHS.hasOneUse()){
-#if 0
- std::cerr << "SELECT: ["; LHS.Val->dump();
- std::cerr << "] ["; RHS.Val->dump();
- std::cerr << "]\n";
-#endif
-
// If this is a load and the token chain is identical, replace the select
// of two loads with a load through a select of the address to load from.
// This triggers in things like "select bool X, 10.0, 123.0" after the FP
// constants have been dropped into the constant pool.
- if ((LHS.getOpcode() == ISD::LOAD ||
- LHS.getOpcode() == ISD::LOADX ) &&
+ if (LHS.getOpcode() == ISD::LOAD &&
// Token chains must be identical.
- LHS.getOperand(0) == RHS.getOperand(0) &&
- // If this is an EXTLOAD, the VT's must match.
- (LHS.getOpcode() == ISD::LOAD ||
- LHS.getOperand(3) == RHS.getOperand(3))) {
- // FIXME: this conflates two src values, discarding one. This is not
- // the right thing to do, but nothing uses srcvalues now. When they do,
- // turn SrcValue into a list of locations.
- SDOperand Addr;
- if (TheSelect->getOpcode() == ISD::SELECT)
- Addr = DAG.getNode(ISD::SELECT, LHS.getOperand(1).getValueType(),
- TheSelect->getOperand(0), LHS.getOperand(1),
- RHS.getOperand(1));
- else
- Addr = DAG.getNode(ISD::SELECT_CC, LHS.getOperand(1).getValueType(),
- TheSelect->getOperand(0),
- TheSelect->getOperand(1),
- LHS.getOperand(1), RHS.getOperand(1),
- TheSelect->getOperand(4));
-
- SDOperand Load;
- if (LHS.getOpcode() == ISD::LOAD)
- Load = DAG.getLoad(TheSelect->getValueType(0), LHS.getOperand(0),
- Addr, LHS.getOperand(2));
- else {
- unsigned LType = LHS.getConstantOperandVal(4);
- Load = DAG.getExtLoad((ISD::LoadExtType)LType,
- TheSelect->getValueType(0),
- LHS.getOperand(0), Addr, LHS.getOperand(2),
- cast<VTSDNode>(LHS.getOperand(3))->getVT());
+ LHS.getOperand(0) == RHS.getOperand(0)) {
+ LoadSDNode *LLD = cast<LoadSDNode>(LHS);
+ LoadSDNode *RLD = cast<LoadSDNode>(RHS);
+
+ // If this is an EXTLOAD, the VT's must match.
+ if (LLD->getLoadedVT() == RLD->getLoadedVT()) {
+ // FIXME: this conflates two src values, discarding one. This is not
+ // the right thing to do, but nothing uses srcvalues now. When they do,
+ // turn SrcValue into a list of locations.
+ SDOperand Addr;
+ if (TheSelect->getOpcode() == ISD::SELECT) {
+ // Check that the condition doesn't reach either load. If so, folding
+ // this will induce a cycle into the DAG.
+ if (!LLD->isPredecessor(TheSelect->getOperand(0).Val) &&
+ !RLD->isPredecessor(TheSelect->getOperand(0).Val)) {
+ Addr = DAG.getNode(ISD::SELECT, LLD->getBasePtr().getValueType(),
+ TheSelect->getOperand(0), LLD->getBasePtr(),
+ RLD->getBasePtr());
+ }
+ } else {
+ // Check that the condition doesn't reach either load. If so, folding
+ // this will induce a cycle into the DAG.
+ if (!LLD->isPredecessor(TheSelect->getOperand(0).Val) &&
+ !RLD->isPredecessor(TheSelect->getOperand(0).Val) &&
+ !LLD->isPredecessor(TheSelect->getOperand(1).Val) &&
+ !RLD->isPredecessor(TheSelect->getOperand(1).Val)) {
+ Addr = DAG.getNode(ISD::SELECT_CC, LLD->getBasePtr().getValueType(),
+ TheSelect->getOperand(0),
+ TheSelect->getOperand(1),
+ LLD->getBasePtr(), RLD->getBasePtr(),
+ TheSelect->getOperand(4));
+ }
+ }
+
+ if (Addr.Val) {
+ SDOperand Load;
+ if (LLD->getExtensionType() == ISD::NON_EXTLOAD)
+ Load = DAG.getLoad(TheSelect->getValueType(0), LLD->getChain(),
+ Addr,LLD->getSrcValue(),
+ LLD->getSrcValueOffset(),
+ LLD->isVolatile(),
+ LLD->getAlignment());
+ else {
+ Load = DAG.getExtLoad(LLD->getExtensionType(),
+ TheSelect->getValueType(0),
+ LLD->getChain(), Addr, LLD->getSrcValue(),
+ LLD->getSrcValueOffset(),
+ LLD->getLoadedVT(),
+ LLD->isVolatile(),
+ LLD->getAlignment());
+ }
+ // Users of the select now use the result of the load.
+ CombineTo(TheSelect, Load);
+
+ // Users of the old loads now use the new load's chain. We know the
+ // old-load value is dead now.
+ CombineTo(LHS.Val, Load.getValue(0), Load.getValue(1));
+ CombineTo(RHS.Val, Load.getValue(0), Load.getValue(1));
+ return true;
+ }
}
- // Users of the select now use the result of the load.
- CombineTo(TheSelect, Load);
-
- // Users of the old loads now use the new load's chain. We know the
- // old-load value is dead now.
- CombineTo(LHS.Val, Load.getValue(0), Load.getValue(1));
- CombineTo(RHS.Val, Load.getValue(0), Load.getValue(1));
- return true;
}
}
SDOperand DAGCombiner::SimplifySelectCC(SDOperand N0, SDOperand N1,
SDOperand N2, SDOperand N3,
- ISD::CondCode CC) {
+ ISD::CondCode CC, bool NotExtCompare) {
MVT::ValueType VT = N2.getValueType();
ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1.Val);
// Determine if the condition we're dealing with is constant
SDOperand SCC = SimplifySetCC(TLI.getSetCCResultTy(), N0, N1, CC, false);
+ if (SCC.Val) AddToWorkList(SCC.Val);
ConstantSDNode *SCCC = dyn_cast_or_null<ConstantSDNode>(SCC.Val);
// fold select_cc true, x, y -> x
// fold select C, 16, 0 -> shl C, 4
if (N2C && N3C && N3C->isNullValue() && isPowerOf2_64(N2C->getValue()) &&
TLI.getSetCCResultContents() == TargetLowering::ZeroOrOneSetCCResult) {
+
+ // If the caller doesn't want us to simplify this into a zext of a compare,
+ // don't do it.
+ if (NotExtCompare && N2C->getValue() == 1)
+ return SDOperand();
+
// Get a SetCC of the condition
// FIXME: Should probably make sure that setcc is legal if we ever have a
// target where it isn't.
// cast from setcc result type to select result type
if (AfterLegalize) {
SCC = DAG.getSetCC(TLI.getSetCCResultTy(), N0, N1, CC);
- Temp = DAG.getZeroExtendInReg(SCC, N2.getValueType());
+ if (N2.getValueType() < SCC.getValueType())
+ Temp = DAG.getZeroExtendInReg(SCC, N2.getValueType());
+ else
+ Temp = DAG.getNode(ISD::ZERO_EXTEND, N2.getValueType(), SCC);
} else {
SCC = DAG.getSetCC(MVT::i1, N0, N1, CC);
Temp = DAG.getNode(ISD::ZERO_EXTEND, N2.getValueType(), SCC);
}
AddToWorkList(SCC.Val);
AddToWorkList(Temp.Val);
+
+ if (N2C->getValue() == 1)
+ return Temp;
// shl setcc result by log2 n2c
return DAG.getNode(ISD::SHL, N2.getValueType(), Temp,
DAG.getConstant(Log2_64(N2C->getValue()),
// Check to see if this is an integer abs. select_cc setl[te] X, 0, -X, X ->
// Y = sra (X, size(X)-1); xor (add (X, Y), Y)
if (N1C && N1C->isNullValue() && (CC == ISD::SETLT || CC == ISD::SETLE) &&
- N0 == N3 && N2.getOpcode() == ISD::SUB && N0 == N2.getOperand(1)) {
- if (ConstantSDNode *SubC = dyn_cast<ConstantSDNode>(N2.getOperand(0))) {
+ N0 == N3 && N2.getOpcode() == ISD::SUB && N0 == N2.getOperand(1) &&
+ N2.getOperand(0) == N1 && MVT::isInteger(N0.getValueType())) {
+ MVT::ValueType XType = N0.getValueType();
+ SDOperand Shift = DAG.getNode(ISD::SRA, XType, N0,
+ DAG.getConstant(MVT::getSizeInBits(XType)-1,
+ TLI.getShiftAmountTy()));
+ SDOperand Add = DAG.getNode(ISD::ADD, XType, N0, Shift);
+ AddToWorkList(Shift.Val);
+ AddToWorkList(Add.Val);
+ return DAG.getNode(ISD::XOR, XType, Add, Shift);
+ }
+ // Check to see if this is an integer abs. select_cc setgt X, -1, X, -X ->
+ // Y = sra (X, size(X)-1); xor (add (X, Y), Y)
+ if (N1C && N1C->isAllOnesValue() && CC == ISD::SETGT &&
+ N0 == N2 && N3.getOpcode() == ISD::SUB && N0 == N3.getOperand(1)) {
+ if (ConstantSDNode *SubC = dyn_cast<ConstantSDNode>(N3.getOperand(0))) {
MVT::ValueType XType = N0.getValueType();
if (SubC->isNullValue() && MVT::isInteger(XType)) {
SDOperand Shift = DAG.getNode(ISD::SRA, XType, N0,
DAG.getConstant(MVT::getSizeInBits(XType)-1,
- TLI.getShiftAmountTy()));
+ TLI.getShiftAmountTy()));
SDOperand Add = DAG.getNode(ISD::ADD, XType, N0, Shift);
AddToWorkList(Shift.Val);
AddToWorkList(Add.Val);
}
}
}
-
+
return SDOperand();
}
+/// SimplifySetCC - This is a stub for TargetLowering::SimplifySetCC.
SDOperand DAGCombiner::SimplifySetCC(MVT::ValueType VT, SDOperand N0,
SDOperand N1, ISD::CondCode Cond,
bool foldBooleans) {
- // These setcc operations always fold.
- switch (Cond) {
- default: break;
- case ISD::SETFALSE:
- case ISD::SETFALSE2: return DAG.getConstant(0, VT);
- case ISD::SETTRUE:
- case ISD::SETTRUE2: return DAG.getConstant(1, VT);
- }
-
- if (ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1.Val)) {
- uint64_t C1 = N1C->getValue();
- if (ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0.Val)) {
- uint64_t C0 = N0C->getValue();
-
- // Sign extend the operands if required
- if (ISD::isSignedIntSetCC(Cond)) {
- C0 = N0C->getSignExtended();
- C1 = N1C->getSignExtended();
- }
-
- switch (Cond) {
- default: assert(0 && "Unknown integer setcc!");
- case ISD::SETEQ: return DAG.getConstant(C0 == C1, VT);
- case ISD::SETNE: return DAG.getConstant(C0 != C1, VT);
- case ISD::SETULT: return DAG.getConstant(C0 < C1, VT);
- case ISD::SETUGT: return DAG.getConstant(C0 > C1, VT);
- case ISD::SETULE: return DAG.getConstant(C0 <= C1, VT);
- case ISD::SETUGE: return DAG.getConstant(C0 >= C1, VT);
- case ISD::SETLT: return DAG.getConstant((int64_t)C0 < (int64_t)C1, VT);
- case ISD::SETGT: return DAG.getConstant((int64_t)C0 > (int64_t)C1, VT);
- case ISD::SETLE: return DAG.getConstant((int64_t)C0 <= (int64_t)C1, VT);
- case ISD::SETGE: return DAG.getConstant((int64_t)C0 >= (int64_t)C1, VT);
- }
- } else {
- // If the LHS is '(srl (ctlz x), 5)', the RHS is 0/1, and this is an
- // equality comparison, then we're just comparing whether X itself is
- // zero.
- if (N0.getOpcode() == ISD::SRL && (C1 == 0 || C1 == 1) &&
- N0.getOperand(0).getOpcode() == ISD::CTLZ &&
- N0.getOperand(1).getOpcode() == ISD::Constant) {
- unsigned ShAmt = cast<ConstantSDNode>(N0.getOperand(1))->getValue();
- if ((Cond == ISD::SETEQ || Cond == ISD::SETNE) &&
- ShAmt == Log2_32(MVT::getSizeInBits(N0.getValueType()))) {
- if ((C1 == 0) == (Cond == ISD::SETEQ)) {
- // (srl (ctlz x), 5) == 0 -> X != 0
- // (srl (ctlz x), 5) != 1 -> X != 0
- Cond = ISD::SETNE;
- } else {
- // (srl (ctlz x), 5) != 0 -> X == 0
- // (srl (ctlz x), 5) == 1 -> X == 0
- Cond = ISD::SETEQ;
- }
- SDOperand Zero = DAG.getConstant(0, N0.getValueType());
- return DAG.getSetCC(VT, N0.getOperand(0).getOperand(0),
- Zero, Cond);
- }
- }
-
- // If the LHS is a ZERO_EXTEND, perform the comparison on the input.
- if (N0.getOpcode() == ISD::ZERO_EXTEND) {
- unsigned InSize = MVT::getSizeInBits(N0.getOperand(0).getValueType());
-
- // If the comparison constant has bits in the upper part, the
- // zero-extended value could never match.
- if (C1 & (~0ULL << InSize)) {
- unsigned VSize = MVT::getSizeInBits(N0.getValueType());
- switch (Cond) {
- case ISD::SETUGT:
- case ISD::SETUGE:
- case ISD::SETEQ: return DAG.getConstant(0, VT);
- case ISD::SETULT:
- case ISD::SETULE:
- case ISD::SETNE: return DAG.getConstant(1, VT);
- case ISD::SETGT:
- case ISD::SETGE:
- // True if the sign bit of C1 is set.
- return DAG.getConstant((C1 & (1ULL << VSize)) != 0, VT);
- case ISD::SETLT:
- case ISD::SETLE:
- // True if the sign bit of C1 isn't set.
- return DAG.getConstant((C1 & (1ULL << VSize)) == 0, VT);
- default:
- break;
- }
- }
-
- // Otherwise, we can perform the comparison with the low bits.
- switch (Cond) {
- case ISD::SETEQ:
- case ISD::SETNE:
- case ISD::SETUGT:
- case ISD::SETUGE:
- case ISD::SETULT:
- case ISD::SETULE:
- return DAG.getSetCC(VT, N0.getOperand(0),
- DAG.getConstant(C1, N0.getOperand(0).getValueType()),
- Cond);
- default:
- break; // todo, be more careful with signed comparisons
- }
- } else if (N0.getOpcode() == ISD::SIGN_EXTEND_INREG &&
- (Cond == ISD::SETEQ || Cond == ISD::SETNE)) {
- MVT::ValueType ExtSrcTy = cast<VTSDNode>(N0.getOperand(1))->getVT();
- unsigned ExtSrcTyBits = MVT::getSizeInBits(ExtSrcTy);
- MVT::ValueType ExtDstTy = N0.getValueType();
- unsigned ExtDstTyBits = MVT::getSizeInBits(ExtDstTy);
-
- // If the extended part has any inconsistent bits, it cannot ever
- // compare equal. In other words, they have to be all ones or all
- // zeros.
- uint64_t ExtBits =
- (~0ULL >> (64-ExtSrcTyBits)) & (~0ULL << (ExtDstTyBits-1));
- if ((C1 & ExtBits) != 0 && (C1 & ExtBits) != ExtBits)
- return DAG.getConstant(Cond == ISD::SETNE, VT);
-
- SDOperand ZextOp;
- MVT::ValueType Op0Ty = N0.getOperand(0).getValueType();
- if (Op0Ty == ExtSrcTy) {
- ZextOp = N0.getOperand(0);
- } else {
- int64_t Imm = ~0ULL >> (64-ExtSrcTyBits);
- ZextOp = DAG.getNode(ISD::AND, Op0Ty, N0.getOperand(0),
- DAG.getConstant(Imm, Op0Ty));
- }
- AddToWorkList(ZextOp.Val);
- // Otherwise, make this a use of a zext.
- return DAG.getSetCC(VT, ZextOp,
- DAG.getConstant(C1 & (~0ULL>>(64-ExtSrcTyBits)),
- ExtDstTy),
- Cond);
- } else if ((N1C->getValue() == 0 || N1C->getValue() == 1) &&
- (Cond == ISD::SETEQ || Cond == ISD::SETNE) &&
- (N0.getOpcode() == ISD::XOR ||
- (N0.getOpcode() == ISD::AND &&
- N0.getOperand(0).getOpcode() == ISD::XOR &&
- N0.getOperand(1) == N0.getOperand(0).getOperand(1))) &&
- isa<ConstantSDNode>(N0.getOperand(1)) &&
- cast<ConstantSDNode>(N0.getOperand(1))->getValue() == 1) {
- // If this is (X^1) == 0/1, swap the RHS and eliminate the xor. We can
- // only do this if the top bits are known zero.
- if (TLI.MaskedValueIsZero(N1,
- MVT::getIntVTBitMask(N0.getValueType())-1)) {
- // Okay, get the un-inverted input value.
- SDOperand Val;
- if (N0.getOpcode() == ISD::XOR)
- Val = N0.getOperand(0);
- else {
- assert(N0.getOpcode() == ISD::AND &&
- N0.getOperand(0).getOpcode() == ISD::XOR);
- // ((X^1)&1)^1 -> X & 1
- Val = DAG.getNode(ISD::AND, N0.getValueType(),
- N0.getOperand(0).getOperand(0), N0.getOperand(1));
- }
- return DAG.getSetCC(VT, Val, N1,
- Cond == ISD::SETEQ ? ISD::SETNE : ISD::SETEQ);
- }
- }
-
- uint64_t MinVal, MaxVal;
- unsigned OperandBitSize = MVT::getSizeInBits(N1C->getValueType(0));
- if (ISD::isSignedIntSetCC(Cond)) {
- MinVal = 1ULL << (OperandBitSize-1);
- if (OperandBitSize != 1) // Avoid X >> 64, which is undefined.
- MaxVal = ~0ULL >> (65-OperandBitSize);
- else
- MaxVal = 0;
- } else {
- MinVal = 0;
- MaxVal = ~0ULL >> (64-OperandBitSize);
- }
-
- // Canonicalize GE/LE comparisons to use GT/LT comparisons.
- if (Cond == ISD::SETGE || Cond == ISD::SETUGE) {
- if (C1 == MinVal) return DAG.getConstant(1, VT); // X >= MIN --> true
- --C1; // X >= C0 --> X > (C0-1)
- return DAG.getSetCC(VT, N0, DAG.getConstant(C1, N1.getValueType()),
- (Cond == ISD::SETGE) ? ISD::SETGT : ISD::SETUGT);
- }
-
- if (Cond == ISD::SETLE || Cond == ISD::SETULE) {
- if (C1 == MaxVal) return DAG.getConstant(1, VT); // X <= MAX --> true
- ++C1; // X <= C0 --> X < (C0+1)
- return DAG.getSetCC(VT, N0, DAG.getConstant(C1, N1.getValueType()),
- (Cond == ISD::SETLE) ? ISD::SETLT : ISD::SETULT);
- }
-
- if ((Cond == ISD::SETLT || Cond == ISD::SETULT) && C1 == MinVal)
- return DAG.getConstant(0, VT); // X < MIN --> false
-
- // Canonicalize setgt X, Min --> setne X, Min
- if ((Cond == ISD::SETGT || Cond == ISD::SETUGT) && C1 == MinVal)
- return DAG.getSetCC(VT, N0, N1, ISD::SETNE);
- // Canonicalize setlt X, Max --> setne X, Max
- if ((Cond == ISD::SETLT || Cond == ISD::SETULT) && C1 == MaxVal)
- return DAG.getSetCC(VT, N0, N1, ISD::SETNE);
-
- // If we have setult X, 1, turn it into seteq X, 0
- if ((Cond == ISD::SETLT || Cond == ISD::SETULT) && C1 == MinVal+1)
- return DAG.getSetCC(VT, N0, DAG.getConstant(MinVal, N0.getValueType()),
- ISD::SETEQ);
- // If we have setugt X, Max-1, turn it into seteq X, Max
- else if ((Cond == ISD::SETGT || Cond == ISD::SETUGT) && C1 == MaxVal-1)
- return DAG.getSetCC(VT, N0, DAG.getConstant(MaxVal, N0.getValueType()),
- ISD::SETEQ);
-
- // If we have "setcc X, C0", check to see if we can shrink the immediate
- // by changing cc.
-
- // SETUGT X, SINTMAX -> SETLT X, 0
- if (Cond == ISD::SETUGT && OperandBitSize != 1 &&
- C1 == (~0ULL >> (65-OperandBitSize)))
- return DAG.getSetCC(VT, N0, DAG.getConstant(0, N1.getValueType()),
- ISD::SETLT);
-
- // FIXME: Implement the rest of these.
-
- // Fold bit comparisons when we can.
- if ((Cond == ISD::SETEQ || Cond == ISD::SETNE) &&
- VT == N0.getValueType() && N0.getOpcode() == ISD::AND)
- if (ConstantSDNode *AndRHS =
- dyn_cast<ConstantSDNode>(N0.getOperand(1))) {
- if (Cond == ISD::SETNE && C1 == 0) {// (X & 8) != 0 --> (X & 8) >> 3
- // Perform the xform if the AND RHS is a single bit.
- if ((AndRHS->getValue() & (AndRHS->getValue()-1)) == 0) {
- return DAG.getNode(ISD::SRL, VT, N0,
- DAG.getConstant(Log2_64(AndRHS->getValue()),
- TLI.getShiftAmountTy()));
- }
- } else if (Cond == ISD::SETEQ && C1 == AndRHS->getValue()) {
- // (X & 8) == 8 --> (X & 8) >> 3
- // Perform the xform if C1 is a single bit.
- if ((C1 & (C1-1)) == 0) {
- return DAG.getNode(ISD::SRL, VT, N0,
- DAG.getConstant(Log2_64(C1),TLI.getShiftAmountTy()));
- }
- }
- }
- }
- } else if (isa<ConstantSDNode>(N0.Val)) {
- // Ensure that the constant occurs on the RHS.
- return DAG.getSetCC(VT, N1, N0, ISD::getSetCCSwappedOperands(Cond));
- }
-
- if (ConstantFPSDNode *N0C = dyn_cast<ConstantFPSDNode>(N0.Val))
- if (ConstantFPSDNode *N1C = dyn_cast<ConstantFPSDNode>(N1.Val)) {
- double C0 = N0C->getValue(), C1 = N1C->getValue();
-
- switch (Cond) {
- default: break; // FIXME: Implement the rest of these!
- case ISD::SETEQ: return DAG.getConstant(C0 == C1, VT);
- case ISD::SETNE: return DAG.getConstant(C0 != C1, VT);
- case ISD::SETLT: return DAG.getConstant(C0 < C1, VT);
- case ISD::SETGT: return DAG.getConstant(C0 > C1, VT);
- case ISD::SETLE: return DAG.getConstant(C0 <= C1, VT);
- case ISD::SETGE: return DAG.getConstant(C0 >= C1, VT);
- }
- } else {
- // Ensure that the constant occurs on the RHS.
- return DAG.getSetCC(VT, N1, N0, ISD::getSetCCSwappedOperands(Cond));
- }
-
- if (N0 == N1) {
- // We can always fold X == Y for integer setcc's.
- if (MVT::isInteger(N0.getValueType()))
- return DAG.getConstant(ISD::isTrueWhenEqual(Cond), VT);
- unsigned UOF = ISD::getUnorderedFlavor(Cond);
- if (UOF == 2) // FP operators that are undefined on NaNs.
- return DAG.getConstant(ISD::isTrueWhenEqual(Cond), VT);
- if (UOF == unsigned(ISD::isTrueWhenEqual(Cond)))
- return DAG.getConstant(UOF, VT);
- // Otherwise, we can't fold it. However, we can simplify it to SETUO/SETO
- // if it is not already.
- ISD::CondCode NewCond = UOF == 0 ? ISD::SETO : ISD::SETUO;
- if (NewCond != Cond)
- return DAG.getSetCC(VT, N0, N1, NewCond);
- }
-
- if ((Cond == ISD::SETEQ || Cond == ISD::SETNE) &&
- MVT::isInteger(N0.getValueType())) {
- if (N0.getOpcode() == ISD::ADD || N0.getOpcode() == ISD::SUB ||
- N0.getOpcode() == ISD::XOR) {
- // Simplify (X+Y) == (X+Z) --> Y == Z
- if (N0.getOpcode() == N1.getOpcode()) {
- if (N0.getOperand(0) == N1.getOperand(0))
- return DAG.getSetCC(VT, N0.getOperand(1), N1.getOperand(1), Cond);
- if (N0.getOperand(1) == N1.getOperand(1))
- return DAG.getSetCC(VT, N0.getOperand(0), N1.getOperand(0), Cond);
- if (DAG.isCommutativeBinOp(N0.getOpcode())) {
- // If X op Y == Y op X, try other combinations.
- if (N0.getOperand(0) == N1.getOperand(1))
- return DAG.getSetCC(VT, N0.getOperand(1), N1.getOperand(0), Cond);
- if (N0.getOperand(1) == N1.getOperand(0))
- return DAG.getSetCC(VT, N0.getOperand(0), N1.getOperand(1), Cond);
- }
- }
-
- if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(N1)) {
- if (ConstantSDNode *LHSR = dyn_cast<ConstantSDNode>(N0.getOperand(1))) {
- // Turn (X+C1) == C2 --> X == C2-C1
- if (N0.getOpcode() == ISD::ADD && N0.Val->hasOneUse()) {
- return DAG.getSetCC(VT, N0.getOperand(0),
- DAG.getConstant(RHSC->getValue()-LHSR->getValue(),
- N0.getValueType()), Cond);
- }
-
- // Turn (X^C1) == C2 into X == C1^C2 iff X&~C1 = 0.
- if (N0.getOpcode() == ISD::XOR)
- // If we know that all of the inverted bits are zero, don't bother
- // performing the inversion.
- if (TLI.MaskedValueIsZero(N0.getOperand(0), ~LHSR->getValue()))
- return DAG.getSetCC(VT, N0.getOperand(0),
- DAG.getConstant(LHSR->getValue()^RHSC->getValue(),
- N0.getValueType()), Cond);
- }
-
- // Turn (C1-X) == C2 --> X == C1-C2
- if (ConstantSDNode *SUBC = dyn_cast<ConstantSDNode>(N0.getOperand(0))) {
- if (N0.getOpcode() == ISD::SUB && N0.Val->hasOneUse()) {
- return DAG.getSetCC(VT, N0.getOperand(1),
- DAG.getConstant(SUBC->getValue()-RHSC->getValue(),
- N0.getValueType()), Cond);
- }
- }
- }
-
- // Simplify (X+Z) == X --> Z == 0
- if (N0.getOperand(0) == N1)
- return DAG.getSetCC(VT, N0.getOperand(1),
- DAG.getConstant(0, N0.getValueType()), Cond);
- if (N0.getOperand(1) == N1) {
- if (DAG.isCommutativeBinOp(N0.getOpcode()))
- return DAG.getSetCC(VT, N0.getOperand(0),
- DAG.getConstant(0, N0.getValueType()), Cond);
- else {
- assert(N0.getOpcode() == ISD::SUB && "Unexpected operation!");
- // (Z-X) == X --> Z == X<<1
- SDOperand SH = DAG.getNode(ISD::SHL, N1.getValueType(),
- N1,
- DAG.getConstant(1,TLI.getShiftAmountTy()));
- AddToWorkList(SH.Val);
- return DAG.getSetCC(VT, N0.getOperand(0), SH, Cond);
- }
- }
- }
-
- if (N1.getOpcode() == ISD::ADD || N1.getOpcode() == ISD::SUB ||
- N1.getOpcode() == ISD::XOR) {
- // Simplify X == (X+Z) --> Z == 0
- if (N1.getOperand(0) == N0) {
- return DAG.getSetCC(VT, N1.getOperand(1),
- DAG.getConstant(0, N1.getValueType()), Cond);
- } else if (N1.getOperand(1) == N0) {
- if (DAG.isCommutativeBinOp(N1.getOpcode())) {
- return DAG.getSetCC(VT, N1.getOperand(0),
- DAG.getConstant(0, N1.getValueType()), Cond);
- } else {
- assert(N1.getOpcode() == ISD::SUB && "Unexpected operation!");
- // X == (Z-X) --> X<<1 == Z
- SDOperand SH = DAG.getNode(ISD::SHL, N1.getValueType(), N0,
- DAG.getConstant(1,TLI.getShiftAmountTy()));
- AddToWorkList(SH.Val);
- return DAG.getSetCC(VT, SH, N1.getOperand(0), Cond);
- }
- }
- }
- }
-
- // Fold away ALL boolean setcc's.
- SDOperand Temp;
- if (N0.getValueType() == MVT::i1 && foldBooleans) {
- switch (Cond) {
- default: assert(0 && "Unknown integer setcc!");
- case ISD::SETEQ: // X == Y -> (X^Y)^1
- Temp = DAG.getNode(ISD::XOR, MVT::i1, N0, N1);
- N0 = DAG.getNode(ISD::XOR, MVT::i1, Temp, DAG.getConstant(1, MVT::i1));
- AddToWorkList(Temp.Val);
- break;
- case ISD::SETNE: // X != Y --> (X^Y)
- N0 = DAG.getNode(ISD::XOR, MVT::i1, N0, N1);
- break;
- case ISD::SETGT: // X >s Y --> X == 0 & Y == 1 --> X^1 & Y
- case ISD::SETULT: // X <u Y --> X == 0 & Y == 1 --> X^1 & Y
- Temp = DAG.getNode(ISD::XOR, MVT::i1, N0, DAG.getConstant(1, MVT::i1));
- N0 = DAG.getNode(ISD::AND, MVT::i1, N1, Temp);
- AddToWorkList(Temp.Val);
- break;
- case ISD::SETLT: // X <s Y --> X == 1 & Y == 0 --> Y^1 & X
- case ISD::SETUGT: // X >u Y --> X == 1 & Y == 0 --> Y^1 & X
- Temp = DAG.getNode(ISD::XOR, MVT::i1, N1, DAG.getConstant(1, MVT::i1));
- N0 = DAG.getNode(ISD::AND, MVT::i1, N0, Temp);
- AddToWorkList(Temp.Val);
- break;
- case ISD::SETULE: // X <=u Y --> X == 0 | Y == 1 --> X^1 | Y
- case ISD::SETGE: // X >=s Y --> X == 0 | Y == 1 --> X^1 | Y
- Temp = DAG.getNode(ISD::XOR, MVT::i1, N0, DAG.getConstant(1, MVT::i1));
- N0 = DAG.getNode(ISD::OR, MVT::i1, N1, Temp);
- AddToWorkList(Temp.Val);
- break;
- case ISD::SETUGE: // X >=u Y --> X == 1 | Y == 0 --> Y^1 | X
- case ISD::SETLE: // X <=s Y --> X == 1 | Y == 0 --> Y^1 | X
- Temp = DAG.getNode(ISD::XOR, MVT::i1, N1, DAG.getConstant(1, MVT::i1));
- N0 = DAG.getNode(ISD::OR, MVT::i1, N0, Temp);
- break;
- }
- if (VT != MVT::i1) {
- AddToWorkList(N0.Val);
- // FIXME: If running after legalize, we probably can't do this.
- N0 = DAG.getNode(ISD::ZERO_EXTEND, VT, N0);
- }
- return N0;
- }
-
- // Could not fold it.
- return SDOperand();
+ TargetLowering::DAGCombinerInfo
+ DagCombineInfo(DAG, !AfterLegalize, false, this);
+ return TLI.SimplifySetCC(VT, N0, N1, Cond, foldBooleans, DagCombineInfo);
}
/// BuildSDIVSequence - Given an ISD::SDIV node expressing a divide by constant,
return S;
}
+/// FindBaseOffset - Return true if base is known not to alias with anything
+/// but itself. Provides base object and offset as results.
+static bool FindBaseOffset(SDOperand Ptr, SDOperand &Base, int64_t &Offset) {
+ // Assume it is a primitive operation.
+ Base = Ptr; Offset = 0;
+
+ // If it's an adding a simple constant then integrate the offset.
+ if (Base.getOpcode() == ISD::ADD) {
+ if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Base.getOperand(1))) {
+ Base = Base.getOperand(0);
+ Offset += C->getValue();
+ }
+ }
+
+ // If it's any of the following then it can't alias with anything but itself.
+ return isa<FrameIndexSDNode>(Base) ||
+ isa<ConstantPoolSDNode>(Base) ||
+ isa<GlobalAddressSDNode>(Base);
+}
+
+/// isAlias - Return true if there is any possibility that the two addresses
+/// overlap.
+bool DAGCombiner::isAlias(SDOperand Ptr1, int64_t Size1,
+ const Value *SrcValue1, int SrcValueOffset1,
+ SDOperand Ptr2, int64_t Size2,
+ const Value *SrcValue2, int SrcValueOffset2)
+{
+ // If they are the same then they must be aliases.
+ if (Ptr1 == Ptr2) return true;
+
+ // Gather base node and offset information.
+ SDOperand Base1, Base2;
+ int64_t Offset1, Offset2;
+ bool KnownBase1 = FindBaseOffset(Ptr1, Base1, Offset1);
+ bool KnownBase2 = FindBaseOffset(Ptr2, Base2, Offset2);
+
+ // If they have a same base address then...
+ if (Base1 == Base2) {
+ // Check to see if the addresses overlap.
+ return!((Offset1 + Size1) <= Offset2 || (Offset2 + Size2) <= Offset1);
+ }
+
+ // If we know both bases then they can't alias.
+ if (KnownBase1 && KnownBase2) return false;
+
+ if (CombinerGlobalAA) {
+ // Use alias analysis information.
+ int Overlap1 = Size1 + SrcValueOffset1 + Offset1;
+ int Overlap2 = Size2 + SrcValueOffset2 + Offset2;
+ AliasAnalysis::AliasResult AAResult =
+ AA.alias(SrcValue1, Overlap1, SrcValue2, Overlap2);
+ if (AAResult == AliasAnalysis::NoAlias)
+ return false;
+ }
+
+ // Otherwise we have to assume they alias.
+ return true;
+}
+
+/// FindAliasInfo - Extracts the relevant alias information from the memory
+/// node. Returns true if the operand was a load.
+bool DAGCombiner::FindAliasInfo(SDNode *N,
+ SDOperand &Ptr, int64_t &Size,
+ const Value *&SrcValue, int &SrcValueOffset) {
+ if (LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
+ Ptr = LD->getBasePtr();
+ Size = MVT::getSizeInBits(LD->getLoadedVT()) >> 3;
+ SrcValue = LD->getSrcValue();
+ SrcValueOffset = LD->getSrcValueOffset();
+ return true;
+ } else if (StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) {
+ Ptr = ST->getBasePtr();
+ Size = MVT::getSizeInBits(ST->getStoredVT()) >> 3;
+ SrcValue = ST->getSrcValue();
+ SrcValueOffset = ST->getSrcValueOffset();
+ } else {
+ assert(0 && "FindAliasInfo expected a memory operand");
+ }
+
+ return false;
+}
+
/// GatherAllAliases - Walk up chain skipping non-aliasing memory nodes,
/// looking for aliasing nodes and adding them to the Aliases vector.
void DAGCombiner::GatherAllAliases(SDNode *N, SDOperand OriginalChain,
// Get alias information for node.
SDOperand Ptr;
int64_t Size;
- SDOperand SrcValue;
- bool IsLoad = FindAliasInfo(N, Ptr, Size, SrcValue);
+ const Value *SrcValue;
+ int SrcValueOffset;
+ bool IsLoad = FindAliasInfo(N, Ptr, Size, SrcValue, SrcValueOffset);
// Starting off.
Chains.push_back(OriginalChain);
// Get alias information for Chain.
SDOperand OpPtr;
int64_t OpSize;
- SDOperand OpSrcValue;
- bool IsOpLoad = FindAliasInfo(Chain.Val, OpPtr, OpSize, OpSrcValue);
+ const Value *OpSrcValue;
+ int OpSrcValueOffset;
+ bool IsOpLoad = FindAliasInfo(Chain.Val, OpPtr, OpSize,
+ OpSrcValue, OpSrcValueOffset);
// If chain is alias then stop here.
if (!(IsLoad && IsOpLoad) &&
- isAlias(Ptr, Size, SrcValue, OpPtr, OpSize, OpSrcValue)) {
+ isAlias(Ptr, Size, SrcValue, SrcValueOffset,
+ OpPtr, OpSize, OpSrcValue, OpSrcValueOffset)) {
Aliases.push_back(Chain);
} else {
// Look further up the chain.
// SelectionDAG::Combine - This is the entry point for the file.
//
-void SelectionDAG::Combine(bool RunningAfterLegalize) {
+void SelectionDAG::Combine(bool RunningAfterLegalize, AliasAnalysis &AA) {
+ if (!RunningAfterLegalize && ViewDAGCombine1)
+ viewGraph();
+ if (RunningAfterLegalize && ViewDAGCombine2)
+ viewGraph();
/// run - This is the main entry point to this class.
///
- DAGCombiner(*this).Run(RunningAfterLegalize);
+ DAGCombiner(*this, AA).Run(RunningAfterLegalize);
}