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