[llvm] r258296 - [SelectionDAG] Fold more offsets into GlobalAddresses

Dan Gohman via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 19 23:03:08 PST 2016


Author: djg
Date: Wed Jan 20 01:03:08 2016
New Revision: 258296

URL: http://llvm.org/viewvc/llvm-project?rev=258296&view=rev
Log:
[SelectionDAG] Fold more offsets into GlobalAddresses

SelectionDAG previously missed opportunities to fold constants into
GlobalAddresses in several areas. For example, given `(add (add GA, c1), y)`, it
would often reassociate to `(add (add GA, y), c1)`, missing the opportunity to
create `(add GA+c, y)`. This isn't often visible on targets such as X86 which
effectively reassociate adds in their complex address-mode folding logic,
however it is currently visible on WebAssembly since it currently has very
simple address mode folding code that doesn't reassociate anything.

This patch fixes this by making SelectionDAG fold offsets into GlobalAddresses
at the same times that it folds constants together, so that it doesn't miss any
opportunities to perform such folding.

Differential Revision: http://reviews.llvm.org/D16090

Added:
    llvm/trunk/test/CodeGen/WebAssembly/address-offsets.ll
Modified:
    llvm/trunk/include/llvm/CodeGen/SelectionDAG.h
    llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
    llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
    llvm/trunk/test/CodeGen/X86/lea-opt.ll
    llvm/trunk/test/CodeGen/XCore/threads.ll

Modified: llvm/trunk/include/llvm/CodeGen/SelectionDAG.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/SelectionDAG.h?rev=258296&r1=258295&r2=258296&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/SelectionDAG.h (original)
+++ llvm/trunk/include/llvm/CodeGen/SelectionDAG.h Wed Jan 20 01:03:08 2016
@@ -1156,6 +1156,10 @@ public:
   /// either of the specified value types.
   SDValue CreateStackTemporary(EVT VT1, EVT VT2);
 
+  SDValue FoldSymbolOffset(unsigned Opcode, EVT VT,
+                           const GlobalAddressSDNode *GA,
+                           const SDNode *N2);
+
   SDValue FoldConstantArithmetic(unsigned Opcode, SDLoc DL, EVT VT,
                                  SDNode *Cst1, SDNode *Cst2);
 
@@ -1267,6 +1271,9 @@ public:
 
   unsigned getEVTAlignment(EVT MemoryVT) const;
 
