<div dir="ltr">This change broke the following small program on Windows:<div><br></div><div><div>#include <string></div><div>#include <iostream></div><div>static const char kData[] = "asdf jkl;";</div><div>int main() {</div><div>  std::string s(kData + 3, sizeof(kData) - 3);</div><div>  std::cout << s << '\n';</div><div>}</div></div><div><br></div><div>It should print "f jkl;", but with this patch (including the fix in r258366), it prints "asdf jkl;". Essentially, the +3 offset from kData got folded away without actually accounting for it.</div><div><br></div><div>I'll get a better reduction soon, but I want to revert for now since this is close to end of day pacific time.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Jan 19, 2016 at 11:03 PM, Dan Gohman via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: djg<br>
Date: Wed Jan 20 01:03:08 2016<br>
New Revision: 258296<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=258296&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=258296&view=rev</a><br>
Log:<br>
[SelectionDAG] Fold more offsets into GlobalAddresses<br>
<br>
SelectionDAG previously missed opportunities to fold constants into<br>
GlobalAddresses in several areas. For example, given `(add (add GA, c1), y)`, it<br>
would often reassociate to `(add (add GA, y), c1)`, missing the opportunity to<br>
create `(add GA+c, y)`. This isn't often visible on targets such as X86 which<br>
effectively reassociate adds in their complex address-mode folding logic,<br>
however it is currently visible on WebAssembly since it currently has very<br>
simple address mode folding code that doesn't reassociate anything.<br>
<br>
This patch fixes this by making SelectionDAG fold offsets into GlobalAddresses<br>
at the same times that it folds constants together, so that it doesn't miss any<br>
opportunities to perform such folding.<br>
<br>
Differential Revision: <a href="http://reviews.llvm.org/D16090" rel="noreferrer" target="_blank">http://reviews.llvm.org/D16090</a><br>
<br>
Added:<br>
    llvm/trunk/test/CodeGen/WebAssembly/address-offsets.ll<br>
Modified:<br>
    llvm/trunk/include/llvm/CodeGen/SelectionDAG.h<br>
    llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp<br>
    llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp<br>
    llvm/trunk/test/CodeGen/X86/lea-opt.ll<br>
    llvm/trunk/test/CodeGen/XCore/threads.ll<br>
<br>
Modified: llvm/trunk/include/llvm/CodeGen/SelectionDAG.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/SelectionDAG.h?rev=258296&r1=258295&r2=258296&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/SelectionDAG.h?rev=258296&r1=258295&r2=258296&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/CodeGen/SelectionDAG.h (original)<br>
+++ llvm/trunk/include/llvm/CodeGen/SelectionDAG.h Wed Jan 20 01:03:08 2016<br>
@@ -1156,6 +1156,10 @@ public:<br>
   /// either of the specified value types.<br>
   SDValue CreateStackTemporary(EVT VT1, EVT VT2);<br>
<br>
+  SDValue FoldSymbolOffset(unsigned Opcode, EVT VT,<br>
+                           const GlobalAddressSDNode *GA,<br>
+                           const SDNode *N2);<br>
+<br>
   SDValue FoldConstantArithmetic(unsigned Opcode, SDLoc DL, EVT VT,<br>
                                  SDNode *Cst1, SDNode *Cst2);<br>
<br>
@@ -1267,6 +1271,9 @@ public:<br>
<br>
   unsigned getEVTAlignment(EVT MemoryVT) const;<br>
<br>
+  /// Test whether the given value is a constant int or similar node.<br>
+  SDNode *isConstantIntBuildVectorOrConstantInt(SDValue N);<br>
+<br>
 private:<br>
   void InsertNode(SDNode *N);<br>
   bool RemoveNodeFromCSEMaps(SDNode *N);<br>
