<div dir="ltr"><span style="color:rgb(0,0,0);font-family:Menlo,Consolas,Monaco,monospace;font-size:11px;line-height:16px;white-space:pre-wrap;background-color:rgb(170,255,170)">DepCandidates (std::set) is dubious.</span><br></div><br><div class="gmail_quote"><div dir="ltr">On Thu, Jul 9, 2015 at 10:06 AM NAKAMURA Takumi <<a href="mailto:geek4civic@gmail.com">geek4civic@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Seems causes different emissions between stage2 and stage3.<br><br> <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__bb.pgr.jp_builders_clang-2D3stage-2Di686-2Dlinux_builds_2726&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=TTOGZbdQ-wgfCFnl68QLWp8Aqk-rJbgmzE0AkbojPQQ&s=3UtyGV2eAHx7UOAPCYQryj9FrzVVQ_hOzLX9gUXSPV0&e=" target="_blank">http://bb.pgr.jp/builders/clang-3stage-i686-linux/builds/2726</a><div><br></div><div>Stage2 is built by clang built by g++, +Asserts.</div><div>Stage3 is built by clang built by stage2-clang, -Asserts.</div></div><br><div class="gmail_quote"><div dir="ltr">On Thu, Jul 9, 2015 at 6:25 AM Reid Kleckner <<a href="mailto:rnk@google.com" target="_blank">rnk@google.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">The number-memchecks.ll test fails for me on Windows because the output ordering is different. The two check groups are printed in opposite order:<div><br></div><div><br></div><div>"""</div><div><div>Printing analysis 'Loop Access Analysis' for function 'testg':</div><div> for.body:</div><div> Report: unsafe dependent memory operations in loop</div><div> Interesting Dependences:</div><div> Unknown:</div><div> store i16 %mul1, i16* %arrayidxC, align 2 -></div></div></div><div dir="ltr"><div><div> store i16 %mul, i16* %arrayidxC1, align 2</div><div><br></div></div></div><div dir="ltr"><div><div> Run-time memory checks:</div><div> Check 0:</div><div> Comparing group 0:</div></div></div><div dir="ltr"><div><div> %arrayidxB = getelementptr inbounds i16, i16* %b, i64 %ind</div></div></div><div dir="ltr"><div><div> Against group 2:</div></div></div><div dir="ltr"><div><div> %arrayidxC1 = getelementptr inbounds i16, i16* %c, i64 %store_ind_inc</div></div></div><div dir="ltr"><div><div> %arrayidxC = getelementptr inbounds i16, i16* %c, i64 %store_ind</div></div></div><div dir="ltr"><div><div> Check 1:</div><div> Comparing group 1:</div></div></div><div dir="ltr"><div><div> %arrayidxA1 = getelementptr inbounds i16, i16* %a, i64 %add</div></div></div><div dir="ltr"><div><div> %arrayidxA = getelementptr inbounds i16, i16* %a, i64 %ind</div></div></div><div dir="ltr"><div><div> Against group 2:</div></div></div><div dir="ltr"><div><div> %arrayidxC1 = getelementptr inbounds i16, i16* %c, i64 %store_ind_inc</div></div></div><div dir="ltr"><div><div> %arrayidxC = getelementptr inbounds i16, i16* %c, i64 %store_ind</div></div></div><div dir="ltr"><div></div><div>"""</div><div><br></div><div>Can you fix the code to be deterministic, i.e. not rely on hashtable ordering?</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jul 8, 2015 at 2:16 AM, Silviu Baranga <span dir="ltr"><<a href="mailto:silviu.baranga@arm.com" target="_blank">silviu.baranga@arm.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: sbaranga<br>
Date: Wed Jul 8 04:16:33 2015<br>
New Revision: 241673<br>
<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject-3Frev-3D241673-26view-3Drev&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=uFcf0gLR_MIrQFYhuAb8gVsoNdftcSB1mZMezpDReAU&s=Dxo7K237VlAGYajD5SNgUt5XddeKt_mFDUjKmbGQiqw&e=" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=241673&view=rev</a><br>
Log:<br>
[LAA] Merge memchecks for accesses separated by a constant offset<br>
<br>
Summary:<br>
Often filter-like loops will do memory accesses that are<br>
separated by constant offsets. In these cases it is<br>
common that we will exceed the threshold for the<br>
allowable number of checks.<br>
<br>
However, it should be possible to merge such checks,<br>
sice a check of any interval againt two other intervals separated<br>
by a constant offset (a,b), (a+c, b+c) will be equivalent with<br>
a check againt (a, b+c), as long as (a,b) and (a+c, b+c) overlap.<br>
Assuming the loop will be executed for a sufficient number of<br>
iterations, this will be true. If not true, checking against<br>
(a, b+c) is still safe (although not equivalent).<br>
<br>
As long as there are no dependencies between two accesses,<br>
we can merge their checks into a single one. We use this<br>
technique to construct groups of accesses, and then check<br>
the intervals associated with the groups instead of<br>
checking the accesses directly.<br>
<br>
Reviewers: anemet<br>
<br>
Subscribers: llvm-commits<br>
<br>
Differential Revision: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__reviews.llvm.org_D10386&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=uFcf0gLR_MIrQFYhuAb8gVsoNdftcSB1mZMezpDReAU&s=WZTW9zyjMHaRKXUhKETIcSFkjBukReMt6Zx5q0F5GLo&e=" rel="noreferrer" target="_blank">http://reviews.llvm.org/D10386</a><br>
<br>
Modified:<br>
llvm/trunk/include/llvm/Analysis/LoopAccessAnalysis.h<br>
llvm/trunk/lib/Analysis/LoopAccessAnalysis.cpp<br>
llvm/trunk/test/Analysis/LoopAccessAnalysis/number-of-memchecks.ll<br>
llvm/trunk/test/Analysis/LoopAccessAnalysis/resort-to-memchecks-only.ll<br>
llvm/trunk/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks.ll<br>
llvm/trunk/test/Transforms/LoopDistribute/basic-with-memchecks.ll<br>
<br>
Modified: llvm/trunk/include/llvm/Analysis/LoopAccessAnalysis.h<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_include_llvm_Analysis_LoopAccessAnalysis.h-3Frev-3D241673-26r1-3D241672-26r2-3D241673-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=uFcf0gLR_MIrQFYhuAb8gVsoNdftcSB1mZMezpDReAU&s=ee7qyjv9D3q1usyor7Ut8EOQ4lfsGoBXXa40MufUDrQ&e=" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/LoopAccessAnalysis.h?rev=241673&r1=241672&r2=241673&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Analysis/LoopAccessAnalysis.h (original)<br>
+++ llvm/trunk/include/llvm/Analysis/LoopAccessAnalysis.h Wed Jul 8 04:16:33 2015<br>
@@ -311,7 +311,7 @@ public:<br>
/// This struct holds information about the memory runtime legality check that<br>
/// a group of pointers do not overlap.<br>
struct RuntimePointerCheck {<br>
- RuntimePointerCheck() : Need(false) {}<br>
+ RuntimePointerCheck(ScalarEvolution *SE) : Need(false), SE(SE) {}<br>
<br>
/// Reset the state of the pointer runtime information.<br>
void reset() {<br>
@@ -322,16 +322,55 @@ public:<br>
IsWritePtr.clear();<br>
DependencySetId.clear();<br>
AliasSetId.clear();<br>
+ Exprs.clear();<br>
}<br>
<br>
/// Insert a pointer and calculate the start and end SCEVs.<br>
- void insert(ScalarEvolution *SE, Loop *Lp, Value *Ptr, bool WritePtr,<br>
- unsigned DepSetId, unsigned ASId,<br>
- const ValueToValueMap &Strides);<br>
+ void insert(Loop *Lp, Value *Ptr, bool WritePtr, unsigned DepSetId,<br>
+ unsigned ASId, const ValueToValueMap &Strides);<br>
<br>
/// \brief No run-time memory checking is necessary.<br>
bool empty() const { return Pointers.empty(); }<br>
<br>
+ /// A grouping of pointers. A single memcheck is required between<br>
+ /// two groups.<br>
+ struct CheckingPtrGroup {<br>
+ /// \brief Create a new pointer checking group containing a single<br>
+ /// pointer, with index \p Index in RtCheck.<br>
+ CheckingPtrGroup(unsigned Index, RuntimePointerCheck &RtCheck)<br>
+ : RtCheck(RtCheck), High(RtCheck.Ends[Index]),<br>
+ Low(RtCheck.Starts[Index]) {<br>
+ Members.push_back(Index);<br>
+ }<br>
+<br>
+ /// \brief Tries to add the pointer recorded in RtCheck at index<br>
+ /// \p Index to this pointer checking group. We can only add a pointer<br>
+ /// to a checking group if we will still be able to get<br>
+ /// the upper and lower bounds of the check. Returns true in case<br>
+ /// of success, false otherwise.<br>
+ bool addPointer(unsigned Index);<br>
+<br>
+ /// Constitutes the context of this pointer checking group. For each<br>
+ /// pointer that is a member of this group we will retain the index<br>
+ /// at which it appears in RtCheck.<br>
+ RuntimePointerCheck &RtCheck;<br>
+ /// The SCEV expression which represents the upper bound of all the<br>
+ /// pointers in this group.<br>
+ const SCEV *High;<br>
+ /// The SCEV expression which represents the lower bound of all the<br>
+ /// pointers in this group.<br>
+ const SCEV *Low;<br>
+ /// Indices of all the pointers that constitute this grouping.<br>
+ SmallVector<unsigned, 2> Members;<br>
+ };<br>
+<br>
+ /// \brief Groups pointers such that a single memcheck is required<br>
+ /// between two different groups. This will clear the CheckingGroups vector<br>
+ /// and re-compute it. We will only group dependecies if \p UseDependencies<br>
+ /// is true, otherwise we will create a separate group for each pointer.<br>
+ void groupChecks(MemoryDepChecker::DepCandidates &DepCands,<br>
+ bool UseDependencies);<br>
+<br>
/// \brief Decide whether we need to issue a run-time check for pointer at<br>
/// index \p I and \p J to prove their independence.<br>
///<br>
@@ -341,6 +380,12 @@ public:<br>
bool needsChecking(unsigned I, unsigned J,<br>
const SmallVectorImpl<int> *PtrPartition) const;<br>
<br>
+ /// \brief Decide if we need to add a check between two groups of pointers,<br>
+ /// according to needsChecking.<br>
+ bool needsChecking(const CheckingPtrGroup &M,<br>
+ const CheckingPtrGroup &N,<br>
+ const SmallVectorImpl<int> *PtrPartition) const;<br>
+<br>
/// \brief Return true if any pointer requires run-time checking according<br>
/// to needsChecking.<br>
bool needsAnyChecking(const SmallVectorImpl<int> *PtrPartition) const;<br>
@@ -372,6 +417,12 @@ public:<br>
SmallVector<unsigned, 2> DependencySetId;<br>
/// Holds the id of the disjoint alias set to which this pointer belongs.<br>
SmallVector<unsigned, 2> AliasSetId;<br>
+ /// Holds at position i the SCEV for the access i<br>
+ SmallVector<const SCEV *, 2> Exprs;<br>
+ /// Holds a partitioning of pointers into "check groups".<br>
+ SmallVector<CheckingPtrGroup, 2> CheckingGroups;<br>
+ /// Holds a pointer to the ScalarEvolution analysis.<br>
+ ScalarEvolution *SE;<br>
};<br>
<br>
LoopAccessInfo(Loop *L, ScalarEvolution *SE, const DataLayout &DL,<br>
<br>
Modified: llvm/trunk/lib/Analysis/LoopAccessAnalysis.cpp<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_lib_Analysis_LoopAccessAnalysis.cpp-3Frev-3D241673-26r1-3D241672-26r2-3D241673-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=uFcf0gLR_MIrQFYhuAb8gVsoNdftcSB1mZMezpDReAU&s=jgDoUSmGrEpNcijw3f5mG6psVDXWQp5Rz1pJjlCtKRQ&e=" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LoopAccessAnalysis.cpp?rev=241673&r1=241672&r2=241673&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Analysis/LoopAccessAnalysis.cpp (original)<br>
+++ llvm/trunk/lib/Analysis/LoopAccessAnalysis.cpp Wed Jul 8 04:16:33 2015<br>
@@ -48,6 +48,13 @@ static cl::opt<unsigned, true> RuntimeMe<br>
cl::location(VectorizerParams::RuntimeMemoryCheckThreshold), cl::init(8));<br>
unsigned VectorizerParams::RuntimeMemoryCheckThreshold;<br>
<br>
+/// \brief The maximum iterations used to merge memory checks<br>
+static cl::opt<unsigned> MemoryCheckMergeThreshold(<br>
+ "memory-check-merge-threshold", cl::Hidden,<br>
+ cl::desc("Maximum number of comparisons done when trying to merge "<br>
+ "runtime memory checks. (default = 100)"),<br>
+ cl::init(100));<br>
+<br>
/// Maximum SIMD width.<br>
const unsigned VectorizerParams::MaxVectorWidth = 64;<br>
<br>
@@ -113,8 +120,8 @@ const SCEV *llvm::replaceSymbolicStrideS<br>
}<br>
<br>
void LoopAccessInfo::RuntimePointerCheck::insert(<br>
- ScalarEvolution *SE, Loop *Lp, Value *Ptr, bool WritePtr, unsigned DepSetId,<br>
- unsigned ASId, const ValueToValueMap &Strides) {<br>
+ Loop *Lp, Value *Ptr, bool WritePtr, unsigned DepSetId, unsigned ASId,<br>
+ const ValueToValueMap &Strides) {<br>
// Get the stride replaced scev.<br>
const SCEV *Sc = replaceSymbolicStrideSCEV(SE, Strides, Ptr);<br>
const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(Sc);<br>
@@ -127,6 +134,136 @@ void LoopAccessInfo::RuntimePointerCheck<br>
IsWritePtr.push_back(WritePtr);<br>
DependencySetId.push_back(DepSetId);<br>
AliasSetId.push_back(ASId);<br>
+ Exprs.push_back(Sc);<br>
+}<br>
+<br>
+bool LoopAccessInfo::RuntimePointerCheck::needsChecking(<br>
+ const CheckingPtrGroup &M, const CheckingPtrGroup &N,<br>
+ const SmallVectorImpl<int> *PtrPartition) const {<br>
+ for (unsigned I = 0, EI = M.Members.size(); EI != I; ++I)<br>
+ for (unsigned J = 0, EJ = N.Members.size(); EJ != J; ++J)<br>
+ if (needsChecking(M.Members[I], N.Members[J], PtrPartition))<br>
+ return true;<br>
+ return false;<br>
+}<br>
+<br>
+/// Compare \p I and \p J and return the minimum.<br>
+/// Return nullptr in case we couldn't find an answer.<br>
+static const SCEV *getMinFromExprs(const SCEV *I, const SCEV *J,<br>
+ ScalarEvolution *SE) {<br>
+ const SCEV *Diff = SE->getMinusSCEV(J, I);<br>
+ const SCEVConstant *C = dyn_cast<const SCEVConstant>(Diff);<br>
+<br>
+ if (!C)<br>
+ return nullptr;<br>
+ if (C->getValue()->isNegative())<br>
+ return J;<br>
+ return I;<br>
+}<br>
+<br>
+bool LoopAccessInfo::RuntimePointerCheck::CheckingPtrGroup::addPointer(<br>
+ unsigned Index) {<br>
+ // Compare the starts and ends with the known minimum and maximum<br>
+ // of this set. We need to know how we compare against the min/max<br>
+ // of the set in order to be able to emit memchecks.<br>
+ const SCEV *Min0 = getMinFromExprs(RtCheck.Starts[Index], Low, RtCheck.SE);<br>
+ if (!Min0)<br>
+ return false;<br>
+<br>
+ const SCEV *Min1 = getMinFromExprs(RtCheck.Ends[Index], High, RtCheck.SE);<br>
+ if (!Min1)<br>
+ return false;<br>
+<br>
+ // Update the low bound expression if we've found a new min value.<br>
+ if (Min0 == RtCheck.Starts[Index])<br>
+ Low = RtCheck.Starts[Index];<br>
+<br>
+ // Update the high bound expression if we've found a new max value.<br>
+ if (Min1 != RtCheck.Ends[Index])<br>
+ High = RtCheck.Ends[Index];<br>
+<br>
+ Members.push_back(Index);<br>
+ return true;<br>
+}<br>
+<br>
+void LoopAccessInfo::RuntimePointerCheck::groupChecks(<br>
+ MemoryDepChecker::DepCandidates &DepCands,<br>
+ bool UseDependencies) {<br>
+ // We build the groups from dependency candidates equivalence classes<br>
+ // because:<br>
+ // - We know that pointers in the same equivalence class share<br>
+ // the same underlying object and therefore there is a chance<br>
+ // that we can compare pointers<br>
+ // - We wouldn't be able to merge two pointers for which we need<br>
+ // to emit a memcheck. The classes in DepCands are already<br>
+ // conveniently built such that no two pointers in the same<br>
+ // class need checking against each other.<br>
+<br>
+ // We use the following (greedy) algorithm to construct the groups<br>
+ // For every pointer in the equivalence class:<br>
+ // For each existing group:<br>
+ // - if the difference between this pointer and the min/max bounds<br>
+ // of the group is a constant, then make the pointer part of the<br>
+ // group and update the min/max bounds of that group as required.<br>
+<br>
+ CheckingGroups.clear();<br>
+<br>
+ // If we don't have the dependency partitions, construct a new<br>
+ // checking pointer group for each pointer.<br>
+ if (!UseDependencies) {<br>
+ for (unsigned I = 0; I < Pointers.size(); ++I)<br>
+ CheckingGroups.push_back(CheckingPtrGroup(I, *this));<br>
+ return;<br>
+ }<br>
+<br>
+ unsigned TotalComparisons = 0;<br>
+<br>
+ DenseMap<Value *, unsigned> PositionMap;<br>
+ for (unsigned Pointer = 0; Pointer < Pointers.size(); ++Pointer)<br>
+ PositionMap[Pointers[Pointer]] = Pointer;<br>
+<br>
+ // Go through all equivalence classes, get the the "pointer check groups"<br>
+ // and add them to the overall solution.<br>
+ for (auto DI = DepCands.begin(), DE = DepCands.end(); DI != DE; ++DI) {<br>
+ if (!DI->isLeader())<br>
+ continue;<br>
+<br>
+ SmallVector<CheckingPtrGroup, 2> Groups;<br>
+<br>
+ for (auto MI = DepCands.member_begin(DI), ME = DepCands.member_end();<br>
+ MI != ME; ++MI) {<br>
+ unsigned Pointer = PositionMap[MI->getPointer()];<br>
+ bool Merged = false;<br>
+<br>
+ // Go through all the existing sets and see if we can find one<br>
+ // which can include this pointer.<br>
+ for (CheckingPtrGroup &Group : Groups) {<br>
+ // Don't perform more than a certain amount of comparisons.<br>
+ // This should limit the cost of grouping the pointers to something<br>
+ // reasonable. If we do end up hitting this threshold, the algorithm<br>
+ // will create separate groups for all remaining pointers.<br>
+ if (TotalComparisons > MemoryCheckMergeThreshold)<br>
+ break;<br>
+<br>
+ TotalComparisons++;<br>
+<br>
+ if (Group.addPointer(Pointer)) {<br>
+ Merged = true;<br>
+ break;<br>
+ }<br>
+ }<br>
+<br>
+ if (!Merged)<br>
+ // We couldn't add this pointer to any existing set or the threshold<br>
+ // for the number of comparisons has been reached. Create a new group<br>
+ // to hold the current pointer.<br>
+ Groups.push_back(CheckingPtrGroup(Pointer, *this));<br>
+ }<br>
+<br>
+ // We've computed the grouped checks for this partition.<br>
+ // Save the results and continue with the next one.<br>
+ std::copy(Groups.begin(), Groups.end(), std::back_inserter(CheckingGroups));<br>
+ }<br>
}<br>
<br>
bool LoopAccessInfo::RuntimePointerCheck::needsChecking(<br>
@@ -156,42 +293,71 @@ bool LoopAccessInfo::RuntimePointerCheck<br>
void LoopAccessInfo::RuntimePointerCheck::print(<br>
raw_ostream &OS, unsigned Depth,<br>
const SmallVectorImpl<int> *PtrPartition) const {<br>
- unsigned NumPointers = Pointers.size();<br>
- if (NumPointers == 0)<br>
- return;<br>
<br>
OS.indent(Depth) << "Run-time memory checks:\n";<br>
+<br>
unsigned N = 0;<br>
- for (unsigned I = 0; I < NumPointers; ++I)<br>
- for (unsigned J = I + 1; J < NumPointers; ++J)<br>
- if (needsChecking(I, J, PtrPartition)) {<br>
- OS.indent(Depth) << N++ << ":\n";<br>
- OS.indent(Depth + 2) << *Pointers[I];<br>
- if (PtrPartition)<br>
- OS << " (Partition: " << (*PtrPartition)[I] << ")";<br>
- OS << "\n";<br>
- OS.indent(Depth + 2) << *Pointers[J];<br>
- if (PtrPartition)<br>
- OS << " (Partition: " << (*PtrPartition)[J] << ")";<br>
- OS << "\n";<br>
+ for (unsigned I = 0; I < CheckingGroups.size(); ++I)<br>
+ for (unsigned J = I + 1; J < CheckingGroups.size(); ++J)<br>
+ if (needsChecking(CheckingGroups[I], CheckingGroups[J], PtrPartition)) {<br>
+ OS.indent(Depth) << "Check " << N++ << ":\n";<br>
+ OS.indent(Depth + 2) << "Comparing group " << I << ":\n";<br>
+<br>
+ for (unsigned K = 0; K < CheckingGroups[I].Members.size(); ++K) {<br>
+ OS.indent(Depth + 2) << *Pointers[CheckingGroups[I].Members[K]]<br>
+ << "\n";<br>
+ if (PtrPartition)<br>
+ OS << " (Partition: "<br>
+ << (*PtrPartition)[CheckingGroups[I].Members[K]] << ")"<br>
+ << "\n";<br>
+ }<br>
+<br>
+ OS.indent(Depth + 2) << "Against group " << J << ":\n";<br>
+<br>
+ for (unsigned K = 0; K < CheckingGroups[J].Members.size(); ++K) {<br>
+ OS.indent(Depth + 2) << *Pointers[CheckingGroups[J].Members[K]]<br>
+ << "\n";<br>
+ if (PtrPartition)<br>
+ OS << " (Partition: "<br>
+ << (*PtrPartition)[CheckingGroups[J].Members[K]] << ")"<br>
+ << "\n";<br>
+ }<br>
}<br>
+<br>
+ OS.indent(Depth) << "Grouped accesses:\n";<br>
+ for (unsigned I = 0; I < CheckingGroups.size(); ++I) {<br>
+ OS.indent(Depth + 2) << "Group " << I << ":\n";<br>
+ OS.indent(Depth + 4) << "(Low: " << *CheckingGroups[I].Low<br>
+ << " High: " << *CheckingGroups[I].High << ")\n";<br>
+ for (unsigned J = 0; J < CheckingGroups[I].Members.size(); ++J) {<br>
+ OS.indent(Depth + 6) << "Member: " << *Exprs[CheckingGroups[I].Members[J]]<br>
+ << "\n";<br>
+ }<br>
+ }<br>
}<br>
<br>
unsigned LoopAccessInfo::RuntimePointerCheck::getNumberOfChecks(<br>
const SmallVectorImpl<int> *PtrPartition) const {<br>
- unsigned NumPointers = Pointers.size();<br>
+<br>
+ unsigned NumPartitions = CheckingGroups.size();<br>
unsigned CheckCount = 0;<br>
<br>
- for (unsigned I = 0; I < NumPointers; ++I)<br>
- for (unsigned J = I + 1; J < NumPointers; ++J)<br>
- if (needsChecking(I, J, PtrPartition))<br>
+ for (unsigned I = 0; I < NumPartitions; ++I)<br>
+ for (unsigned J = I + 1; J < NumPartitions; ++J)<br>
+ if (needsChecking(CheckingGroups[I], CheckingGroups[J], PtrPartition))<br>
CheckCount++;<br>
return CheckCount;<br>
}<br>
<br>
bool LoopAccessInfo::RuntimePointerCheck::needsAnyChecking(<br>
const SmallVectorImpl<int> *PtrPartition) const {<br>
- return getNumberOfChecks(PtrPartition) != 0;<br>
+ unsigned NumPointers = Pointers.size();<br>
+<br>
+ for (unsigned I = 0; I < NumPointers; ++I)<br>
+ for (unsigned J = I + 1; J < NumPointers; ++J)<br>
+ if (needsChecking(I, J, PtrPartition))<br>
+ return true;<br>
+ return false;<br>
}<br>
<br>
namespace {<br>
@@ -341,7 +507,7 @@ bool AccessAnalysis::canCheckPtrAtRT(<br>
// Each access has its own dependence set.<br>
DepId = RunningDepId++;<br>
<br>
- RtCheck.insert(SE, TheLoop, Ptr, IsWrite, DepId, ASId, StridesMap);<br>
+ RtCheck.insert(TheLoop, Ptr, IsWrite, DepId, ASId, StridesMap);<br>
<br>
DEBUG(dbgs() << "LAA: Found a runtime check ptr:" << *Ptr << '\n');<br>
} else {<br>
@@ -387,6 +553,9 @@ bool AccessAnalysis::canCheckPtrAtRT(<br>
}<br>
}<br>
<br>
+ if (NeedRTCheck && CanDoRT)<br>
+ RtCheck.groupChecks(DepCands, IsDepCheckNeeded);<br>
+<br>
return CanDoRT;<br>
}<br>
<br>
@@ -1360,32 +1529,35 @@ std::pair<Instruction *, Instruction *><br>
if (!PtrRtCheck.Need)<br>
return std::make_pair(nullptr, nullptr);<br>
<br>
- unsigned NumPointers = PtrRtCheck.Pointers.size();<br>
- SmallVector<TrackingVH<Value> , 2> Starts;<br>
- SmallVector<TrackingVH<Value> , 2> Ends;<br>
+ SmallVector<TrackingVH<Value>, 2> Starts;<br>
+ SmallVector<TrackingVH<Value>, 2> Ends;<br>
<br>
LLVMContext &Ctx = Loc->getContext();<br>
SCEVExpander Exp(*SE, DL, "induction");<br>
Instruction *FirstInst = nullptr;<br>
<br>
- for (unsigned i = 0; i < NumPointers; ++i) {<br>
- Value *Ptr = PtrRtCheck.Pointers[i];<br>
+ for (unsigned i = 0; i < PtrRtCheck.CheckingGroups.size(); ++i) {<br>
+ const RuntimePointerCheck::CheckingPtrGroup &CG =<br>
+ PtrRtCheck.CheckingGroups[i];<br>
+ Value *Ptr = PtrRtCheck.Pointers[CG.Members[0]];<br>
const SCEV *Sc = SE->getSCEV(Ptr);<br>
<br>
if (SE->isLoopInvariant(Sc, TheLoop)) {<br>
- DEBUG(dbgs() << "LAA: Adding RT check for a loop invariant ptr:" <<<br>
- *Ptr <<"\n");<br>
+ DEBUG(dbgs() << "LAA: Adding RT check for a loop invariant ptr:" << *Ptr<br>
+ << "\n");<br>
Starts.push_back(Ptr);<br>
Ends.push_back(Ptr);<br>
} else {<br>
- DEBUG(dbgs() << "LAA: Adding RT check for range:" << *Ptr << '\n');<br>
unsigned AS = Ptr->getType()->getPointerAddressSpace();<br>
<br>
// Use this type for pointer arithmetic.<br>
Type *PtrArithTy = Type::getInt8PtrTy(Ctx, AS);<br>
+ Value *Start = nullptr, *End = nullptr;<br>
<br>
- Value *Start = Exp.expandCodeFor(PtrRtCheck.Starts[i], PtrArithTy, Loc);<br>
- Value *End = Exp.expandCodeFor(PtrRtCheck.Ends[i], PtrArithTy, Loc);<br>
+ DEBUG(dbgs() << "LAA: Adding RT check for range:\n");<br>
+ Start = Exp.expandCodeFor(CG.Low, PtrArithTy, Loc);<br>
+ End = Exp.expandCodeFor(CG.High, PtrArithTy, Loc);<br>
+ DEBUG(dbgs() << "Start: " << *CG.Low << " End: " << *CG.High << "\n");<br>
Starts.push_back(Start);<br>
Ends.push_back(End);<br>
}<br>
@@ -1394,9 +1566,14 @@ std::pair<Instruction *, Instruction *><br>
IRBuilder<> ChkBuilder(Loc);<br>
// Our instructions might fold to a constant.<br>
Value *MemoryRuntimeCheck = nullptr;<br>
- for (unsigned i = 0; i < NumPointers; ++i) {<br>
- for (unsigned j = i+1; j < NumPointers; ++j) {<br>
- if (!PtrRtCheck.needsChecking(i, j, PtrPartition))<br>
+ for (unsigned i = 0; i < PtrRtCheck.CheckingGroups.size(); ++i) {<br>
+ for (unsigned j = i + 1; j < PtrRtCheck.CheckingGroups.size(); ++j) {<br>
+ const RuntimePointerCheck::CheckingPtrGroup &CGI =<br>
+ PtrRtCheck.CheckingGroups[i];<br>
+ const RuntimePointerCheck::CheckingPtrGroup &CGJ =<br>
+ PtrRtCheck.CheckingGroups[j];<br>
+<br>
+ if (!PtrRtCheck.needsChecking(CGI, CGJ, PtrPartition))<br>
continue;<br>
<br>
unsigned AS0 = Starts[i]->getType()->getPointerAddressSpace();<br>
@@ -1447,8 +1624,8 @@ LoopAccessInfo::LoopAccessInfo(Loop *L,<br>
const TargetLibraryInfo *TLI, AliasAnalysis *AA,<br>
DominatorTree *DT, LoopInfo *LI,<br>
const ValueToValueMap &Strides)<br>
- : DepChecker(SE, L), TheLoop(L), SE(SE), DL(DL),<br>
- TLI(TLI), AA(AA), DT(DT), LI(LI), NumLoads(0), NumStores(0),<br>
+ : PtrRtCheck(SE), DepChecker(SE, L), TheLoop(L), SE(SE), DL(DL), TLI(TLI),<br>
+ AA(AA), DT(DT), LI(LI), NumLoads(0), NumStores(0),<br>
MaxSafeDepDistBytes(-1U), CanVecMem(false),<br>
StoreToLoopInvariantAddress(false) {<br>
if (canAnalyzeLoop())<br>
<br>
Modified: llvm/trunk/test/Analysis/LoopAccessAnalysis/number-of-memchecks.ll<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_test_Analysis_LoopAccessAnalysis_number-2Dof-2Dmemchecks.ll-3Frev-3D241673-26r1-3D241672-26r2-3D241673-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=uFcf0gLR_MIrQFYhuAb8gVsoNdftcSB1mZMezpDReAU&s=Y-v3S_4R47_3pPyXhbHdLm4ACVBkEjbE-9GgFMygShY&e=" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/LoopAccessAnalysis/number-of-memchecks.ll?rev=241673&r1=241672&r2=241673&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/Analysis/LoopAccessAnalysis/number-of-memchecks.ll (original)<br>
+++ llvm/trunk/test/Analysis/LoopAccessAnalysis/number-of-memchecks.ll Wed Jul 8 04:16:33 2015<br>
@@ -1,19 +1,20 @@<br>
; RUN: opt -loop-accesses -analyze < %s | FileCheck %s<br>
<br>
-; 3 reads and 3 writes should need 12 memchecks<br>
-<br>
target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"<br>
target triple = "aarch64--linux-gnueabi"<br>
<br>
+; 3 reads and 3 writes should need 12 memchecks<br>
+; CHECK: function 'testf':<br>
; CHECK: Memory dependences are safe with run-time checks<br>
-; Memory dependecies have labels starting from 0, so in<br>
+<br>
+; Memory dependencies have labels starting from 0, so in<br>
; order to verify that we have n checks, we look for<br>
; (n-1): and not n:.<br>
<br>
; CHECK: Run-time memory checks:<br>
-; CHECK-NEXT: 0:<br>
-; CHECK: 11:<br>
-; CHECK-NOT: 12:<br>
+; CHECK-NEXT: Check 0:<br>
+; CHECK: Check 11:<br>
+; CHECK-NOT: Check 12:<br>
<br>
define void @testf(i16* %a,<br>
i16* %b,<br>
@@ -52,6 +53,165 @@ for.body:<br>
<br>
%exitcond = icmp eq i64 %add, 20<br>
br i1 %exitcond, label %for.end, label %for.body<br>
+<br>
+for.end: ; preds = %for.body<br>
+ ret void<br>
+}<br>
+<br>
+; The following (testg and testh) check that we can group<br>
+; memory checks of accesses which differ by a constant value.<br>
+; Both tests are based on the following C code:<br>
+;<br>
+; void testh(short *a, short *b, short *c) {<br>
+; unsigned long ind = 0;<br>
+; for (unsigned long ind = 0; ind < 20; ++ind) {<br>
+; c[2 * ind] = a[ind] * a[ind + 1];<br>
+; c[2 * ind + 1] = a[ind] * a[ind + 1] * b[ind];<br>
+; }<br>
+; }<br>
+;<br>
+; It is sufficient to check the intervals<br>
+; [a, a + 21], [b, b + 20] against [c, c + 41].<br>
+<br>
+; 3 reads and 2 writes - two of the reads can be merged,<br>
+; and the writes can be merged as well. This gives us a<br>
+; total of 2 memory checks.<br>
+<br>
+; CHECK: function 'testg':<br>
+<br>
+; CHECK: Run-time memory checks:<br>
+; CHECK-NEXT: Check 0:<br>
+; CHECK-NEXT: Comparing group 0:<br>
+; CHECK-NEXT: %arrayidxA1 = getelementptr inbounds i16, i16* %a, i64 %add<br>
+; CHECK-NEXT: %arrayidxA = getelementptr inbounds i16, i16* %a, i64 %ind<br>
+; CHECK-NEXT: Against group 2:<br>
+; CHECK-NEXT: %arrayidxC1 = getelementptr inbounds i16, i16* %c, i64 %store_ind_inc<br>
+; CHECK-NEXT: %arrayidxC = getelementptr inbounds i16, i16* %c, i64 %store_ind<br>
+; CHECK-NEXT: Check 1:<br>
+; CHECK-NEXT: Comparing group 1:<br>
+; CHECK-NEXT: %arrayidxB = getelementptr inbounds i16, i16* %b, i64 %ind<br>
+; CHECK-NEXT: Against group 2:<br>
+; CHECK-NEXT: %arrayidxC1 = getelementptr inbounds i16, i16* %c, i64 %store_ind_inc<br>
+; CHECK-NEXT: %arrayidxC = getelementptr inbounds i16, i16* %c, i64 %store_ind<br>
+; CHECK-NEXT: Grouped accesses:<br>
+; CHECK-NEXT: Group 0:<br>
+; CHECK-NEXT: (Low: %a High: (40 + %a))<br>
+; CHECK-NEXT: Member: {(2 + %a),+,2}<br>
+; CHECK-NEXT: Member: {%a,+,2}<br>
+; CHECK-NEXT: Group 1:<br>
+; CHECK-NEXT: (Low: %b High: (38 + %b))<br>
+; CHECK-NEXT: Member: {%b,+,2}<br>
+; CHECK-NEXT: Group 2:<br>
+; CHECK-NEXT: (Low: %c High: (78 + %c))<br>
+; CHECK-NEXT: Member: {(2 + %c),+,4}<br>
+; CHECK-NEXT: Member: {%c,+,4}<br>
+<br>
+define void @testg(i16* %a,<br>
+ i16* %b,<br>
+ i16* %c) {<br>
+entry:<br>
+ br label %for.body<br>
+<br>
+for.body: ; preds = %for.body, %entry<br>
+ %ind = phi i64 [ 0, %entry ], [ %add, %for.body ]<br>
+ %store_ind = phi i64 [ 0, %entry ], [ %store_ind_next, %for.body ]<br>
+<br>
+ %add = add nuw nsw i64 %ind, 1<br>
+ %store_ind_inc = add nuw nsw i64 %store_ind, 1<br>
+ %store_ind_next = add nuw nsw i64 %store_ind_inc, 1<br>
+<br>
+ %arrayidxA = getelementptr inbounds i16, i16* %a, i64 %ind<br>
+ %loadA = load i16, i16* %arrayidxA, align 2<br>
+<br>
+ %arrayidxA1 = getelementptr inbounds i16, i16* %a, i64 %add<br>
+ %loadA1 = load i16, i16* %arrayidxA1, align 2<br>
+<br>
+ %arrayidxB = getelementptr inbounds i16, i16* %b, i64 %ind<br>
+ %loadB = load i16, i16* %arrayidxB, align 2<br>
+<br>
+ %mul = mul i16 %loadA, %loadA1<br>
+ %mul1 = mul i16 %mul, %loadB<br>
+<br>
+ %arrayidxC = getelementptr inbounds i16, i16* %c, i64 %store_ind<br>
+ store i16 %mul1, i16* %arrayidxC, align 2<br>
+<br>
+ %arrayidxC1 = getelementptr inbounds i16, i16* %c, i64 %store_ind_inc<br>
+ store i16 %mul, i16* %arrayidxC1, align 2<br>
+<br>
+ %exitcond = icmp eq i64 %add, 20<br>
+ br i1 %exitcond, label %for.end, label %for.body<br>
+<br>
+for.end: ; preds = %for.body<br>
+ ret void<br>
+}<br>
+<br>
+; 3 reads and 2 writes - the writes can be merged into a single<br>
+; group, but the GEPs used for the reads are not marked as inbounds.<br>
+; We can still merge them because we are using a unit stride for<br>
+; accesses, so we cannot overflow the GEPs.<br>
+<br>
+; CHECK: function 'testh':<br>
+; CHECK: Run-time memory checks:<br>
+; CHECK-NEXT: Check 0:<br>
+; CHECK-NEXT: Comparing group 0:<br>
+; CHECK-NEXT: %arrayidxA1 = getelementptr i16, i16* %a, i64 %add<br>
+; CHECK-NEXT: %arrayidxA = getelementptr i16, i16* %a, i64 %ind<br>
+; CHECK-NEXT: Against group 2:<br>
+; CHECK-NEXT: %arrayidxC1 = getelementptr inbounds i16, i16* %c, i64 %store_ind_inc<br>
+; CHECK-NEXT: %arrayidxC = getelementptr inbounds i16, i16* %c, i64 %store_ind<br>
+; CHECK-NEXT: Check 1:<br>
+; CHECK-NEXT: Comparing group 1:<br>
+; CHECK-NEXT: %arrayidxB = getelementptr i16, i16* %b, i64 %ind<br>
+; CHECK-NEXT: Against group 2:<br>
+; CHECK-NEXT: %arrayidxC1 = getelementptr inbounds i16, i16* %c, i64 %store_ind_inc<br>
+; CHECK-NEXT: %arrayidxC = getelementptr inbounds i16, i16* %c, i64 %store_ind<br>
+; CHECK-NEXT: Grouped accesses:<br>
+; CHECK-NEXT: Group 0:<br>
+; CHECK-NEXT: (Low: %a High: (40 + %a))<br>
+; CHECK-NEXT: Member: {(2 + %a),+,2}<br>
+; CHECK-NEXT: Member: {%a,+,2}<br>
+; CHECK-NEXT: Group 1:<br>
+; CHECK-NEXT: (Low: %b High: (38 + %b))<br>
+; CHECK-NEXT: Member: {%b,+,2}<br>
+; CHECK-NEXT: Group 2:<br>
+; CHECK-NEXT: (Low: %c High: (78 + %c))<br>
+; CHECK-NEXT: Member: {(2 + %c),+,4}<br>
+; CHECK-NEXT: Member: {%c,+,4}<br>
+<br>
+define void @testh(i16* %a,<br>
+ i16* %b,<br>
+ i16* %c) {<br>
+entry:<br>
+ br label %for.body<br>
+<br>
+for.body: ; preds = %for.body, %entry<br>
+ %ind = phi i64 [ 0, %entry ], [ %add, %for.body ]<br>
+ %store_ind = phi i64 [ 0, %entry ], [ %store_ind_next, %for.body ]<br>
+<br>
+ %add = add nuw nsw i64 %ind, 1<br>
+ %store_ind_inc = add nuw nsw i64 %store_ind, 1<br>
+ %store_ind_next = add nuw nsw i64 %store_ind_inc, 1<br>
+<br>
+ %arrayidxA = getelementptr i16, i16* %a, i64 %ind<br>
+ %loadA = load i16, i16* %arrayidxA, align 2<br>
+<br>
+ %arrayidxA1 = getelementptr i16, i16* %a, i64 %add<br>
+ %loadA1 = load i16, i16* %arrayidxA1, align 2<br>
+<br>
+ %arrayidxB = getelementptr i16, i16* %b, i64 %ind<br>
+ %loadB = load i16, i16* %arrayidxB, align 2<br>
+<br>
+ %mul = mul i16 %loadA, %loadA1<br>
+ %mul1 = mul i16 %mul, %loadB<br>
+<br>
+ %arrayidxC = getelementptr inbounds i16, i16* %c, i64 %store_ind<br>
+ store i16 %mul1, i16* %arrayidxC, align 2<br>
+<br>
+ %arrayidxC1 = getelementptr inbounds i16, i16* %c, i64 %store_ind_inc<br>
+ store i16 %mul, i16* %arrayidxC1, align 2<br>
+<br>
+ %exitcond = icmp eq i64 %add, 20<br>
+ br i1 %exitcond, label %for.end, label %for.body<br>
<br>
for.end: ; preds = %for.body<br>
ret void<br>
<br>
Modified: llvm/trunk/test/Analysis/LoopAccessAnalysis/resort-to-memchecks-only.ll<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_test_Analysis_LoopAccessAnalysis_resort-2Dto-2Dmemchecks-2Donly.ll-3Frev-3D241673-26r1-3D241672-26r2-3D241673-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=uFcf0gLR_MIrQFYhuAb8gVsoNdftcSB1mZMezpDReAU&s=JOc5_PXhNth6VnQN3CEEvSTM90SHTXct7enPAEmHz7I&e=" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/LoopAccessAnalysis/resort-to-memchecks-only.ll?rev=241673&r1=241672&r2=241673&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/Analysis/LoopAccessAnalysis/resort-to-memchecks-only.ll (original)<br>
+++ llvm/trunk/test/Analysis/LoopAccessAnalysis/resort-to-memchecks-only.ll Wed Jul 8 04:16:33 2015<br>
@@ -15,7 +15,9 @@ target triple = "x86_64-apple-macosx10.1<br>
; CHECK-NEXT: Interesting Dependences:<br>
; CHECK-NEXT: Run-time memory checks:<br>
; CHECK-NEXT: 0:<br>
+; CHECK-NEXT: Comparing group<br>
; CHECK-NEXT: %arrayidxA2 = getelementptr inbounds i16, i16* %a, i64 %idx<br>
+; CHECK-NEXT: Against group<br>
; CHECK-NEXT: %arrayidxA = getelementptr inbounds i16, i16* %a, i64 %indvar<br>
<br>
@B = common global i16* null, align 8<br>
<br>
Modified: llvm/trunk/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks.ll<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_test_Analysis_LoopAccessAnalysis_unsafe-2Dand-2Drt-2Dchecks.ll-3Frev-3D241673-26r1-3D241672-26r2-3D241673-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=uFcf0gLR_MIrQFYhuAb8gVsoNdftcSB1mZMezpDReAU&s=YLQkgpXK7eq7uHA9rBwftq4p-U7welp1znOtw8VfhGI&e=" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks.ll?rev=241673&r1=241672&r2=241673&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks.ll (original)<br>
+++ llvm/trunk/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks.ll Wed Jul 8 04:16:33 2015<br>
@@ -14,10 +14,16 @@ target triple = "x86_64-apple-macosx10.1<br>
; CHECK-NEXT: store i16 %mul1, i16* %arrayidxA_plus_2, align 2<br>
; CHECK: Run-time memory checks:<br>
; CHECK-NEXT: 0:<br>
+; CHECK-NEXT: Comparing group<br>
+; CHECK-NEXT: %arrayidxA = getelementptr inbounds i16, i16* %a, i64 %storemerge3<br>
; CHECK-NEXT: %arrayidxA_plus_2 = getelementptr inbounds i16, i16* %a, i64 %add<br>
+; CHECK-NEXT: Against group<br>
; CHECK-NEXT: %arrayidxB = getelementptr inbounds i16, i16* %b, i64 %storemerge3<br>
; CHECK-NEXT: 1:<br>
+; CHECK-NEXT: Comparing group<br>
+; CHECK-NEXT: %arrayidxA = getelementptr inbounds i16, i16* %a, i64 %storemerge3<br>
; CHECK-NEXT: %arrayidxA_plus_2 = getelementptr inbounds i16, i16* %a, i64 %add<br>
+; CHECK-NEXT: Against group<br>
; CHECK-NEXT: %arrayidxC = getelementptr inbounds i16, i16* %c, i64 %storemerge3<br>
<br>
@B = common global i16* null, align 8<br>
<br>
Modified: llvm/trunk/test/Transforms/LoopDistribute/basic-with-memchecks.ll<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_test_Transforms_LoopDistribute_basic-2Dwith-2Dmemchecks.ll-3Frev-3D241673-26r1-3D241672-26r2-3D241673-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=uFcf0gLR_MIrQFYhuAb8gVsoNdftcSB1mZMezpDReAU&s=e-P3DrwxY7CSNu_j9MVwxJ2dBrtPl4pmQ_epAx9j5BY&e=" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LoopDistribute/basic-with-memchecks.ll?rev=241673&r1=241672&r2=241673&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/LoopDistribute/basic-with-memchecks.ll (original)<br>
+++ llvm/trunk/test/Transforms/LoopDistribute/basic-with-memchecks.ll Wed Jul 8 04:16:33 2015<br>
@@ -32,16 +32,14 @@ entry:<br>
%e = load i32*, i32** @E, align 8<br>
br label %for.body<br>
<br>
-; We have two compares for each array overlap check which is a total of 10<br>
-; compares.<br>
+; We have two compares for each array overlap check.<br>
+; Since the checks to A and A + 4 get merged, this will give us a<br>
+; total of 8 compares.<br>
;<br>
; CHECK: for.body.lver.memcheck:<br>
; CHECK: = icmp<br>
; CHECK: = icmp<br>
<br>
-; CHECK: = icmp<br>
-; CHECK: = icmp<br>
-<br>
; CHECK: = icmp<br>
; CHECK: = icmp<br>
<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu" target="_blank">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu" target="_blank">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div></blockquote></div>