+  /// Test whether the given value is a constant int or similar node.
+  SDNode *isConstantIntBuildVectorOrConstantInt(SDValue N);
+
 private:
   void InsertNode(SDNode *N);
   bool RemoveNodeFromCSEMaps(SDNode *N);

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp?rev=258296&r1=258295&r2=258296&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp Wed Jan 20 01:03:08 2016
@@ -390,6 +390,9 @@ namespace {
     /// consecutive chains.
     bool findBetterNeighborChains(StoreSDNode *St);
 
+    /// Match "(X shl/srl V1) & V2" where V2 may not be present.
+    bool MatchRotateHalf(SDValue Op, SDValue &Shift, SDValue &Mask);
+
     /// Holds a pointer to an LSBaseSDNode as well as information on where it
     /// is located in a sequence of memory operations connected by a chain.
     struct MemOpLink {
@@ -763,16 +766,6 @@ static bool isConstantSplatVector(SDNode
           EltVT.getSizeInBits() >= SplatBitSize);
 }
 
-// \brief Returns the SDNode if it is a constant integer BuildVector
-// or constant integer.
-static SDNode *isConstantIntBuildVectorOrConstantInt(SDValue N) {
-  if (isa<ConstantSDNode>(N))
-    return N.getNode();
-  if (ISD::isBuildVectorOfConstantSDNodes(N.getNode()))
-    return N.getNode();
-  return nullptr;
-}
-
 // \brief Returns the SDNode if it is a constant float BuildVector
 // or constant float.
 static SDNode *isConstantFPBuildVectorOrConstantFP(SDValue N) {
@@ -825,8 +818,8 @@ SDValue DAGCombiner::ReassociateOps(unsi
                                     SDValue N0, SDValue N1) {
   EVT VT = N0.getValueType();
   if (N0.getOpcode() == Opc) {
-    if (SDNode *L = isConstantIntBuildVectorOrConstantInt(N0.getOperand(1))) {
-      if (SDNode *R = isConstantIntBuildVectorOrConstantInt(N1)) {
+    if (SDNode *L = DAG.isConstantIntBuildVectorOrConstantInt(N0.getOperand(1))) {
+      if (SDNode *R = DAG.isConstantIntBuildVectorOrConstantInt(N1)) {
         // reassoc. (op (op x, c1), c2) -> (op x, (op c1, c2))
         if (SDValue OpNode = DAG.FoldConstantArithmetic(Opc, DL, VT, L, R))
           return DAG.getNode(Opc, DL, VT, N0.getOperand(0), OpNode);
@@ -845,8 +838,8 @@ SDValue DAGCombiner::ReassociateOps(unsi
   }
 
   if (N1.getOpcode() == Opc) {
-    if (SDNode *R = isConstantIntBuildVectorOrConstantInt(N1.getOperand(1))) {
-      if (SDNode *L = isConstantIntBuildVectorOrConstantInt(N0)) {
+    if (SDNode *R = DAG.isConstantIntBuildVectorOrConstantInt(N1.getOperand(1))) {
+      if (SDNode *L = DAG.isConstantIntBuildVectorOrConstantInt(N0)) {
         // reassoc. (op c2, (op x, c1)) -> (op x, (op c1, c2))
         if (SDValue OpNode = DAG.FoldConstantArithmetic(Opc, DL, VT, R, L))
           return DAG.getNode(Opc, DL, VT, N1.getOperand(0), OpNode);
@@ -1657,34 +1650,28 @@ SDValue DAGCombiner::visitADD(SDNode *N)
     return N0;
   if (N1.getOpcode() == ISD::UNDEF)
     return N1;
-  // fold (add c1, c2) -> c1+c2
-  ConstantSDNode *N0C = getAsNonOpaqueConstant(N0);
-  ConstantSDNode *N1C = getAsNonOpaqueConstant(N1);
-  if (N0C && N1C)
-    return DAG.FoldConstantArithmetic(ISD::ADD, SDLoc(N), VT, N0C, N1C);
-  // canonicalize constant to RHS
-  if (isConstantIntBuildVectorOrConstantInt(N0) &&
-     !isConstantIntBuildVectorOrConstantInt(N1))
-    return DAG.getNode(ISD::ADD, SDLoc(N), VT, N1, N0);
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0)) {
+    // canonicalize constant to RHS
+    if (!DAG.isConstantIntBuildVectorOrConstantInt(N1))
+      return DAG.getNode(ISD::ADD, SDLoc(N), VT, N1, N0);
+    // fold (add c1, c2) -> c1+c2
+    return DAG.FoldConstantArithmetic(ISD::ADD, SDLoc(N), VT,
+                                      N0.getNode(), N1.getNode());
+  }
   // fold (add x, 0) -> x
   if (isNullConstant(N1))
     return N0;
-  // fold (add Sym, c) -> Sym+c
-  if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(N0))
-    if (!LegalOperations && TLI.isOffsetFoldingLegal(GA) && N1C &&
-        GA->getOpcode() == ISD::GlobalAddress)
-      return DAG.getGlobalAddress(GA->getGlobal(), SDLoc(N1C), VT,
-                                  GA->getOffset() +
-                                    (uint64_t)N1C->getSExtValue());
   // fold ((c1-A)+c2) -> (c1+c2)-A
-  if (N1C && N0.getOpcode() == ISD::SUB)
-    if (ConstantSDNode *N0C = getAsNonOpaqueConstant(N0.getOperand(0))) {
-      SDLoc DL(N);
-      return DAG.getNode(ISD::SUB, DL, VT,
-                         DAG.getConstant(N1C->getAPIntValue()+
-                                         N0C->getAPIntValue(), DL, VT),
-                         N0.getOperand(1));
-    }
+  if (ConstantSDNode *N1C = getAsNonOpaqueConstant(N1)) {
+    if (N0.getOpcode() == ISD::SUB)
+      if (ConstantSDNode *N0C = getAsNonOpaqueConstant(N0.getOperand(0))) {
+        SDLoc DL(N);
+        return DAG.getNode(ISD::SUB, DL, VT,
+                           DAG.getConstant(N1C->getAPIntValue()+
+                                           N0C->getAPIntValue(), DL, VT),
+                           N0.getOperand(1));
+      }
+  }
   // reassociate add
   if (SDValue RADD = ReassociateOps(ISD::ADD, SDLoc(N), N0, N1))
     return RADD;
@@ -1879,11 +1866,14 @@ SDValue DAGCombiner::visitSUB(SDNode *N)
   // FIXME: Refactor this and xor and other similar operations together.
   if (N0 == N1)
     return tryFoldToZero(SDLoc(N), TLI, VT, DAG, LegalOperations, LegalTypes);
-  // fold (sub c1, c2) -> c1-c2
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&
+      DAG.isConstantIntBuildVectorOrConstantInt(N1)) {
+    // fold (sub c1, c2) -> c1-c2
+    return DAG.FoldConstantArithmetic(ISD::SUB, SDLoc(N), VT,
+                                      N0.getNode(), N1.getNode());
+  }
   ConstantSDNode *N0C = getAsNonOpaqueConstant(N0);
   ConstantSDNode *N1C = getAsNonOpaqueConstant(N1);
-  if (N0C && N1C)
-    return DAG.FoldConstantArithmetic(ISD::SUB, SDLoc(N), VT, N0C, N1C);
   // fold (sub x, c) -> (add x, -c)
   if (N1C) {
     SDLoc DL(N);
@@ -2047,8 +2037,8 @@ SDValue DAGCombiner::visitMUL(SDNode *N)
                                       N0.getNode(), N1.getNode());
 
   // canonicalize constant to RHS (vector doesn't have to splat)
-  if (isConstantIntBuildVectorOrConstantInt(N0) &&
-     !isConstantIntBuildVectorOrConstantInt(N1))
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&
+     !DAG.isConstantIntBuildVectorOrConstantInt(N1))
     return DAG.getNode(ISD::MUL, SDLoc(N), VT, N1, N0);
   // fold (mul x, 0) -> 0
   if (N1IsConst && ConstValue1 == 0)
@@ -2125,9 +2115,9 @@ SDValue DAGCombiner::visitMUL(SDNode *N)
   }
 
   // fold (mul (add x, c1), c2) -> (add (mul x, c2), c1*c2)
-  if (isConstantIntBuildVectorOrConstantInt(N1) &&
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N1) &&
       N0.getOpcode() == ISD::ADD &&
-      isConstantIntBuildVectorOrConstantInt(N0.getOperand(1)) &&
+      DAG.isConstantIntBuildVectorOrConstantInt(N0.getOperand(1)) &&
       isMulAddWithConstProfitable(N, N0, N1))
       return DAG.getNode(ISD::ADD, SDLoc(N), VT,
                          DAG.getNode(ISD::MUL, SDLoc(N0), VT,
@@ -2698,8 +2688,8 @@ SDValue DAGCombiner::visitIMINMAX(SDNode
     return DAG.FoldConstantArithmetic(N->getOpcode(), SDLoc(N), VT, N0C, N1C);
 
   // canonicalize constant to RHS
-  if (isConstantIntBuildVectorOrConstantInt(N0) &&
-     !isConstantIntBuildVectorOrConstantInt(N1))
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&
+     !DAG.isConstantIntBuildVectorOrConstantInt(N1))
     return DAG.getNode(N->getOpcode(), SDLoc(N), VT, N1, N0);
 
   return SDValue();
@@ -3045,8 +3035,8 @@ SDValue DAGCombiner::visitAND(SDNode *N)
   if (N0C && N1C && !N1C->isOpaque())
     return DAG.FoldConstantArithmetic(ISD::AND, SDLoc(N), VT, N0C, N1C);
   // canonicalize constant to RHS
-  if (isConstantIntBuildVectorOrConstantInt(N0) &&
-     !isConstantIntBuildVectorOrConstantInt(N1))
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&
+     !DAG.isConstantIntBuildVectorOrConstantInt(N1))
     return DAG.getNode(ISD::AND, SDLoc(N), VT, N1, N0);
   // fold (and x, -1) -> x
   if (isAllOnesConstant(N1))
@@ -3760,8 +3750,8 @@ SDValue DAGCombiner::visitOR(SDNode *N)
   if (N0C && N1C && !N1C->isOpaque())
     return DAG.FoldConstantArithmetic(ISD::OR, SDLoc(N), VT, N0C, N1C);
   // canonicalize constant to RHS
-  if (isConstantIntBuildVectorOrConstantInt(N0) &&
-     !isConstantIntBuildVectorOrConstantInt(N1))
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&
+     !DAG.isConstantIntBuildVectorOrConstantInt(N1))
     return DAG.getNode(ISD::OR, SDLoc(N), VT, N1, N0);
   // fold (or x, 0) -> x
   if (isNullConstant(N1))
@@ -3817,9 +3807,9 @@ SDValue DAGCombiner::visitOR(SDNode *N)
 }
 
 /// Match "(X shl/srl V1) & V2" where V2 may not be present.
-static bool MatchRotateHalf(SDValue Op, SDValue &Shift, SDValue &Mask) {
+bool DAGCombiner::MatchRotateHalf(SDValue Op, SDValue &Shift, SDValue &Mask) {
   if (Op.getOpcode() == ISD::AND) {
-    if (isConstantIntBuildVectorOrConstantInt(Op.getOperand(1))) {
+    if (DAG.isConstantIntBuildVectorOrConstantInt(Op.getOperand(1))) {
       Mask = Op.getOperand(1);
       Op = Op.getOperand(0);
     } else {
@@ -4106,8 +4096,8 @@ SDValue DAGCombiner::visitXOR(SDNode *N)
   if (N0C && N1C)
     return DAG.FoldConstantArithmetic(ISD::XOR, SDLoc(N), VT, N0C, N1C);
   // canonicalize constant to RHS
-  if (isConstantIntBuildVectorOrConstantInt(N0) &&
-     !isConstantIntBuildVectorOrConstantInt(N1))
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&
+     !DAG.isConstantIntBuildVectorOrConstantInt(N1))
     return DAG.getNode(ISD::XOR, SDLoc(N), VT, N1, N0);
   // fold (xor x, 0) -> x
   if (isNullConstant(N1))
@@ -4916,7 +4906,7 @@ SDValue DAGCombiner::visitBSWAP(SDNode *
   EVT VT = N->getValueType(0);
 
   // fold (bswap c1) -> c2
-  if (isConstantIntBuildVectorOrConstantInt(N0))
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0))
     return DAG.getNode(ISD::BSWAP, SDLoc(N), VT, N0);
   // fold (bswap (bswap x)) -> x
   if (N0.getOpcode() == ISD::BSWAP)
@@ -4929,7 +4919,7 @@ SDValue DAGCombiner::visitCTLZ(SDNode *N
   EVT VT = N->getValueType(0);
 
   // fold (ctlz c1) -> c2
-  if (isConstantIntBuildVectorOrConstantInt(N0))
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0))
     return DAG.getNode(ISD::CTLZ, SDLoc(N), VT, N0);
   return SDValue();
 }
@@ -4939,7 +4929,7 @@ SDValue DAGCombiner::visitCTLZ_ZERO_UNDE
   EVT VT = N->getValueType(0);
 
   // fold (ctlz_zero_undef c1) -> c2
-  if (isConstantIntBuildVectorOrConstantInt(N0))
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0))
     return DAG.getNode(ISD::CTLZ_ZERO_UNDEF, SDLoc(N), VT, N0);
   return SDValue();
 }
@@ -4949,7 +4939,7 @@ SDValue DAGCombiner::visitCTTZ(SDNode *N
   EVT VT = N->getValueType(0);
 
   // fold (cttz c1) -> c2
-  if (isConstantIntBuildVectorOrConstantInt(N0))
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0))
     return DAG.getNode(ISD::CTTZ, SDLoc(N), VT, N0);
   return SDValue();
 }
@@ -4959,7 +4949,7 @@ SDValue DAGCombiner::visitCTTZ_ZERO_UNDE
   EVT VT = N->getValueType(0);
 
   // fold (cttz_zero_undef c1) -> c2
-  if (isConstantIntBuildVectorOrConstantInt(N0))
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0))
     return DAG.getNode(ISD::CTTZ_ZERO_UNDEF, SDLoc(N), VT, N0);
   return SDValue();
 }
