mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[SelectionDAG] Fold more offsets into GlobalAddresses
This reapplies r258296 and r258366, and also fixes an existing bug in SelectionDAG.cpp's isMemSrcFromString, neglecting to account for the offset in a GlobalAddressSDNode, which is uncovered by those patches. llvm-svn: 258482
This commit is contained in:
parent
714fa41ac7
commit
46980bada3
@ -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);
|
||||
|
@ -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 *N, APInt& SplatValue) {
|
||||
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(unsigned Opc, SDLoc DL,
|
||||
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(unsigned Opc, SDLoc DL,
|
||||
}
|
||||
|
||||
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 *N) {
|
||||
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 *N) {
|
||||
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_UNDEF(SDNode *N) {
|
||||
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_UNDEF(SDNode *N) {
|
||||
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 *N) {
|
||||
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_INREG(SDNode *N) {
|
||||
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(SDNode *N) {
|
||||
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(SDNode *N) {
|
||||
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(SDNode *N) {
|
||||
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::isMulAddWithConstProfitable(SDNode *MulNode,
|
||||
// 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::getStoreMergeAndAliasCandidates(
|
||||
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::getStoreMergeAndAliasCandidates(
|
||||
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::getStoreMergeAndAliasCandidates(
|
||||
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(StoreSDNode* St) {
|
||||
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(SDNode *N, SDValue OldChain) {
|
||||
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::findBetterNeighborChains(StoreSDNode* St) {
|
||||
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))
|
||||
|
@ -3263,6 +3263,26 @@ SDValue SelectionDAG::FoldConstantArithmetic(unsigned Opcode, SDLoc DL, EVT VT,
|
||||
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,13 @@ SDValue SelectionDAG::FoldConstantArithmetic(unsigned Opcode, SDLoc DL, EVT VT,
|
||||
}
|
||||
}
|
||||
|
||||
// fold (add Sym, c) -> Sym+c
|
||||
if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Cst1))
|
||||
return FoldSymbolOffset(Opcode, VT, GA, Cst2);
|
||||
if (isCommutativeBinOp(Opcode))
|
||||
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);
|
||||
@ -4136,7 +4163,7 @@ static SDValue getMemBasePlusOffset(SDValue Base, unsigned Offset, SDLoc dl,
|
||||
/// isMemSrcFromString - Returns true if memcpy source is a string constant.
|
||||
///
|
||||
static bool isMemSrcFromString(SDValue Src, StringRef &Str) {
|
||||
unsigned SrcDelta = 0;
|
||||
uint64_t SrcDelta = 0;
|
||||
GlobalAddressSDNode *G = nullptr;
|
||||
if (Src.getOpcode() == ISD::GlobalAddress)
|
||||
G = cast<GlobalAddressSDNode>(Src);
|
||||
@ -4149,7 +4176,8 @@ static bool isMemSrcFromString(SDValue Src, StringRef &Str) {
|
||||
if (!G)
|
||||
return false;
|
||||
|
||||
return getConstantStringInfo(G->getGlobal(), Str, SrcDelta, false);
|
||||
return getConstantStringInfo(G->getGlobal(), Str,
|
||||
SrcDelta + G->getOffset(), false);
|
||||
}
|
||||
|
||||
/// Determines the optimal series of memory ops to replace the memset / memcpy.
|
||||
@ -7322,6 +7350,22 @@ bool ShuffleVectorSDNode::isSplatMask(const int *Mask, EVT VT) {
|
||||
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,
|
||||
|
672
test/CodeGen/WebAssembly/address-offsets.ll
Normal file
672
test/CodeGen/WebAssembly/address-offsets.ll
Normal file
@ -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"
|
||||
|
||||
@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
|
||||
}
|
@ -34,12 +34,12 @@ sw.bb.2: ; preds = %entry
|
||||
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: ; preds = %entry
|
||||
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]])
|
||||
|
24
test/CodeGen/X86/memcpy-from-string.ll
Normal file
24
test/CodeGen/X86/memcpy-from-string.ll
Normal file
@ -0,0 +1,24 @@
|
||||
; RUN: llc < %s -asm-verbose=false | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
%0 = type { %1, i64, %2 }
|
||||
%1 = type { i8* }
|
||||
%2 = type { i64, [8 x i8] }
|
||||
|
||||
@0 = internal constant [10 x i8] c"asdf jkl;\00", align 1
|
||||
|
||||
; Memcpy lowering should emit stores of immediates containing string data from
|
||||
; the correct offsets.
|
||||
|
||||
; CHECK-LABEL: foo:
|
||||
; CHECK: movb $0, 6(%rdi)
|
||||
; CHECK: movw $15212, 4(%rdi)
|
||||
; CHECK: movl $1802117222, (%rdi)
|
||||
define void @foo(i8* %tmp2) {
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %tmp2, i8* getelementptr inbounds ([10 x i8], [10 x i8]* @0, i64 0, i64 3), i64 7, i32 1, i1 false)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1)
|
18
test/CodeGen/X86/negative-offset.ll
Normal file
18
test/CodeGen/X86/negative-offset.ll
Normal file
@ -0,0 +1,18 @@
|
||||
; RUN: llc < %s -asm-verbose=false | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
; Test that a constant consisting of a global symbol with a negative offset
|
||||
; is properly folded and isel'd.
|
||||
|
||||
; CHECK-LABEL: negative_offset:
|
||||
; CHECK: movl $G, %eax
|
||||
; CHECK: notq %rax
|
||||
; CHECK: addq %rdi, %rax
|
||||
; CHECK: retq
|
||||
@G = external global [8 x i32]
|
||||
define i8* @negative_offset(i8* %a) {
|
||||
%t = getelementptr i8, i8* %a, i64 sub (i64 -1, i64 ptrtoint ([8 x i32]* @G to i64))
|
||||
ret i8* %t
|
||||
}
|
@ -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),
|
||||
|
Loading…
Reference in New Issue
Block a user