<br>
Modified: llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp?rev=258296&r1=258295&r2=258296&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp?rev=258296&r1=258295&r2=258296&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp (original)<br>
+++ llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp Wed Jan 20 01:03:08 2016<br>
@@ -390,6 +390,9 @@ namespace {<br>
     /// consecutive chains.<br>
     bool findBetterNeighborChains(StoreSDNode *St);<br>
<br>
+    /// Match "(X shl/srl V1) & V2" where V2 may not be present.<br>
+    bool MatchRotateHalf(SDValue Op, SDValue &Shift, SDValue &Mask);<br>
+<br>
     /// Holds a pointer to an LSBaseSDNode as well as information on where it<br>
     /// is located in a sequence of memory operations connected by a chain.<br>
     struct MemOpLink {<br>
@@ -763,16 +766,6 @@ static bool isConstantSplatVector(SDNode<br>
           EltVT.getSizeInBits() >= SplatBitSize);<br>
 }<br>
<br>
-// \brief Returns the SDNode if it is a constant integer BuildVector<br>
-// or constant integer.<br>
-static SDNode *isConstantIntBuildVectorOrConstantInt(SDValue N) {<br>
-  if (isa<ConstantSDNode>(N))<br>
-    return N.getNode();<br>
-  if (ISD::isBuildVectorOfConstantSDNodes(N.getNode()))<br>
-    return N.getNode();<br>
-  return nullptr;<br>
-}<br>
-<br>
 // \brief Returns the SDNode if it is a constant float BuildVector<br>
 // or constant float.<br>
 static SDNode *isConstantFPBuildVectorOrConstantFP(SDValue N) {<br>
@@ -825,8 +818,8 @@ SDValue DAGCombiner::ReassociateOps(unsi<br>
                                     SDValue N0, SDValue N1) {<br>
   EVT VT = N0.getValueType();<br>
   if (N0.getOpcode() == Opc) {<br>
-    if (SDNode *L = isConstantIntBuildVectorOrConstantInt(N0.getOperand(1))) {<br>
-      if (SDNode *R = isConstantIntBuildVectorOrConstantInt(N1)) {<br>
+    if (SDNode *L = DAG.isConstantIntBuildVectorOrConstantInt(N0.getOperand(1))) {<br>
+      if (SDNode *R = DAG.isConstantIntBuildVectorOrConstantInt(N1)) {<br>
         // reassoc. (op (op x, c1), c2) -> (op x, (op c1, c2))<br>
         if (SDValue OpNode = DAG.FoldConstantArithmetic(Opc, DL, VT, L, R))<br>
           return DAG.getNode(Opc, DL, VT, N0.getOperand(0), OpNode);<br>
@@ -845,8 +838,8 @@ SDValue DAGCombiner::ReassociateOps(unsi<br>
   }<br>
<br>
   if (N1.getOpcode() == Opc) {<br>
-    if (SDNode *R = isConstantIntBuildVectorOrConstantInt(N1.getOperand(1))) {<br>
-      if (SDNode *L = isConstantIntBuildVectorOrConstantInt(N0)) {<br>
+    if (SDNode *R = DAG.isConstantIntBuildVectorOrConstantInt(N1.getOperand(1))) {<br>
+      if (SDNode *L = DAG.isConstantIntBuildVectorOrConstantInt(N0)) {<br>
         // reassoc. (op c2, (op x, c1)) -> (op x, (op c1, c2))<br>
         if (SDValue OpNode = DAG.FoldConstantArithmetic(Opc, DL, VT, R, L))<br>
           return DAG.getNode(Opc, DL, VT, N1.getOperand(0), OpNode);<br>
@@ -1657,34 +1650,28 @@ SDValue DAGCombiner::visitADD(SDNode *N)<br>
     return N0;<br>
   if (N1.getOpcode() == ISD::UNDEF)<br>
     return N1;<br>
-  // fold (add c1, c2) -> c1+c2<br>
-  ConstantSDNode *N0C = getAsNonOpaqueConstant(N0);<br>
-  ConstantSDNode *N1C = getAsNonOpaqueConstant(N1);<br>
-  if (N0C && N1C)<br>
-    return DAG.FoldConstantArithmetic(ISD::ADD, SDLoc(N), VT, N0C, N1C);<br>
-  // canonicalize constant to RHS<br>
-  if (isConstantIntBuildVectorOrConstantInt(N0) &&<br>
-     !isConstantIntBuildVectorOrConstantInt(N1))<br>
-    return DAG.getNode(ISD::ADD, SDLoc(N), VT, N1, N0);<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0)) {<br>
+    // canonicalize constant to RHS<br>
+    if (!DAG.isConstantIntBuildVectorOrConstantInt(N1))<br>
+      return DAG.getNode(ISD::ADD, SDLoc(N), VT, N1, N0);<br>
+    // fold (add c1, c2) -> c1+c2<br>
+    return DAG.FoldConstantArithmetic(ISD::ADD, SDLoc(N), VT,<br>
+                                      N0.getNode(), N1.getNode());<br>
+  }<br>
   // fold (add x, 0) -> x<br>
   if (isNullConstant(N1))<br>
     return N0;<br>
-  // fold (add Sym, c) -> Sym+c<br>
-  if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(N0))<br>
-    if (!LegalOperations && TLI.isOffsetFoldingLegal(GA) && N1C &&<br>
-        GA->getOpcode() == ISD::GlobalAddress)<br>
-      return DAG.getGlobalAddress(GA->getGlobal(), SDLoc(N1C), VT,<br>
-                                  GA->getOffset() +<br>
-                                    (uint64_t)N1C->getSExtValue());<br>
   // fold ((c1-A)+c2) -> (c1+c2)-A<br>
-  if (N1C && N0.getOpcode() == ISD::SUB)<br>
-    if (ConstantSDNode *N0C = getAsNonOpaqueConstant(N0.getOperand(0))) {<br>
-      SDLoc DL(N);<br>
-      return DAG.getNode(ISD::SUB, DL, VT,<br>
-                         DAG.getConstant(N1C->getAPIntValue()+<br>
-                                         N0C->getAPIntValue(), DL, VT),<br>
-                         N0.getOperand(1));<br>
-    }<br>
+  if (ConstantSDNode *N1C = getAsNonOpaqueConstant(N1)) {<br>
+    if (N0.getOpcode() == ISD::SUB)<br>
+      if (ConstantSDNode *N0C = getAsNonOpaqueConstant(N0.getOperand(0))) {<br>
+        SDLoc DL(N);<br>
+        return DAG.getNode(ISD::SUB, DL, VT,<br>
+                           DAG.getConstant(N1C->getAPIntValue()+<br>
+                                           N0C->getAPIntValue(), DL, VT),<br>
+                           N0.getOperand(1));<br>
+      }<br>
+  }<br>
   // reassociate add<br>
   if (SDValue RADD = ReassociateOps(ISD::ADD, SDLoc(N), N0, N1))<br>
     return RADD;<br>
@@ -1879,11 +1866,14 @@ SDValue DAGCombiner::visitSUB(SDNode *N)<br>
   // FIXME: Refactor this and xor and other similar operations together.<br>
   if (N0 == N1)<br>
     return tryFoldToZero(SDLoc(N), TLI, VT, DAG, LegalOperations, LegalTypes);<br>
-  // fold (sub c1, c2) -> c1-c2<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&<br>
+      DAG.isConstantIntBuildVectorOrConstantInt(N1)) {<br>
+    // fold (sub c1, c2) -> c1-c2<br>
+    return DAG.FoldConstantArithmetic(ISD::SUB, SDLoc(N), VT,<br>
+                                      N0.getNode(), N1.getNode());<br>
+  }<br>
   ConstantSDNode *N0C = getAsNonOpaqueConstant(N0);<br>
   ConstantSDNode *N1C = getAsNonOpaqueConstant(N1);<br>
-  if (N0C && N1C)<br>
-    return DAG.FoldConstantArithmetic(ISD::SUB, SDLoc(N), VT, N0C, N1C);<br>
   // fold (sub x, c) -> (add x, -c)<br>
   if (N1C) {<br>
     SDLoc DL(N);<br>
@@ -2047,8 +2037,8 @@ SDValue DAGCombiner::visitMUL(SDNode *N)<br>
                                       N0.getNode(), N1.getNode());<br>
<br>
   // canonicalize constant to RHS (vector doesn't have to splat)<br>
-  if (isConstantIntBuildVectorOrConstantInt(N0) &&<br>
-     !isConstantIntBuildVectorOrConstantInt(N1))<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&<br>
+     !DAG.isConstantIntBuildVectorOrConstantInt(N1))<br>
     return DAG.getNode(ISD::MUL, SDLoc(N), VT, N1, N0);<br>
   // fold (mul x, 0) -> 0<br>
   if (N1IsConst && ConstValue1 == 0)<br>
@@ -2125,9 +2115,9 @@ SDValue DAGCombiner::visitMUL(SDNode *N)<br>
   }<br>
<br>
   // fold (mul (add x, c1), c2) -> (add (mul x, c2), c1*c2)<br>
-  if (isConstantIntBuildVectorOrConstantInt(N1) &&<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N1) &&<br>
       N0.getOpcode() == ISD::ADD &&<br>
-      isConstantIntBuildVectorOrConstantInt(N0.getOperand(1)) &&<br>
+      DAG.isConstantIntBuildVectorOrConstantInt(N0.getOperand(1)) &&<br>
       isMulAddWithConstProfitable(N, N0, N1))<br>
       return DAG.getNode(ISD::ADD, SDLoc(N), VT,<br>
                          DAG.getNode(ISD::MUL, SDLoc(N0), VT,<br>
@@ -2698,8 +2688,8 @@ SDValue DAGCombiner::visitIMINMAX(SDNode<br>
     return DAG.FoldConstantArithmetic(N->getOpcode(), SDLoc(N), VT, N0C, N1C);<br>
<br>
   // canonicalize constant to RHS<br>
-  if (isConstantIntBuildVectorOrConstantInt(N0) &&<br>
-     !isConstantIntBuildVectorOrConstantInt(N1))<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&<br>
+     !DAG.isConstantIntBuildVectorOrConstantInt(N1))<br>
     return DAG.getNode(N->getOpcode(), SDLoc(N), VT, N1, N0);<br>
<br>
   return SDValue();<br>
@@ -3045,8 +3035,8 @@ SDValue DAGCombiner::visitAND(SDNode *N)<br>
   if (N0C && N1C && !N1C->isOpaque())<br>
     return DAG.FoldConstantArithmetic(ISD::AND, SDLoc(N), VT, N0C, N1C);<br>
   // canonicalize constant to RHS<br>
-  if (isConstantIntBuildVectorOrConstantInt(N0) &&<br>
-     !isConstantIntBuildVectorOrConstantInt(N1))<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&<br>
+     !DAG.isConstantIntBuildVectorOrConstantInt(N1))<br>
     return DAG.getNode(ISD::AND, SDLoc(N), VT, N1, N0);<br>
   // fold (and x, -1) -> x<br>
   if (isAllOnesConstant(N1))<br>
@@ -3760,8 +3750,8 @@ SDValue DAGCombiner::visitOR(SDNode *N)<br>
   if (N0C && N1C && !N1C->isOpaque())<br>
     return DAG.FoldConstantArithmetic(ISD::OR, SDLoc(N), VT, N0C, N1C);<br>
   // canonicalize constant to RHS<br>
-  if (isConstantIntBuildVectorOrConstantInt(N0) &&<br>
-     !isConstantIntBuildVectorOrConstantInt(N1))<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&<br>
+     !DAG.isConstantIntBuildVectorOrConstantInt(N1))<br>
     return DAG.getNode(ISD::OR, SDLoc(N), VT, N1, N0);<br>
   // fold (or x, 0) -> x<br>
   if (isNullConstant(N1))<br>
@@ -3817,9 +3807,9 @@ SDValue DAGCombiner::visitOR(SDNode *N)<br>
 }<br>
<br>
 /// Match "(X shl/srl V1) & V2" where V2 may not be present.<br>
-static bool MatchRotateHalf(SDValue Op, SDValue &Shift, SDValue &Mask) {<br>
+bool DAGCombiner::MatchRotateHalf(SDValue Op, SDValue &Shift, SDValue &Mask) {<br>
   if (Op.getOpcode() == ISD::AND) {<br>
-    if (isConstantIntBuildVectorOrConstantInt(Op.getOperand(1))) {<br>
+    if (DAG.isConstantIntBuildVectorOrConstantInt(Op.getOperand(1))) {<br>
       Mask = Op.getOperand(1);<br>
       Op = Op.getOperand(0);<br>
     } else {<br>
@@ -4106,8 +4096,8 @@ SDValue DAGCombiner::visitXOR(SDNode *N)<br>
   if (N0C && N1C)<br>
     return DAG.FoldConstantArithmetic(ISD::XOR, SDLoc(N), VT, N0C, N1C);<br>
   // canonicalize constant to RHS<br>
-  if (isConstantIntBuildVectorOrConstantInt(N0) &&<br>
-     !isConstantIntBuildVectorOrConstantInt(N1))<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&<br>
+     !DAG.isConstantIntBuildVectorOrConstantInt(N1))<br>
     return DAG.getNode(ISD::XOR, SDLoc(N), VT, N1, N0);<br>
   // fold (xor x, 0) -> x<br>
   if (isNullConstant(N1))<br>
@@ -4916,7 +4906,7 @@ SDValue DAGCombiner::visitBSWAP(SDNode *<br>
   EVT VT = N->getValueType(0);<br>
<br>
   // fold (bswap c1) -> c2<br>
-  if (isConstantIntBuildVectorOrConstantInt(N0))<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0))<br>
     return DAG.getNode(ISD::BSWAP, SDLoc(N), VT, N0);<br>
   // fold (bswap (bswap x)) -> x<br>
   if (N0.getOpcode() == ISD::BSWAP)<br>
@@ -4929,7 +4919,7 @@ SDValue DAGCombiner::visitCTLZ(SDNode *N<br>
   EVT VT = N->getValueType(0);<br>
<br>
   // fold (ctlz c1) -> c2<br>
-  if (isConstantIntBuildVectorOrConstantInt(N0))<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0))<br>
     return DAG.getNode(ISD::CTLZ, SDLoc(N), VT, N0);<br>
   return SDValue();<br>
 }<br>
@@ -4939,7 +4929,7 @@ SDValue DAGCombiner::visitCTLZ_ZERO_UNDE<br>
   EVT VT = N->getValueType(0);<br>
<br>
   // fold (ctlz_zero_undef c1) -> c2<br>
-  if (isConstantIntBuildVectorOrConstantInt(N0))<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0))<br>
     return DAG.getNode(ISD::CTLZ_ZERO_UNDEF, SDLoc(N), VT, N0);<br>
   return SDValue();<br>
 }<br>
@@ -4949,7 +4939,7 @@ SDValue DAGCombiner::visitCTTZ(SDNode *N<br>
   EVT VT = N->getValueType(0);<br>
<br>
   // fold (cttz c1) -> c2<br>
-  if (isConstantIntBuildVectorOrConstantInt(N0))<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0))<br>
     return DAG.getNode(ISD::CTTZ, SDLoc(N), VT, N0);<br>
   return SDValue();<br>
 }<br>
@@ -4959,7 +4949,7 @@ SDValue DAGCombiner::visitCTTZ_ZERO_UNDE<br>
   EVT VT = N->getValueType(0);<br>
<br>
   // fold (cttz_zero_undef c1) -> c2<br>
-  if (isConstantIntBuildVectorOrConstantInt(N0))<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0))<br>
     return DAG.getNode(ISD::CTTZ_ZERO_UNDEF, SDLoc(N), VT, N0);<br>
   return SDValue();<br>
 }<br>