@@ -4969,7 +4959,7 @@ SDValue DAGCombiner::visitCTPOP(SDNode *
   EVT VT = N->getValueType(0);
 
   // fold (ctpop c1) -> c2
-  if (isConstantIntBuildVectorOrConstantInt(N0))
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0))
     return DAG.getNode(ISD::CTPOP, SDLoc(N), VT, N0);
   return SDValue();
 }
@@ -6902,7 +6892,7 @@ SDValue DAGCombiner::visitSIGN_EXTEND_IN
     return DAG.getUNDEF(VT);
 
   // fold (sext_in_reg c1) -> c1
-  if (isConstantIntBuildVectorOrConstantInt(N0))
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0))
     return DAG.getNode(ISD::SIGN_EXTEND_INREG, SDLoc(N), VT, N0, N1);
 
   // If the input is already sign extended, just drop the extension.
@@ -7021,7 +7011,7 @@ SDValue DAGCombiner::visitTRUNCATE(SDNod
   if (N0.getValueType() == N->getValueType(0))
     return N0;
   // fold (truncate c1) -> c1
-  if (isConstantIntBuildVectorOrConstantInt(N0))
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0))
     return DAG.getNode(ISD::TRUNCATE, SDLoc(N), VT, N0);
   // fold (truncate (truncate x)) -> (truncate x)
   if (N0.getOpcode() == ISD::TRUNCATE)
