return InstMap;
}
+ /// \brief Find the set of instructions that read or write via \p Ptr.
+ SmallVector<Instruction *, 4> getInstructionsForAccess(Value *Ptr,
+ bool isWrite) const;
+
private:
ScalarEvolution *SE;
const Loop *InnermostLoop;
/// \brief Decide whether we need to issue a run-time check for pointer at
/// index \p I and \p J to prove their independence.
- bool needsChecking(unsigned I, unsigned J) const;
+ ///
+ /// If \p PtrPartition is set, it contains the partition number for
+ /// pointers (-1 if the pointer belongs to multiple partitions). In this
+ /// case omit checks between pointers belonging to the same partition.
+ bool needsChecking(unsigned I, unsigned J,
+ const SmallVectorImpl<int> *PtrPartition) const;
/// \brief Print the list run-time memory checks necessary.
- void print(raw_ostream &OS, unsigned Depth = 0) const;
+ ///
+ /// If \p PtrPartition is set, it contains the partition number for
+ /// pointers (-1 if the pointer belongs to multiple partitions). In this
+ /// case omit checks between pointers belonging to the same partition.
+ void print(raw_ostream &OS, unsigned Depth = 0,
+ const SmallVectorImpl<int> *PtrPartition = nullptr) const;
/// This flag indicates if we need to add the runtime check.
bool Need;
/// Returns a pair of instructions where the first element is the first
/// instruction generated in possibly a sequence of instructions and the
/// second value is the final comparator value or NULL if no check is needed.
+ ///
+ /// If \p PtrPartition is set, it contains the partition number for pointers
+ /// (-1 if the pointer belongs to multiple partitions). In this case omit
+ /// checks between pointers belonging to the same partition.
std::pair<Instruction *, Instruction *>
- addRuntimeCheck(Instruction *Loc) const;
+ addRuntimeCheck(Instruction *Loc,
+ const SmallVectorImpl<int> *PtrPartition = nullptr) const;
/// \brief The diagnostics report generated for the analysis. E.g. why we
/// couldn't analyze the loop.
/// loop-independent and loop-carried dependences between memory accesses.
const MemoryDepChecker &getDepChecker() const { return DepChecker; }
+ /// \brief Return the list of instructions that use \p Ptr to read or write
+ /// memory.
+ SmallVector<Instruction *, 4> getInstructionsForAccess(Value *Ptr,
+ bool isWrite) const {
+ return DepChecker.getInstructionsForAccess(Ptr, isWrite);
+ }
+
/// \brief Print the information about the memory accesses in the loop.
void print(raw_ostream &OS, unsigned Depth = 0) const;
AliasSetId.push_back(ASId);
}
-bool LoopAccessInfo::RuntimePointerCheck::needsChecking(unsigned I,
- unsigned J) const {
+bool LoopAccessInfo::RuntimePointerCheck::needsChecking(
+ unsigned I, unsigned J, const SmallVectorImpl<int> *PtrPartition) const {
// No need to check if two readonly pointers intersect.
if (!IsWritePtr[I] && !IsWritePtr[J])
return false;
if (AliasSetId[I] != AliasSetId[J])
return false;
+ // If PtrPartition is set omit checks between pointers of the same partition.
+ // Partition number -1 means that the pointer is used in multiple partitions.
+ // In this case we can't omit the check.
+ if (PtrPartition && (*PtrPartition)[I] != -1 &&
+ (*PtrPartition)[I] == (*PtrPartition)[J])
+ return false;
+
return true;
}
-void LoopAccessInfo::RuntimePointerCheck::print(raw_ostream &OS,
- unsigned Depth) const {
+void LoopAccessInfo::RuntimePointerCheck::print(
+ raw_ostream &OS, unsigned Depth,
+ const SmallVectorImpl<int> *PtrPartition) const {
unsigned NumPointers = Pointers.size();
if (NumPointers == 0)
return;
unsigned N = 0;
for (unsigned I = 0; I < NumPointers; ++I)
for (unsigned J = I + 1; J < NumPointers; ++J)
- if (needsChecking(I, J)) {
+ if (needsChecking(I, J, PtrPartition)) {
OS.indent(Depth) << N++ << ":\n";
- OS.indent(Depth + 2) << *Pointers[I] << "\n";
- OS.indent(Depth + 2) << *Pointers[J] << "\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";
}
}
return SafeForVectorization;
}
+SmallVector<Instruction *, 4>
+MemoryDepChecker::getInstructionsForAccess(Value *Ptr, bool isWrite) const {
+ MemAccessInfo Access(Ptr, isWrite);
+ auto &IndexVector = Accesses.find(Access)->second;
+
+ SmallVector<Instruction *, 4> Insts;
+ std::transform(IndexVector.begin(), IndexVector.end(),
+ std::back_inserter(Insts),
+ [&](unsigned Idx) { return this->InstMap[Idx]; });
+ return Insts;
+}
+
const char *MemoryDepChecker::Dependence::DepName[] = {
"NoDep", "Unknown", "Forward", "ForwardButPreventsForwarding", "Backward",
"BackwardVectorizable", "BackwardVectorizableButPreventsForwarding"};
return nullptr;
}
-std::pair<Instruction *, Instruction *>
-LoopAccessInfo::addRuntimeCheck(Instruction *Loc) const {
+std::pair<Instruction *, Instruction *> LoopAccessInfo::addRuntimeCheck(
+ Instruction *Loc, const SmallVectorImpl<int> *PtrPartition) const {
Instruction *tnullptr = nullptr;
if (!PtrRtCheck.Need)
return std::pair<Instruction *, Instruction *>(tnullptr, tnullptr);
Value *MemoryRuntimeCheck = nullptr;
for (unsigned i = 0; i < NumPointers; ++i) {
for (unsigned j = i+1; j < NumPointers; ++j) {
- if (!PtrRtCheck.needsChecking(i, j))
+ if (!PtrRtCheck.needsChecking(i, j, PtrPartition))
continue;
unsigned AS0 = Starts[i]->getType()->getPointerAddressSpace();