@@ -4969,7 +4959,7 @@ SDValue DAGCombiner::visitCTPOP(SDNode *<br>
   EVT VT = N->getValueType(0);<br>
<br>
   // fold (ctpop c1) -> c2<br>
-  if (isConstantIntBuildVectorOrConstantInt(N0))<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0))<br>
     return DAG.getNode(ISD::CTPOP, SDLoc(N), VT, N0);<br>
   return SDValue();<br>
 }<br>
@@ -6902,7 +6892,7 @@ SDValue DAGCombiner::visitSIGN_EXTEND_IN<br>
     return DAG.getUNDEF(VT);<br>
<br>
   // fold (sext_in_reg c1) -> c1<br>
-  if (isConstantIntBuildVectorOrConstantInt(N0))<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0))<br>
     return DAG.getNode(ISD::SIGN_EXTEND_INREG, SDLoc(N), VT, N0, N1);<br>
<br>
   // If the input is already sign extended, just drop the extension.<br>
@@ -7021,7 +7011,7 @@ SDValue DAGCombiner::visitTRUNCATE(SDNod<br>
   if (N0.getValueType() == N->getValueType(0))<br>
     return N0;<br>
   // fold (truncate c1) -> c1<br>
-  if (isConstantIntBuildVectorOrConstantInt(N0))<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0))<br>
     return DAG.getNode(ISD::TRUNCATE, SDLoc(N), VT, N0);<br>
   // fold (truncate (truncate x)) -> (truncate x)<br>
   if (N0.getOpcode() == ISD::TRUNCATE)<br>