@@ -8868,7 +8858,7 @@ SDValue DAGCombiner::visitSINT_TO_FP(SDN
   EVT OpVT = N0.getValueType();
 
   // fold (sint_to_fp c1) -> c1fp
-  if (isConstantIntBuildVectorOrConstantInt(N0) &&
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&
       // ...but only if the target supports immediate floating-point values
       (!LegalOperations ||
        TLI.isOperationLegalOrCustom(llvm::ISD::ConstantFP, VT)))
@@ -8922,7 +8912,7 @@ SDValue DAGCombiner::visitUINT_TO_FP(SDN
   EVT OpVT = N0.getValueType();
 
   // fold (uint_to_fp c1) -> c1fp
-  if (isConstantIntBuildVectorOrConstantInt(N0) &&
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&
       // ...but only if the target supports immediate floating-point values
       (!LegalOperations ||
        TLI.isOperationLegalOrCustom(llvm::ISD::ConstantFP, VT)))
@@ -10940,9 +10930,23 @@ struct BaseIndexOffset {
   }
 
   /// Parses tree in Ptr for base, index, offset addresses.
-  static BaseIndexOffset match(SDValue Ptr) {
+  static BaseIndexOffset match(SDValue Ptr, SelectionDAG &DAG) {
     bool IsIndexSignExt = false;
 
+    // Split up a folded GlobalAddress+Offset into its component parts.
+    if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Ptr))
+      if (GA->getOpcode() == ISD::GlobalAddress && GA->getOffset() != 0) {
+        return BaseIndexOffset(DAG.getGlobalAddress(GA->getGlobal(),
+                                                    SDLoc(GA),
+                                                    GA->getValueType(0),
+                                                    /*Offset=*/0,
+                                                    /*isTargetGA=*/false,
+                                                    GA->getTargetFlags()),
+                               SDValue(),
+                               GA->getOffset(),
+                               IsIndexSignExt);
+      }
+
     // We only can pattern match BASE + INDEX + OFFSET. If Ptr is not an ADD
     // instruction, then it could be just the BASE or everything else we don't
     // know how to handle. Just use Ptr as BASE and give up.
@@ -11063,7 +11067,7 @@ bool DAGCombiner::isMulAddWithConstProfi
       // multiply (CONST * A) after we also do the same transformation
       // to the "t2" instruction.
       if (OtherOp->getOpcode() == ISD::ADD &&
-          isConstantIntBuildVectorOrConstantInt(OtherOp->getOperand(1)) &&
+          DAG.isConstantIntBuildVectorOrConstantInt(OtherOp->getOperand(1)) &&
           OtherOp->getOperand(0).getNode() == MulVar)
         return true;
     }
@@ -11215,7 +11219,7 @@ void DAGCombiner::getStoreMergeAndAliasC
     SmallVectorImpl<LSBaseSDNode*> &AliasLoadNodes) {
   // This holds the base pointer, index, and the offset in bytes from the base
   // pointer.
-  BaseIndexOffset BasePtr = BaseIndexOffset::match(St->getBasePtr());
+  BaseIndexOffset BasePtr = BaseIndexOffset::match(St->getBasePtr(), DAG);
 
   // We must have a base and an offset.
   if (!BasePtr.Base.getNode())
@@ -11253,7 +11257,7 @@ void DAGCombiner::getStoreMergeAndAliasC
         if (OtherST->getMemoryVT() != MemVT)
           continue;
 
-        BaseIndexOffset Ptr = BaseIndexOffset::match(OtherST->getBasePtr());
+        BaseIndexOffset Ptr = BaseIndexOffset::match(OtherST->getBasePtr(), DAG);
 
         if (Ptr.equalBaseIndex(BasePtr))
           StoreNodes.push_back(MemOpLink(OtherST, Ptr.Offset, Seq++));
@@ -11269,7 +11273,7 @@ void DAGCombiner::getStoreMergeAndAliasC
       break;
 
     // Find the base pointer and offset for this memory node.
-    BaseIndexOffset Ptr = BaseIndexOffset::match(Index->getBasePtr());
+    BaseIndexOffset Ptr = BaseIndexOffset::match(Index->getBasePtr(), DAG);
 
     // Check that the base pointer is the same as the original one.
     if (!Ptr.equalBaseIndex(BasePtr))
@@ -11557,7 +11561,7 @@ bool DAGCombiner::MergeConsecutiveStores
     if (Ld->getMemoryVT() != MemVT)
       break;
 
-    BaseIndexOffset LdPtr = BaseIndexOffset::match(Ld->getBasePtr());
+    BaseIndexOffset LdPtr = BaseIndexOffset::match(Ld->getBasePtr(), DAG);
     // If this is not the first ptr that we check.
     if (LdBasePtr.Base.getNode()) {
       // The base ptr must be the same.
@@ -14716,7 +14720,7 @@ SDValue DAGCombiner::FindBetterChain(SDN
 bool DAGCombiner::findBetterNeighborChains(StoreSDNode* St) {
   // This holds the base pointer, index, and the offset in bytes from the base
   // pointer.
-  BaseIndexOffset BasePtr = BaseIndexOffset::match(St->getBasePtr());
+  BaseIndexOffset BasePtr = BaseIndexOffset::match(St->getBasePtr(), DAG);
 
   // We must have a base and an offset.
   if (!BasePtr.Base.getNode())
@@ -14742,7 +14746,7 @@ bool DAGCombiner::findBetterNeighborChai
       break;
 
     // Find the base pointer and offset for this memory node.
-    BaseIndexOffset Ptr = BaseIndexOffset::match(Index->getBasePtr());
+    BaseIndexOffset Ptr = BaseIndexOffset::match(Index->getBasePtr(), DAG);
 
     // Check that the base pointer is the same as the original one.
     if (!Ptr.equalBaseIndex(BasePtr))

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp?rev=258296&r1=258295&r2=258296&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp Wed Jan 20 01:03:08 2016
@@ -3263,6 +3263,26 @@ SDValue SelectionDAG::FoldConstantArithm
   return getConstant(Folded.first, DL, VT);
 }
 
+SDValue SelectionDAG::FoldSymbolOffset(unsigned Opcode, EVT VT,
+                                       const GlobalAddressSDNode *GA,
+                                       const SDNode *N2) {
+  if (GA->getOpcode() != ISD::GlobalAddress)
+    return SDValue();
+  if (!TLI->isOffsetFoldingLegal(GA))
+    return SDValue();
+  const ConstantSDNode *Cst2 = dyn_cast<ConstantSDNode>(N2);
+  if (!Cst2)
+    return SDValue();
+  int64_t Offset = Cst2->getSExtValue();
+  switch (Opcode) {
+  case ISD::ADD: break;
+  case ISD::SUB: Offset = -uint64_t(Offset); break;
+  default: return SDValue();
+  }
+  return getGlobalAddress(GA->getGlobal(), SDLoc(Cst2), VT,
+                          GA->getOffset() + uint64_t(Offset));
+}
+
 SDValue SelectionDAG::FoldConstantArithmetic(unsigned Opcode, SDLoc DL, EVT VT,
                                              SDNode *Cst1, SDNode *Cst2) {
   // If the opcode is a target-specific ISD node, there's nothing we can
@@ -3289,6 +3309,12 @@ SDValue SelectionDAG::FoldConstantArithm
     }
   }
 
+  // fold (add Sym, c) -> Sym+c
+  if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Cst1))
+    return FoldSymbolOffset(Opcode, VT, GA, Cst2);
+  if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Cst2))
+    return FoldSymbolOffset(Opcode, VT, GA, Cst1);
+
   // For vectors extract each constant element into Inputs so we can constant
   // fold them individually.
   BuildVectorSDNode *BV1 = dyn_cast<BuildVectorSDNode>(Cst1);
