using InvariantAccessesTy = SmallVector<InvariantAccess, 8>;
/// @brief Type for equivalent invariant accesses and their domain context.
-///
-/// The first element is the SCEV for the pointer/location that identifies this
-/// equivalence class. The second is a list of memory accesses to that location
-/// that are now treated as invariant and hoisted during code generation. The
-/// third element is the execution context under which the invariant memory
-/// location is accessed, hence the union of all domain contexts for the memory
-/// accesses in the list. The last element describes the type of the invariant
-/// access in order to differentiate between different typed invariant loads of
-/// the same location.
-using InvariantEquivClassTy =
- std::tuple<const SCEV *, MemoryAccessList, isl_set *, Type *>;
+struct InvariantEquivClassTy {
+
+ /// The pointer that identifies this equivalence class
+ const SCEV *IdentifyingPointer;
+
+ /// Memory accesses now treated invariant
+ ///
+ /// These memory accesses access the pointer location that identifies
+ /// this equivalence class. They are treated as invariant and hoisted during
+ /// code generation.
+ MemoryAccessList InvariantAccesses;
+
+ /// The execution context under which the memory location is accessed
+ ///
+ /// It is the union of the execution domains of the memory accesses in the
+ /// InvariantAccesses list.
+ isl_set *ExecutionContext;
+
+ /// The type of the invariant access
+ ///
+ /// It is used to differentiate between differently typed invariant loads from
+ /// the same location.
+ Type *Type;
+};
/// @brief Type for invariant accesses equivalence classes.
using InvariantEquivClassesTy = SmallVector<InvariantEquivClassTy, 8>;
}
ClassRep = LInst;
- InvariantEquivClasses.emplace_back(PointerSCEV, MemoryAccessList(), nullptr,
- Ty);
+ InvariantEquivClasses.emplace_back(
+ InvariantEquivClassTy{PointerSCEV, MemoryAccessList(), nullptr, Ty});
}
}
}
for (const auto &IAClass : InvariantEquivClasses)
- isl_set_free(std::get<2>(IAClass));
+ isl_set_free(IAClass.ExecutionContext);
// Explicitly release all Scop objects and the underlying isl objects before
// we relase the isl context.
Type *Ty = LInst->getType();
const SCEV *PointerSCEV = SE->getSCEV(LInst->getPointerOperand());
for (auto &IAClass : InvariantEquivClasses) {
- if (PointerSCEV != std::get<0>(IAClass) || Ty != std::get<3>(IAClass))
+ if (PointerSCEV != IAClass.IdentifyingPointer || Ty != IAClass.Type)
continue;
- auto &MAs = std::get<1>(IAClass);
+ auto &MAs = IAClass.InvariantAccesses;
for (auto *MA : MAs)
if (MA->getAccessInstruction() == Val)
return &IAClass;
bool Consolidated = false;
for (auto &IAClass : InvariantEquivClasses) {
- if (PointerSCEV != std::get<0>(IAClass) || Ty != std::get<3>(IAClass))
+ if (PointerSCEV != IAClass.IdentifyingPointer || Ty != IAClass.Type)
continue;
// If the pointer and the type is equal check if the access function wrt.
// parameter values and these can be different for distinct part of the
// SCoP. If this happens we cannot consolidate the loads but need to
// create a new invariant load equivalence class.
- auto &MAs = std::get<1>(IAClass);
+ auto &MAs = IAClass.InvariantAccesses;
if (!MAs.empty()) {
auto *LastMA = MAs.front();
Consolidated = true;
// Unify the execution context of the class and this statement.
- isl_set *&IAClassDomainCtx = std::get<2>(IAClass);
+ isl_set *&IAClassDomainCtx = IAClass.ExecutionContext;
if (IAClassDomainCtx)
IAClassDomainCtx =
isl_set_coalesce(isl_set_union(IAClassDomainCtx, MACtx));
// If we did not consolidate MA, thus did not find an equivalence class
// for it, we create a new one.
- InvariantEquivClasses.emplace_back(PointerSCEV, MemoryAccessList{MA}, MACtx,
- Ty);
+ InvariantEquivClasses.emplace_back(
+ InvariantEquivClassTy{PointerSCEV, MemoryAccessList{MA}, MACtx, Ty});
}
isl_set_free(DomainCtx);
OS.indent(4) << "Max Loop Depth: " << getMaxLoopDepth() << "\n";
OS.indent(4) << "Invariant Accesses: {\n";
for (const auto &IAClass : InvariantEquivClasses) {
- const auto &MAs = std::get<1>(IAClass);
+ const auto &MAs = IAClass.InvariantAccesses;
if (MAs.empty()) {
- OS.indent(12) << "Class Pointer: " << *std::get<0>(IAClass) << "\n";
+ OS.indent(12) << "Class Pointer: " << *IAClass.IdentifyingPointer << "\n";
} else {
MAs.front()->print(OS);
- OS.indent(12) << "Execution Context: " << std::get<2>(IAClass) << "\n";
+ OS.indent(12) << "Execution Context: " << IAClass.ExecutionContext
+ << "\n";
}
}
OS.indent(4) << "}\n";
// Check if this invariant access class is empty, hence if we never
// actually added a loads instruction to it. In that case it has no
// (meaningful) users and we should not try to code generate it.
- if (std::get<1>(*IAClass).empty())
+ if (IAClass->InvariantAccesses.empty())
V = UndefValue::get(ParamSCEV->getType());
if (!preloadInvariantEquivClass(*IAClass)) {
// element with the unified execution context. However, we have to map all
// elements of the class to the one preloaded load as they are referenced
// during the code generation and therefor need to be mapped.
- const MemoryAccessList &MAs = std::get<1>(IAClass);
+ const MemoryAccessList &MAs = IAClass.InvariantAccesses;
if (MAs.empty())
return true;
// Check for recurrsion which can be caused by additional constraints, e.g.,
// non-finitie loop contraints. In such a case we have to bail out and insert
// a "false" runtime check that will cause the original code to be executed.
- auto PtrId = std::make_pair(std::get<0>(IAClass), std::get<3>(IAClass));
+ auto PtrId = std::make_pair(IAClass.IdentifyingPointer, IAClass.Type);
if (!PreloadedPtrs.insert(PtrId).second)
return false;
// The exectution context of the IAClass.
- isl_set *&ExecutionCtx = std::get<2>(IAClass);
+ isl_set *&ExecutionCtx = IAClass.ExecutionContext;
// If the base pointer of this class is dependent on another one we have to
// make sure it was preloaded already.
// After we preloaded the BaseIAClass we adjusted the BaseExecutionCtx and
// we need to refine the ExecutionCtx.
- isl_set *BaseExecutionCtx = isl_set_copy(std::get<2>(*BaseIAClass));
+ isl_set *BaseExecutionCtx = isl_set_copy(BaseIAClass->ExecutionContext);
ExecutionCtx = isl_set_intersect(ExecutionCtx, BaseExecutionCtx);
}