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

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 21 17:00:45 PST 2016


This change broke the following small program on Windows:

#include <string>
#include <iostream>
static const char kData[] = "asdf jkl;";
int main() {
  std::string s(kData + 3, sizeof(kData) - 3);
  std::cout << s << '\n';
}

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.

I'll get a better reduction soon, but I want to revert for now since this
is close to end of day pacific time.

On Tue, Jan 19, 2016 at 11:03 PM, Dan Gohman via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

> 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),
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160121/f82ddbe9/attachment-0001.html>


More information about the llvm-commits mailing list