@@ -8868,7 +8858,7 @@ SDValue DAGCombiner::visitSINT_TO_FP(SDN<br>
   EVT OpVT = N0.getValueType();<br>
<br>
   // fold (sint_to_fp c1) -> c1fp<br>
-  if (isConstantIntBuildVectorOrConstantInt(N0) &&<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&<br>
       // ...but only if the target supports immediate floating-point values<br>
       (!LegalOperations ||<br>
        TLI.isOperationLegalOrCustom(llvm::ISD::ConstantFP, VT)))<br>
@@ -8922,7 +8912,7 @@ SDValue DAGCombiner::visitUINT_TO_FP(SDN<br>
   EVT OpVT = N0.getValueType();<br>
<br>
   // fold (uint_to_fp c1) -> c1fp<br>
-  if (isConstantIntBuildVectorOrConstantInt(N0) &&<br>
+  if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&<br>
       // ...but only if the target supports immediate floating-point values<br>
       (!LegalOperations ||<br>
        TLI.isOperationLegalOrCustom(llvm::ISD::ConstantFP, VT)))<br>
@@ -10940,9 +10930,23 @@ struct BaseIndexOffset {<br>
   }<br>
<br>
   /// Parses tree in Ptr for base, index, offset addresses.<br>
-  static BaseIndexOffset match(SDValue Ptr) {<br>
+  static BaseIndexOffset match(SDValue Ptr, SelectionDAG &DAG) {<br>
     bool IsIndexSignExt = false;<br>
<br>
+    // Split up a folded GlobalAddress+Offset into its component parts.<br>
+    if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Ptr))<br>
+      if (GA->getOpcode() == ISD::GlobalAddress && GA->getOffset() != 0) {<br>
+        return BaseIndexOffset(DAG.getGlobalAddress(GA->getGlobal(),<br>
+                                                    SDLoc(GA),<br>
+                                                    GA->getValueType(0),<br>
+                                                    /*Offset=*/0,<br>
+                                                    /*isTargetGA=*/false,<br>
+                                                    GA->getTargetFlags()),<br>
+                               SDValue(),<br>
+                               GA->getOffset(),<br>
+                               IsIndexSignExt);<br>
+      }<br>
+<br>
     // We only can pattern match BASE + INDEX + OFFSET. If Ptr is not an ADD<br>
     // instruction, then it could be just the BASE or everything else we don't<br>
     // know how to handle. Just use Ptr as BASE and give up.<br>
@@ -11063,7 +11067,7 @@ bool DAGCombiner::isMulAddWithConstProfi<br>
       // multiply (CONST * A) after we also do the same transformation<br>
       // to the "t2" instruction.<br>
       if (OtherOp->getOpcode() == ISD::ADD &&<br>
-          isConstantIntBuildVectorOrConstantInt(OtherOp->getOperand(1)) &&<br>
+          DAG.isConstantIntBuildVectorOrConstantInt(OtherOp->getOperand(1)) &&<br>
           OtherOp->getOperand(0).getNode() == MulVar)<br>
         return true;<br>
     }<br>
@@ -11215,7 +11219,7 @@ void DAGCombiner::getStoreMergeAndAliasC<br>
     SmallVectorImpl<LSBaseSDNode*> &AliasLoadNodes) {<br>
   // This holds the base pointer, index, and the offset in bytes from the base<br>
   // pointer.<br>
-  BaseIndexOffset BasePtr = BaseIndexOffset::match(St->getBasePtr());<br>
+  BaseIndexOffset BasePtr = BaseIndexOffset::match(St->getBasePtr(), DAG);<br>
<br>
   // We must have a base and an offset.<br>
   if (!BasePtr.Base.getNode())<br>
@@ -11253,7 +11257,7 @@ void DAGCombiner::getStoreMergeAndAliasC<br>
         if (OtherST->getMemoryVT() != MemVT)<br>
           continue;<br>
<br>
-        BaseIndexOffset Ptr = BaseIndexOffset::match(OtherST->getBasePtr());<br>
+        BaseIndexOffset Ptr = BaseIndexOffset::match(OtherST->getBasePtr(), DAG);<br>
<br>
         if (Ptr.equalBaseIndex(BasePtr))<br>
           StoreNodes.push_back(MemOpLink(OtherST, Ptr.Offset, Seq++));<br>
@@ -11269,7 +11273,7 @@ void DAGCombiner::getStoreMergeAndAliasC<br>
       break;<br>
<br>
     // Find the base pointer and offset for this memory node.<br>
-    BaseIndexOffset Ptr = BaseIndexOffset::match(Index->getBasePtr());<br>
+    BaseIndexOffset Ptr = BaseIndexOffset::match(Index->getBasePtr(), DAG);<br>
<br>
     // Check that the base pointer is the same as the original one.<br>
     if (!Ptr.equalBaseIndex(BasePtr))<br>
@@ -11557,7 +11561,7 @@ bool DAGCombiner::MergeConsecutiveStores<br>
     if (Ld->getMemoryVT() != MemVT)<br>
       break;<br>
<br>
-    BaseIndexOffset LdPtr = BaseIndexOffset::match(Ld->getBasePtr());<br>
+    BaseIndexOffset LdPtr = BaseIndexOffset::match(Ld->getBasePtr(), DAG);<br>
     // If this is not the first ptr that we check.<br>
     if (LdBasePtr.Base.getNode()) {<br>
       // The base ptr must be the same.<br>
@@ -14716,7 +14720,7 @@ SDValue DAGCombiner::FindBetterChain(SDN<br>
 bool DAGCombiner::findBetterNeighborChains(StoreSDNode* St) {<br>
   // This holds the base pointer, index, and the offset in bytes from the base<br>
   // pointer.<br>
-  BaseIndexOffset BasePtr = BaseIndexOffset::match(St->getBasePtr());<br>
+  BaseIndexOffset BasePtr = BaseIndexOffset::match(St->getBasePtr(), DAG);<br>
<br>
   // We must have a base and an offset.<br>
   if (!BasePtr.Base.getNode())<br>
@@ -14742,7 +14746,7 @@ bool DAGCombiner::findBetterNeighborChai<br>
       break;<br>
<br>
     // Find the base pointer and offset for this memory node.<br>
-    BaseIndexOffset Ptr = BaseIndexOffset::match(Index->getBasePtr());<br>
+    BaseIndexOffset Ptr = BaseIndexOffset::match(Index->getBasePtr(), DAG);<br>
<br>
     // Check that the base pointer is the same as the original one.<br>
     if (!Ptr.equalBaseIndex(BasePtr))<br>
<br>
Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp?rev=258296&r1=258295&r2=258296&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp?rev=258296&r1=258295&r2=258296&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp (original)<br>
+++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp Wed Jan 20 01:03:08 2016<br>
@@ -3263,6 +3263,26 @@ SDValue SelectionDAG::FoldConstantArithm<br>
   return getConstant(Folded.first, DL, VT);<br>
 }<br>
<br>
+SDValue SelectionDAG::FoldSymbolOffset(unsigned Opcode, EVT VT,<br>
+                                       const GlobalAddressSDNode *GA,<br>
+                                       const SDNode *N2) {<br>
+  if (GA->getOpcode() != ISD::GlobalAddress)<br>
+    return SDValue();<br>
+  if (!TLI->isOffsetFoldingLegal(GA))<br>
+    return SDValue();<br>
+  const ConstantSDNode *Cst2 = dyn_cast<ConstantSDNode>(N2);<br>
+  if (!Cst2)<br>
+    return SDValue();<br>
+  int64_t Offset = Cst2->getSExtValue();<br>
+  switch (Opcode) {<br>
+  case ISD::ADD: break;<br>
+  case ISD::SUB: Offset = -uint64_t(Offset); break;<br>
+  default: return SDValue();<br>
+  }<br>
+  return getGlobalAddress(GA->getGlobal(), SDLoc(Cst2), VT,<br>
+                          GA->getOffset() + uint64_t(Offset));<br>
+}<br>
+<br>
 SDValue SelectionDAG::FoldConstantArithmetic(unsigned Opcode, SDLoc DL, EVT VT,<br>
                                              SDNode *Cst1, SDNode *Cst2) {<br>
   // If the opcode is a target-specific ISD node, there's nothing we can<br>
@@ -3289,6 +3309,12 @@ SDValue SelectionDAG::FoldConstantArithm<br>
     }<br>
   }<br>
<br>
+  // fold (add Sym, c) -> Sym+c<br>
+  if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Cst1))<br>
+    return FoldSymbolOffset(Opcode, VT, GA, Cst2);<br>
+  if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Cst2))<br>
+    return FoldSymbolOffset(Opcode, VT, GA, Cst1);<br>
+<br>
   // For vectors extract each constant element into Inputs so we can constant<br>
   // fold them individually.<br>
   BuildVectorSDNode *BV1 = dyn_cast<BuildVectorSDNode>(Cst1);<br>
