17#include "llvm/ADT/ArrayRef.h"
18#include "llvm/ADT/DenseSet.h"
19#include "llvm/ADT/Sequence.h"
20#include "llvm/ADT/SetOperations.h"
21#include "llvm/ADT/SmallVector.h"
22#include "llvm/ADT/StringRef.h"
23#include "llvm/ADT/iterator_range.h"
24#include "llvm/Analysis/TargetTransformInfo.h"
25#include "llvm/IR/DataLayout.h"
26#include "llvm/IR/Function.h"
27#include "llvm/IR/Module.h"
28#include "llvm/Support/CommandLine.h"
29#include "llvm/Support/Debug.h"
30#include "llvm/Support/TypeSize.h"
31#include "llvm/Support/raw_ostream.h"
45#define DEBUG_TYPE "polly-opt-isl"
55 "polly-target-latency-vector-fma",
56 cl::desc(
"The minimal number of cycles between issuing two "
57 "dependent consecutive vector fused multiply-add "
62 "polly-target-throughput-vector-fma",
63 cl::desc(
"A throughput of the processor floating-point arithmetic units "
64 "expressed in the number of vector fused multiply-add "
65 "instructions per clock cycle."),
69 "polly-target-1st-cache-level-size",
70 cl::desc(
"The size of the first cache level specified in bytes."),
74 "polly-target-1st-cache-level-default-size",
75 cl::desc(
"The default size of the first cache level specified in bytes"
76 " (if not enough were provided by the TargetTransformInfo)."),
80 "polly-target-2nd-cache-level-size",
81 cl::desc(
"The size of the second level specified in bytes."), cl::Hidden,
85 "polly-target-2nd-cache-level-default-size",
86 cl::desc(
"The default size of the second cache level specified in bytes"
87 " (if not enough were provided by the TargetTransformInfo)."),
98 "polly-target-1st-cache-level-associativity",
99 cl::desc(
"The associativity of the first cache level."), cl::Hidden,
103 "polly-target-1st-cache-level-default-associativity",
104 cl::desc(
"The default associativity of the first cache level"
105 " (if not enough were provided by the TargetTransformInfo)."),
109 "polly-target-2nd-cache-level-associativity",
110 cl::desc(
"The associativity of the second cache level."), cl::Hidden,
114 "polly-target-2nd-cache-level-default-associativity",
115 cl::desc(
"The default associativity of the second cache level"
116 " (if not enough were provided by the TargetTransformInfo)."),
120 "polly-target-vector-register-bitwidth",
121 cl::desc(
"The size in bits of a vector register (if not set, this "
122 "information is taken from LLVM's target information."),
126 "polly-pattern-matching-nc-quotient",
127 cl::desc(
"Quotient that is obtained by dividing Nc, the parameter of the"
128 "macro-kernel, by Nr, the parameter of the micro-kernel"),
132 "polly-pattern-matching-max-stack-array-size",
133 cl::desc(
"The maximal size in bytes of a packed array of the matrix "
134 "multiplication optimization that is allocated on the stack; "
135 "larger ones are allocated on the heap (-1: all on the stack, "
136 "0: all on the heap)"),
141 cl::desc(
"Perform optimizations of tensor contractions based "
142 "on pattern matching"),
147 cl::desc(
"Perform optimizations of matrix multiplications "
148 "based on pattern matching"),
152 "polly-tc-dependences-computeout",
153 cl::desc(
"Bound the dependence analysis by a maximal amount of "
154 "computational steps (0 means no bound)"),
162struct MicroKernelParamsTy {
171struct MacroKernelParamsTy {
182 MemoryAccess *
A =
nullptr;
183 MemoryAccess *
B =
nullptr;
184 MemoryAccess *ReadFromC =
nullptr;
185 MemoryAccess *WriteToC =
nullptr;
225 MemoryAccess *
A =
nullptr;
226 MemoryAccess *
B =
nullptr;
232 MemoryAccess *ReadFromC =
nullptr;
233 MemoryAccess *WriteToC =
nullptr;
239 SmallDenseSet<int> I;
240 SmallDenseSet<int> J;
245 SmallDenseSet<int> P;
253 SmallVector<int> DimensionSizes;
254 SmallVector<int> ADimensions;
255 SmallVector<int> BDimensions;
256 SmallVector<int> CDimensions;
262 SmallVector<int> OrderedI;
263 SmallVector<int> OrderedJ;
264 SmallVector<int> OrderedP;
272static isl::union_set getUnrollIsolatedSetOptions(isl::ctx
Ctx) {
273 isl::space Space = isl::space(
Ctx, 0, 0, 1);
277 UnrollIsolatedSetOption =
278 UnrollIsolatedSetOption.set_tuple_id(
isl::dim::in, DimInId);
279 UnrollIsolatedSetOption =
280 UnrollIsolatedSetOption.set_tuple_id(
isl::dim::out, DimOutId);
281 return UnrollIsolatedSetOption.
wrap();
294static isl::map permuteDimensions(isl::map Map,
isl::dim DimType,
295 unsigned DstPos,
unsigned SrcPos) {
298 if (DstPos == SrcPos)
301 if (Map.has_tuple_id(DimType))
302 DimId = Map.get_tuple_id(DimType);
305 if (Map.has_tuple_id(FreeDim))
306 FreeDimId = Map.get_tuple_id(FreeDim);
307 auto MaxDim = std::max(DstPos, SrcPos);
308 auto MinDim = std::min(DstPos, SrcPos);
309 Map = Map.move_dims(FreeDim, 0, DimType, MaxDim, 1);
310 Map = Map.move_dims(FreeDim, 0, DimType, MinDim, 1);
311 Map = Map.move_dims(DimType, MinDim, FreeDim, 1, 1);
312 Map = Map.move_dims(DimType, MaxDim, FreeDim, 0, 1);
314 Map = Map.set_tuple_id(DimType, DimId);
316 Map = Map.set_tuple_id(FreeDim, FreeDimId);
332static bool isMatMulOperandAcc(
isl::set Domain, isl::map AccMap,
int &FirstPos,
347 int FirstDims[] = {0, 0, 1, 1, 2, 2};
348 int SecondDims[] = {1, 2, 2, 0, 0, 1};
349 for (
int i = 0; i < 6; i += 1) {
350 auto PossibleMatMul =
362 if (AccMap.
is_equal(PossibleMatMul)) {
363 if (FirstPos != -1 && FirstPos != FirstDims[i])
365 FirstPos = FirstDims[i];
366 if (SecondPos != -1 && SecondPos != SecondDims[i])
368 SecondPos = SecondDims[i];
387static bool isMatMulNonScalarReadAccess(MemoryAccess *MemAccess,
393 if (isMatMulOperandAcc(StmtDomain, AccMap, MMI.i, MMI.j) && !MMI.ReadFromC) {
394 MMI.ReadFromC = MemAccess;
397 if (isMatMulOperandAcc(StmtDomain, AccMap, MMI.i, MMI.k) && !MMI.A) {
401 if (isMatMulOperandAcc(StmtDomain, AccMap, MMI.k, MMI.j) && !MMI.B) {
421static bool containsOnlyMatrMultAcc(isl::map PartialSchedule,
423 auto InputDimId = PartialSchedule.get_tuple_id(
isl::dim::in);
424 auto *Stmt =
static_cast<ScopStmt *
>(InputDimId.get_user());
426 assert(OutDimNum > 2 &&
"In case of the matrix multiplication the loop nest "
427 "and, consequently, the corresponding scheduling "
428 "functions have at least three dimensions.");
430 permuteDimensions(PartialSchedule,
isl::dim::out, MMI.i, OutDimNum - 1);
432 permuteDimensions(PartialSchedule,
isl::dim::out, MMI.j, OutDimNum - 1);
434 permuteDimensions(PartialSchedule,
isl::dim::out, MMI.k, OutDimNum - 1);
437 for (
auto *MemA = Accesses.begin(); MemA != Accesses.end() - 1; MemA++) {
438 auto *MemAccessPtr = *MemA;
439 if (MemAccessPtr->isLatestArrayKind() && MemAccessPtr != MMI.WriteToC &&
440 !isMatMulNonScalarReadAccess(MemAccessPtr, MMI) &&
441 !(MemAccessPtr->isStrideZero(MapI) &&
442 MemAccessPtr->isStrideZero(MapJ) && MemAccessPtr->isStrideZero(MapK)))
462static bool containsOnlyMatMulDep(isl::map Schedule,
const Dependences *D,
467 Dep = Dep.
unite(Red);
469 auto Space = DomainSpace.map_from_domain_and_range(DomainSpace);
472 for (
int i = 0; i < DeltasDimNum; i++) {
474 Pos = Pos < 0 && Val.is_one() ? i : Pos;
475 if (Val.is_nan() || !(Val.is_zero() || (i == Pos && Val.is_one())))
478 if (DeltasDimNum == 0 || Pos < 0)
506static bool containsMatrMult(isl::map PartialSchedule,
const Dependences *D,
508 auto InputDimsId = PartialSchedule.get_tuple_id(
isl::dim::in);
509 auto *Stmt =
static_cast<ScopStmt *
>(InputDimsId.get_user());
510 if (Stmt->size() <= 1)
514 for (
auto *MemA = Accesses.end() - 1; MemA != Accesses.begin(); MemA--) {
515 auto *MemAccessPtr = *MemA;
516 if (!MemAccessPtr->isLatestArrayKind())
518 if (!MemAccessPtr->isWrite())
520 auto AccMap = MemAccessPtr->getLatestAccessRelation();
521 if (!isMatMulOperandAcc(Stmt->getDomain(), AccMap, MMI.i, MMI.j))
523 MMI.WriteToC = MemAccessPtr;
527 if (!containsOnlyMatMulDep(PartialSchedule, D, MMI.k))
530 if (!MMI.WriteToC || !containsOnlyMatrMultAcc(PartialSchedule, MMI))
533 if (!MMI.A || !MMI.B || !MMI.ReadFromC)
545static isl::schedule_node permuteBandNodeDimensions(isl::schedule_node Node,
547 unsigned SecondDim) {
550 std::max(FirstDim, SecondDim));
551 auto PartialSchedule =
553 auto PartialScheduleFirstDim = PartialSchedule.at(FirstDim);
554 auto PartialScheduleSecondDim = PartialSchedule.at(SecondDim);
556 PartialSchedule.set_union_pw_aff(SecondDim, PartialScheduleFirstDim);
558 PartialSchedule.set_union_pw_aff(FirstDim, PartialScheduleSecondDim);
563static isl::schedule_node
564createMicroKernel(isl::schedule_node Node,
565 MicroKernelParamsTy MicroKernelParams) {
569 return permuteBandNodeDimensions(Node, 0, 1).
child(0).
child(0);
582static isl::schedule_node
583createMacroKernel(isl::schedule_node Node,
584 MacroKernelParamsTy MacroKernelParams) {
586 if (MacroKernelParams.Mc == 1 && MacroKernelParams.Nc == 1 &&
587 MacroKernelParams.Kc == 1)
590 std::vector<int> TileSizes(DimOutNum, 1);
591 TileSizes[DimOutNum - 3] = MacroKernelParams.Mc;
592 TileSizes[DimOutNum - 2] = MacroKernelParams.Nc;
593 TileSizes[DimOutNum - 1] = MacroKernelParams.Kc;
594 Node =
tileNode(Node,
"1st level tiling", TileSizes, 1);
596 Node = permuteBandNodeDimensions(Node, DimOutNum - 2, DimOutNum - 1);
597 Node = permuteBandNodeDimensions(Node, DimOutNum - 3, DimOutNum - 1);
608static uint64_t getMatMulAlignTypeSize(
const MatMulInfoTy &MMI) {
610 auto &DL =
S->
getFunction().getParent()->getDataLayout();
613 auto ElementSizeC = DL.getTypeAllocSize(MMI.WriteToC->
getElementType());
614 return std::max({ElementSizeA, ElementSizeB, ElementSizeC});
623static uint64_t getMatMulTypeSize(
const MatMulInfoTy &MMI) {
625 auto &DL =
S->
getFunction().getParent()->getDataLayout();
626 auto ElementSizeA = DL.getTypeSizeInBits(MMI.A->
getElementType());
627 auto ElementSizeB = DL.getTypeSizeInBits(MMI.B->
getElementType());
628 auto ElementSizeC = DL.getTypeSizeInBits(MMI.WriteToC->
getElementType());
629 return std::max({ElementSizeA, ElementSizeB, ElementSizeC});
644static MicroKernelParamsTy getMicroKernelParams(
const TargetTransformInfo *TTI,
645 const MatMulInfoTy &MMI) {
646 assert(TTI &&
"The target transform info should be provided.");
652 if (RegisterBitwidth == -1)
654 TTI->getRegisterBitWidth(TargetTransformInfo::RGK_FixedWidthVector);
655 auto ElementSize = getMatMulTypeSize(MMI);
656 assert(ElementSize > 0 &&
"The element size of the matrix multiplication "
657 "operands should be greater than zero.");
658 auto Nvec = RegisterBitwidth / ElementSize;
671static void getTargetCacheParameters(
const llvm::TargetTransformInfo *TTI) {
672 auto L1DCache = llvm::TargetTransformInfo::CacheLevel::L1D;
673 auto L2DCache = llvm::TargetTransformInfo::CacheLevel::L2D;
675 if (TTI->getCacheSize(L1DCache))
681 if (TTI->getCacheSize(L2DCache))
687 if (TTI->getCacheAssociativity(L1DCache))
689 TTI->getCacheAssociativity(L1DCache).value();
695 if (TTI->getCacheAssociativity(L2DCache))
697 TTI->getCacheAssociativity(L2DCache).value();
719static MacroKernelParamsTy
720getMacroKernelParams(
const llvm::TargetTransformInfo *TTI,
721 const MicroKernelParamsTy &MicroKernelParams,
722 const MatMulInfoTy &MMI) {
723 getTargetCacheParameters(TTI);
729 if (!(MicroKernelParams.Mr > 0 && MicroKernelParams.Nr > 0 &&
738 (1 +
static_cast<double>(MicroKernelParams.Nr) / MicroKernelParams.Mr));
747 auto ElementSize = getMatMulAlignTypeSize(MMI);
748 assert(ElementSize > 0 &&
"The element size of the matrix multiplication "
749 "operands should be greater than zero.");
758 assert(Mc > 0 && Nc > 0 && Kc > 0 &&
759 "Matrix block sizes should be greater than zero");
789static isl::map getMatMulAccRel(isl::map MapOldIndVar,
unsigned FirstDim,
790 unsigned SecondDim) {
791 auto AccessRelSpace = isl::space(MapOldIndVar.
ctx(), 0, 9, 3);
799static isl::schedule_node createExtensionNode(isl::schedule_node Node,
800 isl::map ExtensionMap) {
801 auto Extension = isl::union_map(ExtensionMap);
810static void setPackedArrayAllocation(ScopArrayInfo *SAI,
811 ArrayRef<unsigned> DimSizes) {
813 for (
unsigned DimSize : DimSizes)
819static isl::schedule_node optimizePackedB(isl::schedule_node Node,
820 ScopStmt *Stmt, isl::map MapOldIndVar,
821 MicroKernelParamsTy MicroParams,
822 MacroKernelParamsTy MacroParams,
828 unsigned FirstDimSize = MacroParams.Nc / MicroParams.Nr;
829 unsigned SecondDimSize = MacroParams.Kc;
830 unsigned ThirdDimSize = MicroParams.Nr;
831 ScopArrayInfo *PackedB =
833 {FirstDimSize, SecondDimSize, ThirdDimSize});
834 setPackedArrayAllocation(PackedB,
835 {FirstDimSize, SecondDimSize, ThirdDimSize});
839 isl::map AccRelPackedB = getMatMulAccRel(MapOldIndVar, 3, 7);
844 ScopStmt *CopyStmt =
S->addScopStmt(AccRelB, AccRelPackedB,
Domain);
850 isl::map ExtMap = MapOldIndVar.project_out(
isl::dim::out, 2, Dim - 2);
855 return createExtensionNode(Node, ExtMap);
858static isl::schedule_node optimizePackedA(isl::schedule_node Node, ScopStmt *,
859 isl::map MapOldIndVar,
860 MicroKernelParamsTy MicroParams,
861 MacroKernelParamsTy MacroParams,
863 isl::id InputDimsId = MapOldIndVar.get_tuple_id(
isl::dim::in);
864 ScopStmt *Stmt =
static_cast<ScopStmt *
>(InputDimsId.get_user());
866 isl::id DomainId =
Domain.get_tuple_id();
869 unsigned FirstDimSize = MacroParams.Mc / MicroParams.Mr;
870 unsigned SecondDimSize = MacroParams.Kc;
871 unsigned ThirdDimSize = MicroParams.Mr;
874 {FirstDimSize, SecondDimSize, ThirdDimSize});
875 setPackedArrayAllocation(PackedA,
876 {FirstDimSize, SecondDimSize, ThirdDimSize});
880 isl::map AccRelPackedA = getMatMulAccRel(MapOldIndVar, 4, 6);
884 isl::map PackedATranslator = AccRelPackedA.
apply_domain(AccRelA);
893 isl::map OuterDomainMap =
898 isl::map DomainTranslator = OuterDomainMap.
range_product(CopyFrom);
906 isl::map CopyTo = CopyFrom.
apply_range(PackedATranslator);
916 ExtScatterCopy = ExtScatterCopy.project_out(
isl::dim::in, 3, 2);
917 return createExtensionNode(Node, ExtScatterCopy);
952static isl::schedule_node
953optimizeDataLayoutMatrMulPattern(isl::schedule_node Node, isl::map MapOldIndVar,
954 MicroKernelParamsTy MicroParams,
955 MacroKernelParamsTy MacroParams,
957 isl::id InputDimsId = MapOldIndVar.get_tuple_id(
isl::dim::in);
958 ScopStmt *Stmt =
static_cast<ScopStmt *
>(InputDimsId.get_user());
963 Node = Node.
child(0);
965 optimizePackedB(Node, Stmt, MapOldIndVar, MicroParams, MacroParams, MMI);
967 Node = Node.
child(0);
969 optimizePackedA(Node, Stmt, MapOldIndVar, MicroParams, MacroParams, MMI);
987getInductionVariablesSubstitution(isl::schedule_node Node,
988 MicroKernelParamsTy MicroKernelParams,
989 MacroKernelParamsTy MacroKernelParams) {
990 auto Child = Node.
child(0);
1013static isl::schedule_node
1014isolateAndUnrollMatMulInnerLoops(isl::schedule_node Node,
1015 MicroKernelParamsTy MicroKernelParams) {
1016 isl::schedule_node Child = Node.
child(0);
1017 isl::union_map UnMapOldIndVar = Child.get_prefix_schedule_relation();
1025 isl::union_set IsolateOption =
1027 isl::ctx
Ctx = Node.
ctx();
1029 Options = Options.
unite(getUnrollIsolatedSetOptions(
Ctx));
1030 Node = Node.
as<isl::schedule_node_band>().set_ast_build_options(Options);
1034 Node = Node.
as<isl::schedule_node_band>().set_ast_build_options(Options);
1043static isl::schedule_node markLoopVectorizerDisabled(isl::schedule_node Node) {
1056static isl::schedule_node
1057getBandNodeWithOriginDimOrder(isl::schedule_node Node) {
1061 auto Domain = Node.get_universe_domain();
1063 if (Node.get_schedule_depth().
release() != 0 ||
1068 auto PartialSchedulePwAff =
Domain.identity_union_pw_multi_aff();
1069 auto PartialScheduleMultiPwAff =
1070 isl::multi_union_pw_aff(PartialSchedulePwAff);
1071 PartialScheduleMultiPwAff =
1076static isl::schedule_node optimizeMatMulPattern(isl::schedule_node Node,
1077 const TargetTransformInfo *TTI,
1078 MatMulInfoTy &MMI) {
1079 assert(TTI &&
"The target transform info should be provided.");
1081 assert(DimOutNum > 2 &&
"In case of the matrix multiplication the loop nest "
1082 "and, consequently, the corresponding scheduling "
1083 "functions have at least three dimensions.");
1084 Node = getBandNodeWithOriginDimOrder(Node);
1085 Node = permuteBandNodeDimensions(Node, MMI.i, DimOutNum - 3);
1086 int NewJ = MMI.j == DimOutNum - 3 ? MMI.i : MMI.j;
1087 int NewK = MMI.k == DimOutNum - 3 ? MMI.i : MMI.k;
1088 Node = permuteBandNodeDimensions(Node, NewJ, DimOutNum - 2);
1089 NewK = NewK == DimOutNum - 2 ? NewJ : NewK;
1090 Node = permuteBandNodeDimensions(Node, NewK, DimOutNum - 1);
1091 auto MicroKernelParams = getMicroKernelParams(TTI, MMI);
1092 auto MacroKernelParams = getMacroKernelParams(TTI, MicroKernelParams, MMI);
1093 Node = createMacroKernel(Node, MacroKernelParams);
1094 Node = createMicroKernel(Node, MicroKernelParams);
1095 if (MacroKernelParams.Mc == 1 || MacroKernelParams.Nc == 1 ||
1096 MacroKernelParams.Kc == 1)
1098 auto MapOldIndVar = getInductionVariablesSubstitution(Node, MicroKernelParams,
1102 Node = markLoopVectorizerDisabled(Node.
parent()).
child(0);
1103 Node = isolateAndUnrollMatMulInnerLoops(Node, MicroKernelParams);
1104 return optimizeDataLayoutMatrMulPattern(Node, MapOldIndVar, MicroKernelParams,
1105 MacroKernelParams, MMI);
1128static bool isMatrMultPattern(isl::schedule_node Node,
const Dependences *D,
1129 MatMulInfoTy &MMI) {
1133 Node.get_schedule_depth().
release() != 0 ||
1137 if (containsMatrMult(NewPartialSchedule, D, MMI))
1151static int getDimSize(
const ScopArrayInfo *SAI,
unsigned Pos) {
1156 auto *ConstantDimSize = dyn_cast<const SCEVConstant>(SCEVDimSize);
1158 auto *IntDimSize = dyn_cast<ConstantInt>(ConstantDimSize->getValue());
1160 return IntDimSize->getSExtValue();
1174 ArrayRef<int> Dimensions) {
1184 for (
unsigned i = 0; i < Dimensions.size(); i++) {
1185 const int InPos = Dimensions[i];
1186 if ((InPos >=
static_cast<int>(DimInSize)) || (InPos < 0))
1198 return AccMap.
is_equal(PossibleTensor);
1215 SmallDenseSet<int> &IndexSet,
1216 SmallVectorImpl<int> &DimensionSizes,
1217 SmallVectorImpl<int> &Dimensions) {
1220 assert(SAI &&
"AccMap should represent memory access");
1241 for (
unsigned i = 0; i < OutDimNum; i++)
1245 Dimensions.assign(OutDimNum, -1);
1252 if (ValAPInt.isSignedIntN(32))
1253 OutPos = ValAPInt.getSExtValue();
1254 if ((OutPos < 0) || (OutPos >=
static_cast<int>(OutDimNum)) ||
1258 Dimensions[OutPos] = i;
1259 if (DimensionSizes[i] <= 0)
1260 DimensionSizes[i] = getDimSize(SAI, OutPos);
1263 return isCorrectAccessMap(
Domain, AccMap, Dimensions);
1272static SmallDenseSet<int>
intersect(
const SmallDenseSet<int> &
A,
1273 const SmallDenseSet<int> &
B) {
1274 SmallDenseSet<int> Intersection =
A;
1275 set_intersect(Intersection,
B);
1276 return Intersection;
1285static bool isSuperset(
const SmallDenseSet<int> &
A,
1286 const SmallDenseSet<int> &
B) {
1296static SmallDenseSet<int> unite(
const SmallDenseSet<int> &
A,
1297 const SmallDenseSet<int> &
B) {
1298 SmallDenseSet<int> Union =
A;
1299 set_union(Union,
B);
1312static MemoryAccess *getWriteAccess(
isl::set Domain, ScopStmt *Stmt,
1314 SmallDenseSet<int> &IandJIndexSet) {
1315 TCI.WriteToC =
nullptr;
1317 for (MemoryAccess *MemA : reverse(Accesses)) {
1319 if (!MemA->isLatestArrayKind())
1322 if (!MemA->isWrite())
1325 isl::map AccMap = MemA->getLatestAccessRelation();
1326 if (!isTCOperandAcc(
Domain, AccMap, IandJIndexSet, TCI.DimensionSizes,
1345static bool setReadAccess(MemoryAccess *MemAccessPtr,
1346 const SmallDenseSet<int> &IndexSet,
1347 const SmallDenseSet<int> &IandJIndexSet,
1348 ArrayRef<int> Dimensions, TCInfoTy &TCI) {
1351 if (!isSuperset(IndexSet, TCI.P))
1355 TCI.I = set_difference(IndexSet, TCI.P);
1356 if (!isSuperset(IandJIndexSet, TCI.I))
1360 TCI.J = set_difference(IandJIndexSet, TCI.I);
1363 TCI.A = MemAccessPtr;
1364 llvm::replace(TCI.ADimensions, TCI.ADimensions.begin(),
1365 TCI.ADimensions.end(), Dimensions.begin(), Dimensions.end());
1371 if (unite(TCI.P, TCI.J) != IndexSet)
1375 TCI.B = MemAccessPtr;
1376 llvm::replace(TCI.BDimensions, TCI.BDimensions.begin(),
1377 TCI.BDimensions.end(), Dimensions.begin(), Dimensions.end());
1394static bool setReadAccesses(
isl::set Domain, ScopStmt *Stmt, TCInfoTy &TCI,
1395 SmallDenseSet<int> &IandJIndexSet) {
1398 TCI.ReadFromC =
nullptr;
1400 for (
auto *MemA = Accesses.begin(); *MemA != TCI.WriteToC; MemA++) {
1401 MemoryAccess *MemAccessPtr = *MemA;
1423 TCI.ReadFromC = MemAccessPtr;
1427 SmallVector<int> Dimensions;
1428 SmallDenseSet<int> IndexSet;
1429 if (!isTCOperandAcc(
Domain, AccMap, IndexSet, TCI.DimensionSizes,
1433 if (!setReadAccess(MemAccessPtr, IndexSet, IandJIndexSet, Dimensions, TCI))
1439 return TCI.ReadFromC && TCI.A && TCI.B;
1454static bool containsOnlyTCAcc(
isl::set Domain, isl::map PartialSchedule,
1456 isl::id InputDimsId = PartialSchedule.get_tuple_id(
isl::dim::in);
1457 ScopStmt *Stmt =
static_cast<ScopStmt *
>(InputDimsId.get_user());
1465 TCI.DimensionSizes.resize(DimNum);
1466 SmallDenseSet<int> IandJIndexSet;
1468 TCI.WriteToC = getWriteAccess(
Domain, Stmt, TCI, IandJIndexSet);
1472 if (
intersect(IandJIndexSet, TCI.P).size() != 0)
1475 if (!setReadAccesses(
Domain, Stmt, TCI, IandJIndexSet))
1503static bool isReductionCarriedOverDim(
isl::set DepDelta,
unsigned Dim,
1504 isl::pw_multi_aff BoundDeltas,
1505 const SmallDenseSet<int> &IndexSet) {
1506 isl::space Space = DepDelta.
get_space();
1508 for (
unsigned i = 0; i < Dim; i += 1)
1527 if (!IndexSet.count(i)) {
1530 if (DepDelta.plain_get_val_if_fixed(
isl::dim::set, i).is_zero())
1539 if (!Complement.plain_get_val_if_fixed(
isl::dim::set, i).is_zero())
1589static bool areDepsOverCompleteDomain(
isl::set Domain, isl::map DepsForStmt,
1590 isl::pw_multi_aff UpperBound,
1591 SmallDenseSet<int> &IndexSet) {
1596 for (
const auto It : IndexSet) {
1597 isl::val FixedVal = UpperBoundSet.plain_get_val_if_fixed(
isl::dim::set, It);
1604 Domain.subtract(DomainRed));
1624static bool containsOnlyTcDeps(isl::map Schedule,
const Dependences *D,
1628 isl::union_map Dep =
1632 isl::space Space = DomainSpace.map_from_domain_and_range(DomainSpace);
1636 isl::pw_multi_aff LowerBound =
Domain.lexmin_pw_multi_aff();
1637 isl::pw_multi_aff UpperBound =
Domain.lexmax_pw_multi_aff();
1638 isl::pw_multi_aff BoundDeltas = UpperBound.
sub(LowerBound);
1648 if (!isReductionCarriedOverDim(Intersection, i, BoundDeltas, IndexSet))
1652 DepDeltas = DepDeltas.
subtract(Intersection);
1660 return areDepsOverCompleteDomain(
Domain, DepsForStmt, UpperBound, IndexSet);
1691static bool containsTCInfoTy(isl::map PartialSchedule,
const Dependences *D,
1693 if (!containsOnlyTcDeps(PartialSchedule, D, TCI.P,
Domain))
1697 if (TCI.P.size() == 0)
1700 if (!containsOnlyTCAcc(
Domain, PartialSchedule, TCI))
1704 if ((TCI.I.size() == 0) || (TCI.J.size() == 0))
1765static bool isTCPattern(isl::schedule_node Node,
const Dependences *D,
1767 Node = Node.
child(0);
1769 isl::union_set
Domain = Node.domain();
1824 if (!Node.
parent().
isa<isl::schedule_node_sequence>() ||
1839 if (containsTCInfoTy(PartialScheduleMap, D, TCI,
isl::set(
Domain)))
1849 const llvm::TargetTransformInfo *TTI,
1853 POLLY_DEBUG(dbgs() <<
"The tensor contraction pattern was detected\n");
1856 POLLY_DEBUG(dbgs() <<
"The matrix multiplication pattern was detected\n");
1857 return optimizeMatMulPattern(Node, TTI, MMI);
static cl::opt< int > OptComputeOut("polly-dependences-computeout", cl::desc("Bound the dependence analysis by a maximal amount of " "computational steps (0 means no bound)"), cl::Hidden, cl::init(500000), cl::cat(PollyCategory))
static cl::opt< int > FirstCacheLevelDefaultSize("polly-target-1st-cache-level-default-size", cl::desc("The default size of the first cache level specified in bytes" " (if not enough were provided by the TargetTransformInfo)."), cl::Hidden, cl::init(32768), cl::cat(PollyCategory))
static cl::opt< bool > PMBasedTCOpts("polly-tc-opt", cl::desc("Perform optimizations of tensor contractions based " "on pattern matching"), cl::init(false), cl::cat(PollyCategory))
static cl::opt< int > SecondCacheLevelDefaultAssociativity("polly-target-2nd-cache-level-default-associativity", cl::desc("The default associativity of the second cache level" " (if not enough were provided by the TargetTransformInfo)."), cl::Hidden, cl::init(8), cl::cat(PollyCategory))
static cl::opt< int > FirstCacheLevelAssociativity("polly-target-1st-cache-level-associativity", cl::desc("The associativity of the first cache level."), cl::Hidden, cl::init(-1), cl::cat(PollyCategory))
static cl::opt< int > SecondCacheLevelDefaultSize("polly-target-2nd-cache-level-default-size", cl::desc("The default size of the second cache level specified in bytes" " (if not enough were provided by the TargetTransformInfo)."), cl::Hidden, cl::init(262144), cl::cat(PollyCategory))
static cl::opt< int > PollyPatternMatchingNcQuotient("polly-pattern-matching-nc-quotient", cl::desc("Quotient that is obtained by dividing Nc, the parameter of the" "macro-kernel, by Nr, the parameter of the micro-kernel"), cl::Hidden, cl::init(256), cl::cat(PollyCategory))
static cl::opt< int > FirstCacheLevelSize("polly-target-1st-cache-level-size", cl::desc("The size of the first cache level specified in bytes."), cl::Hidden, cl::init(-1), cl::cat(PollyCategory))
static cl::opt< int > ThroughputVectorFma("polly-target-throughput-vector-fma", cl::desc("A throughput of the processor floating-point arithmetic units " "expressed in the number of vector fused multiply-add " "instructions per clock cycle."), cl::Hidden, cl::init(1), cl::cat(PollyCategory))
static cl::opt< int > SecondCacheLevelSize("polly-target-2nd-cache-level-size", cl::desc("The size of the second level specified in bytes."), cl::Hidden, cl::init(-1), cl::cat(PollyCategory))
static cl::opt< int > OptComputeOut("polly-tc-dependences-computeout", cl::desc("Bound the dependence analysis by a maximal amount of " "computational steps (0 means no bound)"), cl::Hidden, cl::init(500000), cl::cat(PollyCategory))
static cl::opt< int > FirstCacheLevelDefaultAssociativity("polly-target-1st-cache-level-default-associativity", cl::desc("The default associativity of the first cache level" " (if not enough were provided by the TargetTransformInfo)."), cl::Hidden, cl::init(8), cl::cat(PollyCategory))
static cl::opt< int > SecondCacheLevelAssociativity("polly-target-2nd-cache-level-associativity", cl::desc("The associativity of the second cache level."), cl::Hidden, cl::init(-1), cl::cat(PollyCategory))
static cl::opt< int > VectorRegisterBitwidth("polly-target-vector-register-bitwidth", cl::desc("The size in bits of a vector register (if not set, this " "information is taken from LLVM's target information."), cl::Hidden, cl::init(-1), cl::cat(PollyCategory))
static cl::opt< int > LatencyVectorFma("polly-target-latency-vector-fma", cl::desc("The minimal number of cycles between issuing two " "dependent consecutive vector fused multiply-add " "instructions."), cl::Hidden, cl::init(8), cl::cat(PollyCategory))
static cl::opt< bool > PMBasedMMMOpts("polly-matmul-opt", cl::desc("Perform optimizations of matrix multiplications " "based on pattern matching"), cl::init(true), cl::cat(PollyCategory))
static cl::opt< int > MaxStackArraySize("polly-pattern-matching-max-stack-array-size", cl::desc("The maximal size in bytes of a packed array of the matrix " "multiplication optimization that is allocated on the stack; " "larger ones are allocated on the heap (-1: all on the stack, " "0: all on the heap)"), cl::Hidden, cl::init(1024 *1024), cl::cat(PollyCategory))
llvm::cl::OptionCategory PollyCategory
__isl_give isl_set * isl_set_from_pw_multi_aff(__isl_take isl_pw_multi_aff *pma)
__isl_give isl_pw_multi_aff * isl_pw_multi_aff_from_set(__isl_take isl_set *set)
struct isl_pw_multi_aff isl_pw_multi_aff
isl::checked::map reverse() const
isl::checked::set deltas() const
class size range_tuple_dim() const
isl::checked::set range() const
isl::checked::set wrap() const
isl::checked::ctx ctx() const
isl::checked::map apply_range(isl::checked::map map2) const
boolean is_equal(const isl::checked::map &map2) const
isl::checked::map range_product(isl::checked::map map2) const
isl::checked::space get_space() const
isl::checked::map apply_domain(isl::checked::map map2) const
isl::checked::map intersect_domain(isl::checked::set set) const
isl::checked::set domain() const
__isl_keep isl_map * get() const
isl::checked::map intersect_range(isl::checked::set set) const
__isl_give isl_map * copy() const &
isl::checked::multi_pw_aff add(const isl::checked::multi_pw_aff &multi2) const
__isl_give isl_pw_multi_aff * copy() const &
isl::checked::multi_pw_aff sub(const isl::checked::multi_pw_aff &multi2) const
__isl_give isl_pw_multi_aff * release()
isl::checked::ctx ctx() const
isl::checked::schedule_node child(int pos) const
__isl_give isl_schedule_node * release()
isl::checked::schedule_node graft_before(isl::checked::schedule_node graft) const
isl::checked::schedule_node insert_partial_schedule(isl::checked::multi_union_pw_aff schedule) const
__isl_give isl_schedule_node * copy() const &
isl::checked::union_map get_prefix_schedule_union_map() const
isl::checked::schedule_node parent() const
isl::checked::schedule_node insert_mark(isl::checked::id mark) const
__isl_keep isl_schedule_node * get() const
__isl_give isl_set * copy() const &
isl::checked::set intersect(isl::checked::set set2) const
boolean is_subset(const isl::checked::set &set2) const
class size tuple_dim() const
boolean is_equal(const isl::checked::set &set2) const
isl::checked::space get_space() const
isl::checked::set subtract(isl::checked::set set2) const
isl::checked::space domain() const
isl::checked::union_map unite(isl::checked::union_map umap2) const
isl::checked::map extract_map(isl::checked::space space) const
isl::checked::union_set unite(isl::checked::union_set uset2) const
__isl_give isl_val * release()
static isl::id alloc(isl::ctx ctx, const std::string &name, void *user)
static isl::map from_union_map(isl::union_map umap)
static isl::map universe(isl::space space)
static isl::schedule_node from_extension(isl::union_map extension)
static isl::set universe(isl::space space)
The accumulated dependence information for a SCoP.
isl::union_map getDependences(int Kinds) const
Get the dependences of type Kinds.
isl::map getLatestAccessRelation() const
Return the newest access relation of this access.
bool isLatestArrayKind() const
Whether storage memory is either an custom .s2a/.phiops alloca (false) or an existing pointer into an...
bool isWrite() const
Is this a write memory access?
bool isRead() const
Is this a read memory access?
Type * getElementType() const
Return the element type of the accessed array wrt. this access.
ScopStmt * getStatement() const
Get the statement that contains this memory access.
void setNewAccessRelation(isl::map NewAccessRelation)
Set the updated access relation read from JSCOP file.
const SCEV * getDimensionSize(unsigned Dim) const
Return the size of dimension dim as SCEV*.
static const ScopArrayInfo * getFromId(isl::id Id)
Access the ScopArrayInfo associated with an isl Id.
void setIsOnHeap(bool value)
int getElemSizeInBytes() const
Get element size in bytes.
isl::id getBasePtrId() const
Return the isl id for the base pointer.
isl::id getDomainId() const
Get the id of the iteration domain space.
bool isRegionStmt() const
Return true if this statement represents a whole region.
isl::set getDomain() const
Get the iteration domain of this ScopStmt.
void addScopStmt(BasicBlock *BB, StringRef Name, Loop *SurroundingLoop, std::vector< Instruction * > Instructions)
Create a new SCoP statement for BB.
ScopArrayInfo * createScopArrayInfo(Type *ElementType, const std::string &BaseName, const std::vector< unsigned > &Sizes)
Create an array and return the corresponding ScopArrayInfo object.
Function & getFunction() const
Return the function this SCoP is in.
enum isl_schedule_node_type isl_schedule_node_get_type(__isl_keep isl_schedule_node *node)
boolean manage(isl_bool val)
llvm::SmallVector< MemoryAccess *, 32 > getAccessesInOrder(ScopStmt &Stmt)
Return a vector that contains MemoryAccesses in the order in which they are executed.
@ Value
MemoryKind::Value: Models an llvm::Value.
isl::schedule_node applyRegisterTiling(isl::schedule_node Node, llvm::ArrayRef< int > TileSizes, int DefaultTileSize)
Tile a schedule node and unroll point loops.
isl::val getConstant(isl::pw_aff PwAff, bool Max, bool Min)
If PwAff maps to a constant, return said constant.
isl::map makeIdentityMap(const isl::set &Set, bool RestrictDomain)
Construct an identity map for the given domain values.
llvm::iota_range< unsigned > rangeIslSize(unsigned Begin, isl::size End)
Check that End is valid and return an iterator from Begin to End.
isl::schedule_node tryOptimizeMatMulPattern(isl::schedule_node Node, const llvm::TargetTransformInfo *TTI, const Dependences *D)
Apply the BLIS matmul optimization pattern if possible.
isl::union_set getIsolateOptions(isl::set IsolateDomain, unsigned OutDimsNum)
Create an isl::union_set, which describes the isolate option based on IsolateDomain.
isl::schedule_node tileNode(isl::schedule_node Node, const char *Identifier, llvm::ArrayRef< int > TileSizes, int DefaultTileSize)
Tile a schedule node.
isl::union_set getDimOptions(isl::ctx Ctx, const char *Option)
Create an isl::union_set, which describes the specified option for the dimension of the current node.
llvm::APInt APIntFromVal(__isl_take isl_val *Val)
Translate isl_val to llvm::APInt.
isl::set getPartialTilePrefixes(isl::set ScheduleRange, int VectorWidth)
Build the desired set of partial tile prefixes.
__isl_export isl_size isl_schedule_node_band_n_member(__isl_keep isl_schedule_node *node)
__isl_export __isl_give isl_multi_union_pw_aff * isl_schedule_node_band_get_partial_schedule(__isl_keep isl_schedule_node *node)
__isl_export __isl_give isl_schedule_node * isl_schedule_node_band_split(__isl_take isl_schedule_node *node, int pos)
__isl_give isl_union_map * isl_schedule_node_band_get_partial_schedule_union_map(__isl_keep isl_schedule_node *node)
__isl_give isl_schedule_node * isl_schedule_node_delete(__isl_take isl_schedule_node *node)
@ isl_schedule_node_filter
@ isl_schedule_node_domain
__isl_give isl_set * isl_set_fix_val(__isl_take isl_set *set, enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
static TupleKindPtr Domain("Domain")
static std::vector< std::string > intersect(const std::vector< std::string > &v1, const std::vector< std::string > &v2)
isl_size isl_union_map_n_map(__isl_keep isl_union_map *umap)
isl_size isl_union_set_n_set(__isl_keep isl_union_set *uset)