1 //===- LoopTransformWarning.cpp -  ----------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Emit warnings if forced code transformations have not been performed.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/Transforms/Scalar/WarnMissedTransforms.h"
14 #include "llvm/Analysis/LoopInfo.h"
15 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
16 #include "llvm/InitializePasses.h"
17 #include "llvm/Transforms/Utils/LoopUtils.h"
18 
19 using namespace llvm;
20 
21 #define DEBUG_TYPE "transform-warning"
22 
23 /// Emit warnings for forced (i.e. user-defined) loop transformations which have
24 /// still not been performed.
25 static void warnAboutLeftoverTransformations(Loop *L,
26                                              OptimizationRemarkEmitter *ORE) {
27   if (hasUnrollTransformation(L) == TM_ForcedByUser) {
28     LLVM_DEBUG(dbgs() << "Leftover unroll transformation\n");
29     ORE->emit(
30         DiagnosticInfoOptimizationFailure(DEBUG_TYPE,
31                                           "FailedRequestedUnrolling",
32                                           L->getStartLoc(), L->getHeader())
33         << "loop not unrolled: the optimizer was unable to perform the "
34            "requested transformation; the transformation might be disabled or "
35            "specified as part of an unsupported transformation ordering");
36   }
37 
38   if (hasUnrollAndJamTransformation(L) == TM_ForcedByUser) {
39     LLVM_DEBUG(dbgs() << "Leftover unroll-and-jam transformation\n");
40     ORE->emit(
41         DiagnosticInfoOptimizationFailure(DEBUG_TYPE,
42                                           "FailedRequestedUnrollAndJamming",
43                                           L->getStartLoc(), L->getHeader())
44         << "loop not unroll-and-jammed: the optimizer was unable to perform "
45            "the requested transformation; the transformation might be disabled "
46            "or specified as part of an unsupported transformation ordering");
47   }
48 
49   if (hasVectorizeTransformation(L) == TM_ForcedByUser) {
50     LLVM_DEBUG(dbgs() << "Leftover vectorization transformation\n");
51     Optional<ElementCount> VectorizeWidth =
52         getOptionalElementCountLoopAttribute(L);
53     Optional<int> InterleaveCount =
54         getOptionalIntLoopAttribute(L, "llvm.loop.interleave.count");
55 
56     if (!VectorizeWidth || VectorizeWidth->isVector())
57       ORE->emit(
58           DiagnosticInfoOptimizationFailure(DEBUG_TYPE,
59                                             "FailedRequestedVectorization",
60                                             L->getStartLoc(), L->getHeader())
61           << "loop not vectorized: the optimizer was unable to perform the "
62              "requested transformation; the transformation might be disabled "
63              "or specified as part of an unsupported transformation ordering");
64     else if (InterleaveCount.value_or(0) != 1)
65       ORE->emit(
66           DiagnosticInfoOptimizationFailure(DEBUG_TYPE,
67                                             "FailedRequestedInterleaving",
68                                             L->getStartLoc(), L->getHeader())
69           << "loop not interleaved: the optimizer was unable to perform the "
70              "requested transformation; the transformation might be disabled "
71              "or specified as part of an unsupported transformation ordering");
72   }
73 
74   if (hasDistributeTransformation(L) == TM_ForcedByUser) {
75     LLVM_DEBUG(dbgs() << "Leftover distribute transformation\n");
76     ORE->emit(
77         DiagnosticInfoOptimizationFailure(DEBUG_TYPE,
78                                           "FailedRequestedDistribution",
79                                           L->getStartLoc(), L->getHeader())
80         << "loop not distributed: the optimizer was unable to perform the "
81            "requested transformation; the transformation might be disabled or "
82            "specified as part of an unsupported transformation ordering");
83   }
84 }
85 
86 static void warnAboutLeftoverTransformations(Function *F, LoopInfo *LI,
87                                              OptimizationRemarkEmitter *ORE) {
88   for (auto *L : LI->getLoopsInPreorder())
89     warnAboutLeftoverTransformations(L, ORE);
90 }
91 
92 // New pass manager boilerplate
93 PreservedAnalyses
94 WarnMissedTransformationsPass::run(Function &F, FunctionAnalysisManager &AM) {
95   // Do not warn about not applied transformations if optimizations are
96   // disabled.
97   if (F.hasOptNone())
98     return PreservedAnalyses::all();
99 
100   auto &ORE = AM.getResult<OptimizationRemarkEmitterAnalysis>(F);
101   auto &LI = AM.getResult<LoopAnalysis>(F);
102 
103   warnAboutLeftoverTransformations(&F, &LI, &ORE);
104 
105   return PreservedAnalyses::all();
106 }
107 
108 // Legacy pass manager boilerplate
109 namespace {
110 class WarnMissedTransformationsLegacy : public FunctionPass {
111 public:
112   static char ID;
113 
114   explicit WarnMissedTransformationsLegacy() : FunctionPass(ID) {
115     initializeWarnMissedTransformationsLegacyPass(
116         *PassRegistry::getPassRegistry());
117   }
118 
119   bool runOnFunction(Function &F) override {
120     if (skipFunction(F))
121       return false;
122 
123     auto &ORE = getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
124     auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
125 
126     warnAboutLeftoverTransformations(&F, &LI, &ORE);
127     return false;
128   }
129 
130   void getAnalysisUsage(AnalysisUsage &AU) const override {
131     AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
132     AU.addRequired<LoopInfoWrapperPass>();
133 
134     AU.setPreservesAll();
135   }
136 };
137 } // end anonymous namespace
138 
139 char WarnMissedTransformationsLegacy::ID = 0;
140 
141 INITIALIZE_PASS_BEGIN(WarnMissedTransformationsLegacy, "transform-warning",
142                       "Warn about non-applied transformations", false, false)
143 INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
144 INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass)
145 INITIALIZE_PASS_END(WarnMissedTransformationsLegacy, "transform-warning",
146                     "Warn about non-applied transformations", false, false)
147 
148 Pass *llvm::createWarnMissedTransformationsPass() {
149   return new WarnMissedTransformationsLegacy();
150 }
151