@@ -7322,6 +7348,22 @@ bool ShuffleVectorSDNode::isSplatMask(co<br>
   return true;<br>
 }<br>
<br>
+// \brief Returns the SDNode if it is a constant integer BuildVector<br>
+// or constant integer.<br>
+SDNode *SelectionDAG::isConstantIntBuildVectorOrConstantInt(SDValue N) {<br>
+  if (isa<ConstantSDNode>(N))<br>
+    return N.getNode();<br>
+  if (ISD::isBuildVectorOfConstantSDNodes(N.getNode()))<br>
+    return N.getNode();<br>
+  // Treat a GlobalAddress supporting constant offset folding as a<br>
+  // constant integer.<br>
+  if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(N))<br>
+    if (GA->getOpcode() == ISD::GlobalAddress &&<br>
+        TLI->isOffsetFoldingLegal(GA))<br>
+      return GA;<br>
+  return nullptr;<br>
+}<br>
+<br>
 #ifndef NDEBUG<br>
 static void checkForCyclesHelper(const SDNode *N,<br>
                                  SmallPtrSetImpl<const SDNode*> &Visited,<br>
<br>
Added: llvm/trunk/test/CodeGen/WebAssembly/address-offsets.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/address-offsets.ll?rev=258296&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/address-offsets.ll?rev=258296&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/CodeGen/WebAssembly/address-offsets.ll (added)<br>
+++ llvm/trunk/test/CodeGen/WebAssembly/address-offsets.ll Wed Jan 20 01:03:08 2016<br>
@@ -0,0 +1,672 @@<br>
+; RUN: llc < %s -asm-verbose=false | FileCheck %s<br>
+<br>
+; Test folding constant offsets and symbols into load and store addresses under<br>
+; a variety of circumstances.<br>
+<br>
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"<br>
+target triple = "wasm32-unknown-unknown"<br>
+<br>
+@g = external global [0 x i32], align 4<br>
+<br>
+; CHECK-LABEL: load_test0:<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 0{{$}}<br>
+; CHECK-NEXT: i32.load  $push1=, g+40($pop0){{$}}<br>
+; CHECK-NEXT: return    $pop1{{$}}<br>
+define i32 @load_test0() {<br>
+  %t = load i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test0_noinbounds:<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 0{{$}}<br>
+; CHECK-NEXT: i32.load  $push1=, g+40($pop0){{$}}<br>
+; CHECK-NEXT: return    $pop1{{$}}<br>
+define i32 @load_test0_noinbounds() {<br>
+  %t = load i32, i32* getelementptr ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test1:<br>
+; CHECK-NEXT: param     i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.load  $push2=, g+40($pop1){{$}}<br>
+; CHECK-NEXT: return    $pop2{{$}}<br>
+define i32 @load_test1(i32 %n) {<br>
+  %add = add nsw i32 %n, 10<br>
+  %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add<br>
+  %t = load i32, i32* %arrayidx, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test2:<br>
+; CHECK-NEXT: param     i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.load  $push2=, g+40($pop1){{$}}<br>
+; CHECK-NEXT: return    $pop2{{$}}<br>
+define i32 @load_test2(i32 %n) {<br>
+  %add = add nsw i32 10, %n<br>
+  %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add<br>
+  %t = load i32, i32* %arrayidx, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test3:<br>
+; CHECK-NEXT: param     i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.load  $push2=, g+40($pop1){{$}}<br>
+; CHECK-NEXT: return    $pop2{{$}}<br>
+define i32 @load_test3(i32 %n) {<br>
+  %add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %n<br>
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10<br>
+  %t = load i32, i32* %add.ptr1, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test4:<br>
+; CHECK-NEXT: param     i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.load  $push2=, g+40($pop1){{$}}<br>
+; CHECK-NEXT: return    $pop2{{$}}<br>
+define i32 @load_test4(i32 %n) {<br>
+  %add.ptr = getelementptr inbounds i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), i32 %n<br>
+  %t = load i32, i32* %add.ptr, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test5:<br>
+; CHECK-NEXT: param     i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.load  $push2=, g+40($pop1){{$}}<br>
+; CHECK-NEXT: return    $pop2{{$}}<br>
+define i32 @load_test5(i32 %n) {<br>
+  %add.ptr = getelementptr inbounds i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), i32 %n<br>
+  %t = load i32, i32* %add.ptr, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test6:<br>
+; CHECK-NEXT: param     i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.load  $push2=, g+40($pop1){{$}}<br>
+; CHECK-NEXT: return    $pop2{{$}}<br>
+define i32 @load_test6(i32 %n) {<br>
+  %add = add nsw i32 %n, 10<br>
+  %add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add<br>
+  %t = load i32, i32* %add.ptr, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test7:<br>
+; CHECK-NEXT: param     i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.load  $push2=, g+40($pop1){{$}}<br>
+; CHECK-NEXT: return    $pop2{{$}}<br>
+define i32 @load_test7(i32 %n) {<br>
+  %add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %n<br>
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10<br>
+  %t = load i32, i32* %add.ptr1, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test8:<br>
+; CHECK-NEXT: param     i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.load  $push2=, g+40($pop1){{$}}<br>
+; CHECK-NEXT: return    $pop2{{$}}<br>
+define i32 @load_test8(i32 %n) {<br>
+  %add = add nsw i32 10, %n<br>
+  %add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add<br>
+  %t = load i32, i32* %add.ptr, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test9:<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 0{{$}}<br>
+; CHECK-NEXT: i32.load  $push1=, g-40($pop0){{$}}<br>
+; CHECK-NEXT: return    $pop1{{$}}<br>
+define i32 @load_test9() {<br>
+  %t = load i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 1073741814), align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test10:<br>
+; CHECK-NEXT: param     i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.const $push2=, g-40{{$}}<br>
+; CHECK-NEXT: i32.add   $push3=, $pop1, $pop2{{$}}<br>
+; CHECK-NEXT: i32.load  $push4=, 0($pop3){{$}}<br>
+; CHECK-NEXT: return    $pop4{{$}}<br>
+define i32 @load_test10(i32 %n) {<br>
+  %add = add nsw i32 %n, -10<br>
+  %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add<br>
+  %t = load i32, i32* %arrayidx, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test11:<br>
+; CHECK-NEXT: param     i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.load  $push0=, 40($0){{$}}<br>
+; CHECK-NEXT: return    $pop0{{$}}<br>
+define i32 @load_test11(i32* %p) {<br>
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 10<br>
+  %t = load i32, i32* %arrayidx, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test11_noinbounds:<br>
+; CHECK-NEXT: param     i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 40{{$}}<br>
+; CHECK-NEXT: i32.add   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.load  $push2=, 0($pop1){{$}}<br>
+; CHECK-NEXT: return    $pop2{{$}}<br>
+define i32 @load_test11_noinbounds(i32* %p) {<br>
+  %arrayidx = getelementptr i32, i32* %p, i32 10<br>
+  %t = load i32, i32* %arrayidx, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test12:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}<br>
+; CHECK-NEXT: i32.const $push3=, 40{{$}}<br>
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}<br>
+; CHECK-NEXT: i32.load  $push5=, 0($pop4){{$}}<br>
+; CHECK-NEXT: return    $pop5{{$}}<br>
+define i32 @load_test12(i32* %p, i32 %n) {<br>
+  %add = add nsw i32 %n, 10<br>
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add<br>
+  %t = load i32, i32* %arrayidx, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test13:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}<br>
+; CHECK-NEXT: i32.const $push3=, 40{{$}}<br>
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}<br>
+; CHECK-NEXT: i32.load  $push5=, 0($pop4){{$}}<br>
+; CHECK-NEXT: return    $pop5{{$}}<br>
+define i32 @load_test13(i32* %p, i32 %n) {<br>
+  %add = add nsw i32 10, %n<br>
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add<br>
+  %t = load i32, i32* %arrayidx, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test14:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $0, $pop1{{$}}<br>
+; CHECK-NEXT: i32.load  $push3=, 40($pop2){{$}}<br>
+; CHECK-NEXT: return    $pop3{{$}}<br>
+define i32 @load_test14(i32* %p, i32 %n) {<br>
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 %n<br>
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10<br>
+  %t = load i32, i32* %add.ptr1, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test15:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $0, $pop1{{$}}<br>
+; CHECK-NEXT: i32.const $push3=, 40{{$}}<br>
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}<br>
+; CHECK-NEXT: i32.load  $push5=, 0($pop4){{$}}<br>
+; CHECK-NEXT: return    $pop5{{$}}<br>
+define i32 @load_test15(i32* %p, i32 %n) {<br>
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 10<br>
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 %n<br>
+  %t = load i32, i32* %add.ptr1, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test16:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $0, $pop1{{$}}<br>
+; CHECK-NEXT: i32.const $push3=, 40{{$}}<br>
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}<br>
+; CHECK-NEXT: i32.load  $push5=, 0($pop4){{$}}<br>
+; CHECK-NEXT: return    $pop5{{$}}<br>
+define i32 @load_test16(i32* %p, i32 %n) {<br>
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 10<br>
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 %n<br>
+  %t = load i32, i32* %add.ptr1, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test17:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}<br>
+; CHECK-NEXT: i32.const $push3=, 40{{$}}<br>
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}<br>
+; CHECK-NEXT: i32.load  $push5=, 0($pop4){{$}}<br>
+; CHECK-NEXT: return    $pop5{{$}}<br>
+define i32 @load_test17(i32* %p, i32 %n) {<br>
+  %add = add nsw i32 %n, 10<br>
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 %add<br>
+  %t = load i32, i32* %add.ptr, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test18:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $0, $pop1{{$}}<br>
+; CHECK-NEXT: i32.load  $push3=, 40($pop2){{$}}<br>
+; CHECK-NEXT: return    $pop3{{$}}<br>
+define i32 @load_test18(i32* %p, i32 %n) {<br>
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 %n<br>
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10<br>
+  %t = load i32, i32* %add.ptr1, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test19:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}<br>
+; CHECK-NEXT: i32.const $push3=, 40{{$}}<br>
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}<br>
+; CHECK-NEXT: i32.load  $push5=, 0($pop4){{$}}<br>
+; CHECK-NEXT: return    $pop5{{$}}<br>
+define i32 @load_test19(i32* %p, i32 %n) {<br>
+  %add = add nsw i32 10, %n<br>
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 %add<br>
+  %t = load i32, i32* %add.ptr, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test20:<br>
+; CHECK-NEXT: param     i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, -40{{$}}<br>
+; CHECK-NEXT: i32.add   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.load  $push2=, 0($pop1){{$}}<br>
+; CHECK-NEXT: return    $pop2{{$}}<br>
+define i32 @load_test20(i32* %p) {<br>
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 -10<br>
+  %t = load i32, i32* %arrayidx, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: load_test21:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: result    i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}<br>
+; CHECK-NEXT: i32.const $push3=, -40{{$}}<br>
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}<br>
+; CHECK-NEXT: i32.load  $push5=, 0($pop4){{$}}<br>
+; CHECK-NEXT: return    $pop5{{$}}<br>
+define i32 @load_test21(i32* %p, i32 %n) {<br>
+  %add = add nsw i32 %n, -10<br>
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add<br>
+  %t = load i32, i32* %arrayidx, align 4<br>
+  ret i32 %t<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test0:<br>
+; CHECK-NEXT: param     i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 0{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, g+40($pop0), $0{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test0(i32 %i) {<br>
+  store i32 %i, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test0_noinbounds:<br>
+; CHECK-NEXT: param     i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 0{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, g+40($pop0), $0{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test0_noinbounds(i32 %i) {<br>
+  store i32 %i, i32* getelementptr ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test1:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, g+40($pop1), $1{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test1(i32 %n, i32 %i) {<br>
+  %add = add nsw i32 %n, 10<br>
+  %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add<br>
+  store i32 %i, i32* %arrayidx, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test2:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, g+40($pop1), $1{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test2(i32 %n, i32 %i) {<br>
+  %add = add nsw i32 10, %n<br>
+  %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add<br>
+  store i32 %i, i32* %arrayidx, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test3:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, g+40($pop1), $1{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test3(i32 %n, i32 %i) {<br>
+  %add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %n<br>
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10<br>
+  store i32 %i, i32* %add.ptr1, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test4:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, g+40($pop1), $1{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test4(i32 %n, i32 %i) {<br>
+  %add.ptr = getelementptr inbounds i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), i32 %n<br>
+  store i32 %i, i32* %add.ptr, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test5:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, g+40($pop1), $1{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test5(i32 %n, i32 %i) {<br>
+  %add.ptr = getelementptr inbounds i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), i32 %n<br>
+  store i32 %i, i32* %add.ptr, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test6:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, g+40($pop1), $1{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test6(i32 %n, i32 %i) {<br>
+  %add = add nsw i32 %n, 10<br>
+  %add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add<br>
+  store i32 %i, i32* %add.ptr, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test7:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, g+40($pop1), $1{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test7(i32 %n, i32 %i) {<br>
+  %add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %n<br>
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10<br>
+  store i32 %i, i32* %add.ptr1, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test8:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, g+40($pop1), $1{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test8(i32 %n, i32 %i) {<br>
+  %add = add nsw i32 10, %n<br>
+  %add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add<br>
+  store i32 %i, i32* %add.ptr, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test9:<br>
+; CHECK-NEXT: param     i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 0{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, g-40($pop0), $0{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test9(i32 %i) {<br>
+  store i32 %i, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 1073741814), align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test10:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.const $push2=, g-40{{$}}<br>
+; CHECK-NEXT: i32.add   $push3=, $pop1, $pop2{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, 0($pop3), $1{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test10(i32 %n, i32 %i) {<br>
+  %add = add nsw i32 %n, -10<br>
+  %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add<br>
+  store i32 %i, i32* %arrayidx, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test11:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, 40($0), $1{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test11(i32* %p, i32 %i) {<br>
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 10<br>
+  store i32 %i, i32* %arrayidx, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test11_noinbounds:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 40{{$}}<br>
+; CHECK-NEXT: i32.add   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, 0($pop1), $1{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test11_noinbounds(i32* %p, i32 %i) {<br>
+  %arrayidx = getelementptr i32, i32* %p, i32 10<br>
+  store i32 %i, i32* %arrayidx, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test12:<br>
+; CHECK-NEXT: param     i32, i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}<br>
+; CHECK-NEXT: i32.const $push3=, 40{{$}}<br>
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, 0($pop4), $2{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test12(i32* %p, i32 %n, i32 %i) {<br>
+  %add = add nsw i32 %n, 10<br>
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add<br>
+  store i32 %i, i32* %arrayidx, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test13:<br>
+; CHECK-NEXT: param     i32, i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}<br>
+; CHECK-NEXT: i32.const $push3=, 40{{$}}<br>
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, 0($pop4), $2{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test13(i32* %p, i32 %n, i32 %i) {<br>
+  %add = add nsw i32 10, %n<br>
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add<br>
+  store i32 %i, i32* %arrayidx, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test14:<br>
+; CHECK-NEXT: param     i32, i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $0, $pop1{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, 40($pop2), $2{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test14(i32* %p, i32 %n, i32 %i) {<br>
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 %n<br>
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10<br>
+  store i32 %i, i32* %add.ptr1, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test15:<br>
+; CHECK-NEXT: param     i32, i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $0, $pop1{{$}}<br>
+; CHECK-NEXT: i32.const $push3=, 40{{$}}<br>
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, 0($pop4), $2{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test15(i32* %p, i32 %n, i32 %i) {<br>
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 10<br>
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 %n<br>
+  store i32 %i, i32* %add.ptr1, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test16:<br>
+; CHECK-NEXT: param     i32, i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $0, $pop1{{$}}<br>
+; CHECK-NEXT: i32.const $push3=, 40{{$}}<br>
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, 0($pop4), $2{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test16(i32* %p, i32 %n, i32 %i) {<br>
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 10<br>
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 %n<br>
+  store i32 %i, i32* %add.ptr1, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test17:<br>
+; CHECK-NEXT: param     i32, i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}<br>
+; CHECK-NEXT: i32.const $push3=, 40{{$}}<br>
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, 0($pop4), $2{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test17(i32* %p, i32 %n, i32 %i) {<br>
+  %add = add nsw i32 %n, 10<br>
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 %add<br>
+  store i32 %i, i32* %add.ptr, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test18:<br>
+; CHECK-NEXT: param     i32, i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $0, $pop1{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, 40($pop2), $2{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test18(i32* %p, i32 %n, i32 %i) {<br>
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 %n<br>
+  %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10<br>
+  store i32 %i, i32* %add.ptr1, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test19:<br>
+; CHECK-NEXT: param     i32, i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}<br>
+; CHECK-NEXT: i32.const $push3=, 40{{$}}<br>
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, 0($pop4), $2{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test19(i32* %p, i32 %n, i32 %i) {<br>
+  %add = add nsw i32 10, %n<br>
+  %add.ptr = getelementptr inbounds i32, i32* %p, i32 %add<br>
+  store i32 %i, i32* %add.ptr, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test20:<br>
+; CHECK-NEXT: param     i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, -40{{$}}<br>
+; CHECK-NEXT: i32.add   $push1=, $0, $pop0{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, 0($pop1), $1{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test20(i32* %p, i32 %i) {<br>
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 -10<br>
+  store i32 %i, i32* %arrayidx, align 4<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: store_test21:<br>
+; CHECK-NEXT: param     i32, i32, i32{{$}}<br>
+; CHECK-NEXT: i32.const $push0=, 2{{$}}<br>
+; CHECK-NEXT: i32.shl   $push1=, $1, $pop0{{$}}<br>
+; CHECK-NEXT: i32.add   $push2=, $pop1, $0{{$}}<br>
+; CHECK-NEXT: i32.const $push3=, -40{{$}}<br>
+; CHECK-NEXT: i32.add   $push4=, $pop2, $pop3{{$}}<br>
+; CHECK-NEXT: i32.store $discard=, 0($pop4), $2{{$}}<br>
+; CHECK-NEXT: return{{$}}<br>
+define void @store_test21(i32* %p, i32 %n, i32 %i) {<br>
+  %add = add nsw i32 %n, -10<br>
+  %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add<br>
+  store i32 %i, i32* %arrayidx, align 4<br>
+  ret void<br>
+}<br>
<br>
Modified: llvm/trunk/test/CodeGen/X86/lea-opt.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/lea-opt.ll?rev=258296&r1=258295&r2=258296&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/lea-opt.ll?rev=258296&r1=258295&r2=258296&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/CodeGen/X86/lea-opt.ll (original)<br>
+++ llvm/trunk/test/CodeGen/X86/lea-opt.ll Wed Jan 20 01:03:08 2016<br>
@@ -34,12 +34,12 @@ sw.bb.2:<br>
 sw.epilog:                                        ; preds = %sw.bb.2, %sw.bb.1, %entry<br>
   ret void<br>
 ; CHECK-LABEL: test1:<br>
-; CHECK:       leaq (%rdi,%rdi,2), [[REG1:%[a-z]+]]<br>
-; CHECK:       movl arr1(,[[REG1]],4), {{.*}}<br>
-; CHECK:       leaq arr1+4(,[[REG1]],4), [[REG2:%[a-z]+]]<br>
-; CHECK:       subl arr1+4(,[[REG1]],4), {{.*}}<br>
-; CHECK:       leaq arr1+8(,[[REG1]],4), [[REG3:%[a-z]+]]<br>
-; CHECK:       addl arr1+8(,[[REG1]],4), {{.*}}<br>
+; CHECK:       shlq $2, [[REG1:%[a-z]+]]<br>
+; CHECK:       movl arr1([[REG1]],[[REG1]],2), {{.*}}<br>
+; CHECK:       leaq arr1+4([[REG1]],[[REG1]],2), [[REG2:%[a-z]+]]<br>
+; CHECK:       subl arr1+4([[REG1]],[[REG1]],2), {{.*}}<br>
+; CHECK:       leaq arr1+8([[REG1]],[[REG1]],2), [[REG3:%[a-z]+]]<br>
+; CHECK:       addl arr1+8([[REG1]],[[REG1]],2), {{.*}}<br>
 ; CHECK:       movl ${{[1-4]+}}, ([[REG2]])<br>
 ; CHECK:       movl ${{[1-4]+}}, ([[REG3]])<br>
 ; CHECK:       movl ${{[1-4]+}}, ([[REG2]])<br>
@@ -74,11 +74,11 @@ sw.bb.2:<br>
 sw.epilog:                                        ; preds = %sw.bb.2, %sw.bb.1, %entry<br>
   ret void<br>
 ; CHECK-LABEL: test2:<br>
-; CHECK:       leaq (%rdi,%rdi,2), [[REG1:%[a-z]+]]<br>
-; CHECK:       leaq arr1+4(,[[REG1]],4), [[REG2:%[a-z]+]]<br>
+; CHECK:       shlq $2, [[REG1:%[a-z]+]]<br>
+; CHECK:       leaq arr1+4([[REG1]],[[REG1]],2), [[REG2:%[a-z]+]]<br>
 ; CHECK:       movl -4([[REG2]]), {{.*}}<br>
 ; CHECK:       subl ([[REG2]]), {{.*}}<br>
-; CHECK:       leaq arr1+8(,[[REG1]],4), [[REG3:%[a-z]+]]<br>
+; CHECK:       leaq arr1+8([[REG1]],[[REG1]],2), [[REG3:%[a-z]+]]<br>
 ; CHECK:       addl ([[REG3]]), {{.*}}<br>
 ; CHECK:       movl ${{[1-4]+}}, ([[REG2]])<br>
 ; CHECK:       movl ${{[1-4]+}}, ([[REG3]])<br>
<br>
Modified: llvm/trunk/test/CodeGen/XCore/threads.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/XCore/threads.ll?rev=258296&r1=258295&r2=258296&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/XCore/threads.ll?rev=258296&r1=258295&r2=258296&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/CodeGen/XCore/threads.ll (original)<br>
+++ llvm/trunk/test/CodeGen/XCore/threads.ll Wed Jan 20 01:03:08 2016<br>
@@ -87,7 +87,7 @@ define i32* @f_tle() {<br>
 ; CHECK: shl [[R0:r[0-9]]], r11, 3<br>
 ; CHECK: ldaw [[R1:r[0-9]]], dp[tle]<br>
 ; r0 = &tl + id*8<br>
-; CHECK: add r0, [[R1]], [[R0]]<br>
+; CHECK: add r0, [[R0]], [[R1]]<br>
   ret i32* getelementptr inbounds ([2 x i32], [2 x i32]* @tle, i32 0, i32 0)<br>
 }<br>
<br>
@@ -96,7 +96,7 @@ define i32 @f_tlExpr () {<br>
 ; CHECK: get r11, id<br>
 ; CHECK: shl [[R0:r[0-9]]], r11, 3<br>
 ; CHECK: ldaw [[R1:r[0-9]]], dp[tle]<br>
-; CHECK: add [[R2:r[0-9]]], [[R1]], [[R0]]<br>
+; CHECK: add [[R2:r[0-9]]], [[R0]], [[R1]]<br>
 ; CHECK: add r0, [[R2]], [[R2]]<br>
   ret i32 add(<br>
       i32 ptrtoint( i32* getelementptr inbounds ([2 x i32], [2 x i32]* @tle, i32 0, i32 0) to i32),<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>