1111// ===----------------------------------------------------------------------===//
1212
1313#include " polly/ManualOptimizer.h"
14+ #include " polly/DependenceInfo.h"
15+ #include " polly/Options.h"
1416#include " polly/ScheduleTreeTransform.h"
1517#include " polly/Support/ScopHelper.h"
1618#include " llvm/ADT/Optional.h"
1719#include " llvm/ADT/StringRef.h"
1820#include " llvm/Analysis/LoopInfo.h"
21+ #include " llvm/Analysis/OptimizationRemarkEmitter.h"
1922#include " llvm/IR/Metadata.h"
2023#include " llvm/Transforms/Utils/LoopUtils.h"
2124
@@ -25,6 +28,12 @@ using namespace polly;
2528using namespace llvm ;
2629
2730namespace {
31+
32+ static cl::opt<bool > IgnoreDepcheck (
33+ " polly-pragma-ignore-depcheck" ,
34+ cl::desc (" Skip the dependency check for pragma-based transformations" ),
35+ cl::init(false ), cl::ZeroOrMore, cl::cat(PollyCategory));
36+
2837// / Same as llvm::hasUnrollTransformation(), but takes a LoopID as argument
2938// / instead of a Loop.
3039static TransformationMode hasUnrollTransformation (MDNode *LoopID) {
@@ -48,6 +57,31 @@ static TransformationMode hasUnrollTransformation(MDNode *LoopID) {
4857 return TM_Unspecified;
4958}
5059
60+ // Return the first DebugLoc in the list.
61+ static DebugLoc findFirstDebugLoc (MDNode *MD) {
62+ if (MD) {
63+ for (const MDOperand &X : drop_begin (MD->operands (), 1 )) {
64+ Metadata *A = X.get ();
65+ if (!isa<DILocation>(A))
66+ continue ;
67+ return cast<DILocation>(A);
68+ }
69+ }
70+
71+ return {};
72+ }
73+
74+ static DebugLoc findTransformationDebugLoc (MDNode *LoopMD, StringRef Name) {
75+ // First find dedicated transformation location
76+ // (such as the location of #pragma clang loop)
77+ MDNode *MD = findOptionMDForLoopID (LoopMD, Name);
78+ if (DebugLoc K = findFirstDebugLoc (MD))
79+ return K;
80+
81+ // Otherwise, fall back to the location of the loop itself
82+ return findFirstDebugLoc (LoopMD);
83+ }
84+
5185// / Apply full or partial unrolling.
5286static isl::schedule applyLoopUnroll (MDNode *LoopMD,
5387 isl::schedule_node BandToUnroll) {
@@ -78,6 +112,15 @@ static isl::schedule applyLoopUnroll(MDNode *LoopMD,
78112 return {};
79113}
80114
115+ static isl::schedule applyLoopFission (MDNode *LoopMD,
116+ isl::schedule_node BandToFission) {
117+ // TODO: Make it possible to selectively fission substatements.
118+ // TODO: Apply followup loop properties.
119+ // TODO: Instead of fission every statement, find the maximum set that does
120+ // not cause a dependency violation.
121+ return applyMaxFission (BandToFission);
122+ }
123+
81124// Return the properties from a LoopID. Scalar properties are ignored.
82125static auto getLoopMDProps (MDNode *LoopMD) {
83126 return map_range (
@@ -96,14 +139,76 @@ class SearchTransformVisitor
96139 BaseTy &getBase () { return *this ; }
97140 const BaseTy &getBase () const { return *this ; }
98141
142+ polly::Scop *S;
143+ const Dependences *D;
144+ OptimizationRemarkEmitter *ORE;
145+
99146 // Set after a transformation is applied. Recursive search must be aborted
100147 // once this happens to ensure that any new followup transformation is
101148 // transformed in innermost-first order.
102149 isl::schedule Result;
103150
151+ // / Check wether a schedule after a transformation is legal. Return the old
152+ // / schedule without the transformation.
153+ isl::schedule
154+ checkDependencyViolation (llvm::MDNode *LoopMD, llvm::Value *CodeRegion,
155+ const isl::schedule_node &OrigBand,
156+ StringRef DebugLocAttr, StringRef TransPrefix,
157+ StringRef RemarkName, StringRef TransformationName) {
158+ if (D->isValidSchedule (*S, Result))
159+ return Result;
160+
161+ LLVMContext &Ctx = LoopMD->getContext ();
162+ LLVM_DEBUG (dbgs () << " Dependency violation detected\n " );
163+
164+ DebugLoc TransformLoc = findTransformationDebugLoc (LoopMD, DebugLocAttr);
165+
166+ if (IgnoreDepcheck) {
167+ LLVM_DEBUG (dbgs () << " Still accepting transformation due to "
168+ " -polly-pragma-ignore-depcheck\n " );
169+ if (ORE) {
170+ ORE->emit (
171+ OptimizationRemark (DEBUG_TYPE, RemarkName, TransformLoc, CodeRegion)
172+ << (Twine (" Could not verify dependencies for " ) +
173+ TransformationName +
174+ " ; still applying because of -polly-pragma-ignore-depcheck" )
175+ .str ());
176+ }
177+ return Result;
178+ }
179+
180+ LLVM_DEBUG (dbgs () << " Rolling back transformation\n " );
181+
182+ if (ORE) {
183+ ORE->emit (DiagnosticInfoOptimizationFailure (DEBUG_TYPE, RemarkName,
184+ TransformLoc, CodeRegion)
185+ << (Twine (" not applying " ) + TransformationName +
186+ " : cannot ensure semantic equivalence due to possible "
187+ " dependency violations" )
188+ .str ());
189+ }
190+
191+ // If illegal, revert and remove the transformation to not risk re-trying
192+ // indefintely.
193+ MDNode *NewLoopMD =
194+ makePostTransformationMetadata (Ctx, LoopMD, {TransPrefix}, {});
195+ BandAttr *Attr = getBandAttr (OrigBand);
196+ Attr->Metadata = NewLoopMD;
197+
198+ // Roll back old schedule.
199+ return OrigBand.get_schedule ();
200+ }
201+
104202public:
105- static isl::schedule applyOneTransformation (const isl::schedule &Sched) {
106- SearchTransformVisitor Transformer;
203+ SearchTransformVisitor (polly::Scop *S, const Dependences *D,
204+ OptimizationRemarkEmitter *ORE)
205+ : S(S), D(D), ORE(ORE) {}
206+
207+ static isl::schedule applyOneTransformation (polly::Scop *S,
208+ const Dependences *D,
209+ OptimizationRemarkEmitter *ORE,
210+ const isl::schedule &Sched) {
211+ SearchTransformVisitor Transformer (S, D, ORE);
107212 Transformer.visit (Sched);
108213 return Transformer.Result ;
109214 }
@@ -125,6 +230,14 @@ class SearchTransformVisitor
125230 return ;
126231 }
127232
233+ // CodeRegion used but ORE to determine code hotness.
234+ // TODO: Works only for original loop; for transformed loops, should track
235+ // where the loop's body code comes from.
236+ Loop *Loop = Attr->OriginalLoop ;
237+ Value *CodeRegion = nullptr ;
238+ if (Loop)
239+ CodeRegion = Loop->getHeader ();
240+
128241 MDNode *LoopMD = Attr->Metadata ;
129242 if (!LoopMD)
130243 return ;
@@ -146,6 +259,15 @@ class SearchTransformVisitor
146259 Result = applyLoopUnroll (LoopMD, Band);
147260 if (!Result.is_null ())
148261 return ;
262+ } else if (AttrName == " llvm.loop.distribute.enable" ) {
263+ Result = applyLoopFission (LoopMD, Band);
264+ if (!Result.is_null ())
265+ Result = checkDependencyViolation (
266+ LoopMD, CodeRegion, Band, " llvm.loop.distribute.loc" ,
267+ " llvm.loop.distribute." , " FailedRequestedFission" ,
268+ " loop fission/distribution" );
269+ if (!Result.is_null ())
270+ return ;
149271 }
150272
151273 // not a loop transformation; look for next property
@@ -162,11 +284,14 @@ class SearchTransformVisitor
162284
163285} // namespace
164286
165- isl::schedule polly::applyManualTransformations (Scop *S, isl::schedule Sched) {
287+ isl::schedule
288+ polly::applyManualTransformations (Scop *S, isl::schedule Sched,
289+ const Dependences &D,
290+ OptimizationRemarkEmitter *ORE) {
166291 // Search the loop nest for transformations until fixpoint.
167292 while (true ) {
168293 isl::schedule Result =
169- SearchTransformVisitor::applyOneTransformation (Sched);
294+ SearchTransformVisitor::applyOneTransformation (S, &D, ORE, Sched);
170295 if (Result.is_null ()) {
171296 // No (more) transformation has been found.
172297 break ;
0 commit comments