@@ -7322,6 +7348,22 @@ bool ShuffleVectorSDNode::isSplatMask(co
   return true;
 }
 
+// \brief Returns the SDNode if it is a constant integer BuildVector
+// or constant integer.
+SDNode *SelectionDAG::isConstantIntBuildVectorOrConstantInt(SDValue N) {
+  if (isa<ConstantSDNode>(N))
+    return N.getNode();
+  if (ISD::isBuildVectorOfConstantSDNodes(N.getNode()))
+    return N.getNode();
+  // Treat a GlobalAddress supporting constant offset folding as a
+  // constant integer.
+  if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(N))
+    if (GA->getOpcode() == ISD::GlobalAddress &&
+        TLI->isOffsetFoldingLegal(GA))
+      return GA;
+  return nullptr;
+}
+
 #ifndef NDEBUG
 static void checkForCyclesHelper(const SDNode *N,
                                  SmallPtrSetImpl<const SDNode*> &Visited,

Added: llvm/trunk/test/CodeGen/WebAssembly/address-offsets.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/address-offsets.ll?rev=258296&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/address-offsets.ll (added)
+++ llvm/trunk/test/CodeGen/WebAssembly/address-offsets.ll Wed Jan 20 01:03:08 2016
@@ -0,0 +1,672 @@
+; RUN: llc < %s -asm-verbose=false | FileCheck %s
+
+; Test folding constant offsets and symbols into load and store addresses under
+; a variety of circumstances.
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+ at g = external global [0 x i32], align 4
+
+; CHECK-LABEL: load_test0:
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 0{{$}}
+; CHECK-NEXT: i32.load  $push1=, g+40($pop0){{$}}
+; CHECK-NEXT: return    $pop1{{$}}
+define i32 @load_test0() {
+  %t = load i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test0_noinbounds:
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 0{{$}}
+; CHECK-NEXT: i32.load  $push1=, g+40($pop0){{$}}
+; CHECK-NEXT: return    $pop1{{$}}
+define i32 @load_test0_noinbounds() {
+  %t = load i32, i32* getelementptr ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test1:
+; CHECK-NEXT: param     i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.load  $push2=, g+40($pop1){{$}}
+; CHECK-NEXT: return    $pop2{{$}}
+define i32 @load_test1(i32 %n) {
+  %add = add nsw i32 %n, 10
+  %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
+  %t = load i32, i32* %arrayidx, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test2:
+; CHECK-NEXT: param     i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.load  $push2=, g+40($pop1){{$}}
+; CHECK-NEXT: return    $pop2{{$}}
+define i32 @load_test2(i32 %n) {
+  %add = add nsw i32 10, %n
+  %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
+  %t = load i32, i32* %arrayidx, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test3:
+; CHECK-NEXT: param     i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.load  $push2=, g+40($pop1){{$}}
+; CHECK-NEXT: return    $pop2{{$}}
+define i32 @load_test3(i32 %n) {
+  %add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %n
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10
+  %t = load i32, i32* %add.ptr1, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test4:
+; CHECK-NEXT: param     i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.load  $push2=, g+40($pop1){{$}}
+; CHECK-NEXT: return    $pop2{{$}}
+define i32 @load_test4(i32 %n) {
+  %add.ptr = getelementptr inbounds i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), i32 %n
+  %t = load i32, i32* %add.ptr, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test5:
+; CHECK-NEXT: param     i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.load  $push2=, g+40($pop1){{$}}
+; CHECK-NEXT: return    $pop2{{$}}
+define i32 @load_test5(i32 %n) {
+  %add.ptr = getelementptr inbounds i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), i32 %n
+  %t = load i32, i32* %add.ptr, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test6:
+; CHECK-NEXT: param     i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.load  $push2=, g+40($pop1){{$}}
+; CHECK-NEXT: return    $pop2{{$}}
+define i32 @load_test6(i32 %n) {
+  %add = add nsw i32 %n, 10
+  %add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
+  %t = load i32, i32* %add.ptr, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test7:
+; CHECK-NEXT: param     i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.load  $push2=, g+40($pop1){{$}}
+; CHECK-NEXT: return    $pop2{{$}}
+define i32 @load_test7(i32 %n) {
+  %add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %n
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10
+  %t = load i32, i32* %add.ptr1, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test8:
+; CHECK-NEXT: param     i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.load  $push2=, g+40($pop1){{$}}
+; CHECK-NEXT: return    $pop2{{$}}
+define i32 @load_test8(i32 %n) {
+  %add = add nsw i32 10, %n
+  %add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
+  %t = load i32, i32* %add.ptr, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test9:
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 0{{$}}
+; CHECK-NEXT: i32.load  $push1=, g-40($pop0){{$}}
+; CHECK-NEXT: return    $pop1{{$}}
+define i32 @load_test9() {
+  %t = load i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 1073741814), align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test10:
+; CHECK-NEXT: param     i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.const $push2=, g-40{{$}}
+; CHECK-NEXT: i32.add   $push3=, $pop1, $pop2{{$}}
+; CHECK-NEXT: i32.load  $push4=, 0($pop3){{$}}
+; CHECK-NEXT: return    $pop4{{$}}
+define i32 @load_test10(i32 %n) {
+  %add = add nsw i32 %n, -10
+  %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
+  %t = load i32, i32* %arrayidx, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test11:
+; CHECK-NEXT: param     i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.load  $push0=, 40($0){{$}}
+; CHECK-NEXT: return    $pop0{{$}}
+define i32 @load_test11(i32* %p) {
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 10
+  %t = load i32, i32* %arrayidx, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test11_noinbounds:
+; CHECK-NEXT: param     i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 40{{$}}
+; CHECK-NEXT: i32.add   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.load  $push2=, 0($pop1){{$}}
+; CHECK-NEXT: return    $pop2{{$}}
+define i32 @load_test11_noinbounds(i32* %p) {
+  %arrayidx = getelementptr i32, i32* %p, i32 10
+  %t = load i32, i32* %arrayidx, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test12:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}
+; CHECK-NEXT: i32.const $push3=, 40{{$}}
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}
+; CHECK-NEXT: i32.load  $push5=, 0($pop4){{$}}
+; CHECK-NEXT: return    $pop5{{$}}
+define i32 @load_test12(i32* %p, i32 %n) {
+  %add = add nsw i32 %n, 10
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add
+  %t = load i32, i32* %arrayidx, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test13:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}
+; CHECK-NEXT: i32.const $push3=, 40{{$}}
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}
+; CHECK-NEXT: i32.load  $push5=, 0($pop4){{$}}
+; CHECK-NEXT: return    $pop5{{$}}
+define i32 @load_test13(i32* %p, i32 %n) {
+  %add = add nsw i32 10, %n
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add
+  %t = load i32, i32* %arrayidx, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test14:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $0, $pop1{{$}}
+; CHECK-NEXT: i32.load  $push3=, 40($pop2){{$}}
+; CHECK-NEXT: return    $pop3{{$}}
+define i32 @load_test14(i32* %p, i32 %n) {
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 %n
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10
+  %t = load i32, i32* %add.ptr1, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test15:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $0, $pop1{{$}}
+; CHECK-NEXT: i32.const $push3=, 40{{$}}
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}
+; CHECK-NEXT: i32.load  $push5=, 0($pop4){{$}}
+; CHECK-NEXT: return    $pop5{{$}}
+define i32 @load_test15(i32* %p, i32 %n) {
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 10
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 %n
+  %t = load i32, i32* %add.ptr1, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test16:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $0, $pop1{{$}}
+; CHECK-NEXT: i32.const $push3=, 40{{$}}
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}
+; CHECK-NEXT: i32.load  $push5=, 0($pop4){{$}}
+; CHECK-NEXT: return    $pop5{{$}}
+define i32 @load_test16(i32* %p, i32 %n) {
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 10
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 %n
+  %t = load i32, i32* %add.ptr1, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test17:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}
+; CHECK-NEXT: i32.const $push3=, 40{{$}}
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}
+; CHECK-NEXT: i32.load  $push5=, 0($pop4){{$}}
+; CHECK-NEXT: return    $pop5{{$}}
+define i32 @load_test17(i32* %p, i32 %n) {
+  %add = add nsw i32 %n, 10
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 %add
+  %t = load i32, i32* %add.ptr, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test18:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $0, $pop1{{$}}
+; CHECK-NEXT: i32.load  $push3=, 40($pop2){{$}}
+; CHECK-NEXT: return    $pop3{{$}}
+define i32 @load_test18(i32* %p, i32 %n) {
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 %n
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10
+  %t = load i32, i32* %add.ptr1, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test19:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}
+; CHECK-NEXT: i32.const $push3=, 40{{$}}
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}
+; CHECK-NEXT: i32.load  $push5=, 0($pop4){{$}}
+; CHECK-NEXT: return    $pop5{{$}}
+define i32 @load_test19(i32* %p, i32 %n) {
+  %add = add nsw i32 10, %n
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 %add
+  %t = load i32, i32* %add.ptr, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test20:
+; CHECK-NEXT: param     i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, -40{{$}}
+; CHECK-NEXT: i32.add   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.load  $push2=, 0($pop1){{$}}
+; CHECK-NEXT: return    $pop2{{$}}
+define i32 @load_test20(i32* %p) {
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 -10
+  %t = load i32, i32* %arrayidx, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: load_test21:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: result    i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}
+; CHECK-NEXT: i32.const $push3=, -40{{$}}
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}
+; CHECK-NEXT: i32.load  $push5=, 0($pop4){{$}}
+; CHECK-NEXT: return    $pop5{{$}}
+define i32 @load_test21(i32* %p, i32 %n) {
+  %add = add nsw i32 %n, -10
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add
+  %t = load i32, i32* %arrayidx, align 4
+  ret i32 %t
+}
+
+; CHECK-LABEL: store_test0:
+; CHECK-NEXT: param     i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 0{{$}}
+; CHECK-NEXT: i32.store $discard=, g+40($pop0), $0{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test0(i32 %i) {
+  store i32 %i, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test0_noinbounds:
+; CHECK-NEXT: param     i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 0{{$}}
+; CHECK-NEXT: i32.store $discard=, g+40($pop0), $0{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test0_noinbounds(i32 %i) {
+  store i32 %i, i32* getelementptr ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test1:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.store $discard=, g+40($pop1), $1{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test1(i32 %n, i32 %i) {
+  %add = add nsw i32 %n, 10
+  %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
+  store i32 %i, i32* %arrayidx, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test2:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.store $discard=, g+40($pop1), $1{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test2(i32 %n, i32 %i) {
+  %add = add nsw i32 10, %n
+  %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
+  store i32 %i, i32* %arrayidx, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test3:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.store $discard=, g+40($pop1), $1{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test3(i32 %n, i32 %i) {
+  %add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %n
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10
+  store i32 %i, i32* %add.ptr1, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test4:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.store $discard=, g+40($pop1), $1{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test4(i32 %n, i32 %i) {
+  %add.ptr = getelementptr inbounds i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), i32 %n
+  store i32 %i, i32* %add.ptr, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test5:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.store $discard=, g+40($pop1), $1{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test5(i32 %n, i32 %i) {
+  %add.ptr = getelementptr inbounds i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), i32 %n
+  store i32 %i, i32* %add.ptr, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test6:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.store $discard=, g+40($pop1), $1{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test6(i32 %n, i32 %i) {
+  %add = add nsw i32 %n, 10
+  %add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
+  store i32 %i, i32* %add.ptr, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test7:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.store $discard=, g+40($pop1), $1{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test7(i32 %n, i32 %i) {
+  %add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %n
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10
+  store i32 %i, i32* %add.ptr1, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test8:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.store $discard=, g+40($pop1), $1{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test8(i32 %n, i32 %i) {
+  %add = add nsw i32 10, %n
+  %add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
+  store i32 %i, i32* %add.ptr, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test9:
+; CHECK-NEXT: param     i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 0{{$}}
+; CHECK-NEXT: i32.store $discard=, g-40($pop0), $0{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test9(i32 %i) {
+  store i32 %i, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 1073741814), align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test10:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.const $push2=, g-40{{$}}
+; CHECK-NEXT: i32.add   $push3=, $pop1, $pop2{{$}}
+; CHECK-NEXT: i32.store $discard=, 0($pop3), $1{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test10(i32 %n, i32 %i) {
+  %add = add nsw i32 %n, -10
+  %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
+  store i32 %i, i32* %arrayidx, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test11:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: i32.store $discard=, 40($0), $1{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test11(i32* %p, i32 %i) {
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 10
+  store i32 %i, i32* %arrayidx, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test11_noinbounds:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 40{{$}}
+; CHECK-NEXT: i32.add   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.store $discard=, 0($pop1), $1{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test11_noinbounds(i32* %p, i32 %i) {
+  %arrayidx = getelementptr i32, i32* %p, i32 10
+  store i32 %i, i32* %arrayidx, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test12:
+; CHECK-NEXT: param     i32, i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}
+; CHECK-NEXT: i32.const $push3=, 40{{$}}
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}
+; CHECK-NEXT: i32.store $discard=, 0($pop4), $2{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test12(i32* %p, i32 %n, i32 %i) {
+  %add = add nsw i32 %n, 10
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add
+  store i32 %i, i32* %arrayidx, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test13:
+; CHECK-NEXT: param     i32, i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}
+; CHECK-NEXT: i32.const $push3=, 40{{$}}
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}
+; CHECK-NEXT: i32.store $discard=, 0($pop4), $2{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test13(i32* %p, i32 %n, i32 %i) {
+  %add = add nsw i32 10, %n
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add
+  store i32 %i, i32* %arrayidx, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test14:
+; CHECK-NEXT: param     i32, i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $0, $pop1{{$}}
+; CHECK-NEXT: i32.store $discard=, 40($pop2), $2{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test14(i32* %p, i32 %n, i32 %i) {
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 %n
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10
+  store i32 %i, i32* %add.ptr1, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test15:
+; CHECK-NEXT: param     i32, i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $0, $pop1{{$}}
+; CHECK-NEXT: i32.const $push3=, 40{{$}}
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}
+; CHECK-NEXT: i32.store $discard=, 0($pop4), $2{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test15(i32* %p, i32 %n, i32 %i) {
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 10
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 %n
+  store i32 %i, i32* %add.ptr1, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test16:
+; CHECK-NEXT: param     i32, i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $0, $pop1{{$}}
+; CHECK-NEXT: i32.const $push3=, 40{{$}}
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}
+; CHECK-NEXT: i32.store $discard=, 0($pop4), $2{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test16(i32* %p, i32 %n, i32 %i) {
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 10
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 %n
+  store i32 %i, i32* %add.ptr1, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test17:
+; CHECK-NEXT: param     i32, i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}
+; CHECK-NEXT: i32.const $push3=, 40{{$}}
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}
+; CHECK-NEXT: i32.store $discard=, 0($pop4), $2{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test17(i32* %p, i32 %n, i32 %i) {
+  %add = add nsw i32 %n, 10
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 %add
+  store i32 %i, i32* %add.ptr, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test18:
+; CHECK-NEXT: param     i32, i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $0, $pop1{{$}}
+; CHECK-NEXT: i32.store $discard=, 40($pop2), $2{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test18(i32* %p, i32 %n, i32 %i) {
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 %n
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10
+  store i32 %i, i32* %add.ptr1, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test19:
+; CHECK-NEXT: param     i32, i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}
+; CHECK-NEXT: i32.const $push3=, 40{{$}}
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}
+; CHECK-NEXT: i32.store $discard=, 0($pop4), $2{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test19(i32* %p, i32 %n, i32 %i) {
+  %add = add nsw i32 10, %n
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 %add
+  store i32 %i, i32* %add.ptr, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test20:
+; CHECK-NEXT: param     i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, -40{{$}}
+; CHECK-NEXT: i32.add   $push1=, $0, $pop0{{$}}
+; CHECK-NEXT: i32.store $discard=, 0($pop1), $1{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test20(i32* %p, i32 %i) {
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 -10
+  store i32 %i, i32* %arrayidx, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_test21:
+; CHECK-NEXT: param     i32, i32, i32{{$}}
+; CHECK-NEXT: i32.const $push0=, 2{{$}}
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}
+; CHECK-NEXT: i32.const $push3=, -40{{$}}
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}
+; CHECK-NEXT: i32.store $discard=, 0($pop4), $2{{$}}
+; CHECK-NEXT: return{{$}}
+define void @store_test21(i32* %p, i32 %n, i32 %i) {
+  %add = add nsw i32 %n, -10
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add
+  store i32 %i, i32* %arrayidx, align 4
+  ret void
+}

Modified: llvm/trunk/test/CodeGen/X86/lea-opt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/lea-opt.ll?rev=258296&r1=258295&r2=258296&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/lea-opt.ll (original)
+++ llvm/trunk/test/CodeGen/X86/lea-opt.ll Wed Jan 20 01:03:08 2016
@@ -34,12 +34,12 @@ sw.bb.2:
 sw.epilog:                                        ; preds = %sw.bb.2, %sw.bb.1, %entry
   ret void
 ; CHECK-LABEL: test1:
-; CHECK:	leaq (%rdi,%rdi,2), [[REG1:%[a-z]+]]
-; CHECK:	movl arr1(,[[REG1]],4), {{.*}}
-; CHECK:	leaq arr1+4(,[[REG1]],4), [[REG2:%[a-z]+]]
-; CHECK:	subl arr1+4(,[[REG1]],4), {{.*}}
-; CHECK:	leaq arr1+8(,[[REG1]],4), [[REG3:%[a-z]+]]
-; CHECK:	addl arr1+8(,[[REG1]],4), {{.*}}
+; CHECK:	shlq $2, [[REG1:%[a-z]+]]
+; CHECK:	movl arr1([[REG1]],[[REG1]],2), {{.*}}
+; CHECK:	leaq arr1+4([[REG1]],[[REG1]],2), [[REG2:%[a-z]+]]
+; CHECK:	subl arr1+4([[REG1]],[[REG1]],2), {{.*}}
+; CHECK:	leaq arr1+8([[REG1]],[[REG1]],2), [[REG3:%[a-z]+]]
+; CHECK:	addl arr1+8([[REG1]],[[REG1]],2), {{.*}}
 ; CHECK:	movl ${{[1-4]+}}, ([[REG2]])
 ; CHECK:	movl ${{[1-4]+}}, ([[REG3]])
 ; CHECK:	movl ${{[1-4]+}}, ([[REG2]])
@@ -74,11 +74,11 @@ sw.bb.2:
 sw.epilog:                                        ; preds = %sw.bb.2, %sw.bb.1, %entry
   ret void
 ; CHECK-LABEL: test2:
-; CHECK:	leaq (%rdi,%rdi,2), [[REG1:%[a-z]+]]
-; CHECK:	leaq arr1+4(,[[REG1]],4), [[REG2:%[a-z]+]]
+; CHECK:	shlq $2, [[REG1:%[a-z]+]]
+; CHECK:	leaq arr1+4([[REG1]],[[REG1]],2), [[REG2:%[a-z]+]]
 ; CHECK:	movl -4([[REG2]]), {{.*}}
 ; CHECK:	subl ([[REG2]]), {{.*}}
-; CHECK:	leaq arr1+8(,[[REG1]],4), [[REG3:%[a-z]+]]
+; CHECK:	leaq arr1+8([[REG1]],[[REG1]],2), [[REG3:%[a-z]+]]
 ; CHECK:	addl ([[REG3]]), {{.*}}
 ; CHECK:	movl ${{[1-4]+}}, ([[REG2]])
 ; CHECK:	movl ${{[1-4]+}}, ([[REG3]])

Modified: llvm/trunk/test/CodeGen/XCore/threads.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/XCore/threads.ll?rev=258296&r1=258295&r2=258296&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/XCore/threads.ll (original)
+++ llvm/trunk/test/CodeGen/XCore/threads.ll Wed Jan 20 01:03:08 2016
@@ -87,7 +87,7 @@ define i32* @f_tle() {
 ; CHECK: shl [[R0:r[0-9]]], r11, 3
 ; CHECK: ldaw [[R1:r[0-9]]], dp[tle]
 ; r0 = &tl + id*8
-; CHECK: add r0, [[R1]], [[R0]]
+; CHECK: add r0, [[R0]], [[R1]]
   ret i32* getelementptr inbounds ([2 x i32], [2 x i32]* @tle, i32 0, i32 0)
 }
 
@@ -96,7 +96,7 @@ define i32 @f_tlExpr () {
 ; CHECK: get r11, id
 ; CHECK: shl [[R0:r[0-9]]], r11, 3
 ; CHECK: ldaw [[R1:r[0-9]]], dp[tle]
-; CHECK: add [[R2:r[0-9]]], [[R1]], [[R0]]
+; CHECK: add [[R2:r[0-9]]], [[R0]], [[R1]]
 ; CHECK: add r0, [[R2]], [[R2]]
   ret i32 add(
       i32 ptrtoint( i32* getelementptr inbounds ([2 x i32], [2 x i32]* @tle, i32 0, i32 0) to i32),




More information about the llvm-commits mailing list