[PATCH] D23738: [PM] Extend the explicit 'invalidate' method API on analysis results to accept an Invalidator that allows them to invalidate themselves if their dependencies are in turn invalidated.

Justin Lebar via llvm-commits llvm-commits at lists.llvm.org
Sun Oct 9 12:51:15 PDT 2016


jlebar added a comment.

I am still trying to understand why we've designed it this way, but here are some comments on comments.



================
Comment at: include/llvm/IR/PassManager.h:365
+  /// erases. Provides both the pass ID and concept pointer such that it is
+  /// half of a bijection and provides storage for the actual result concept.
+  typedef std::list<std::pair<void *, std::unique_ptr<ResultConceptT>>>
----------------
I can't figure out what "half of a bijection" is, and this phrase apparently appears nowhere on the internet other than in this file.  Can we rephrase?


================
Comment at: include/llvm/IR/PassManager.h:365
+  /// erases. Provides both the pass ID and concept pointer such that it is
+  /// half of a bijection and provides storage for the actual result concept.
+  typedef std::list<std::pair<void *, std::unique_ptr<ResultConceptT>>>
----------------
jlebar wrote:
> I can't figure out what "half of a bijection" is, and this phrase apparently appears nowhere on the internet other than in this file.  Can we rephrase?
Comma before "and" -- new independent clause.


================
Comment at: include/llvm/IR/PassManager.h:369
+
+  /// \brief Map type from function pointer to our custom list type.
+  typedef DenseMap<IRUnitT *, AnalysisResultListT> AnalysisResultListMapT;
----------------
An IRUnitT is not necessarily a function pointer, nor a pointer to an llvm::Function, right?


================
Comment at: include/llvm/IR/PassManager.h:372
+
+  /// \brief Map type from a pair of analysis ID and function pointer to an
+  /// iterator into a particular result list.
----------------
same here wrt "function pointer"


================
Comment at: include/llvm/IR/PassManager.h:373
+  /// \brief Map type from a pair of analysis ID and function pointer to an
+  /// iterator into a particular result list.
+  typedef DenseMap<std::pair<void *, IRUnitT *>,
----------------
This comment in particular, but also the one above, just sort of spells out in English what the type is.  It's definitely helpful to tell me what "void*" is, but you could write that as

  std::pair</* AnalysisID */ void*, IRUnit *>

or even

  using AnalysisID = void*;
  std::pair<AnalysisID, IRUnit *>

Once we've made the code clearer in this way, perhaps we could use the comments to say something about what these types are for.


================
Comment at: include/llvm/IR/PassManager.h:379
 public:
-  // Most public APIs are inherited from the CRTP base class.
+  /// An API provided to analysis results when they are handling invalidation to
+  /// allow them to invalidate other analyses they depend on.
----------------
comma before "to"


================
Comment at: include/llvm/IR/PassManager.h:383
+  /// This is used to support analysis results which embed handles to other
+  /// analysis results and thus recursive invalidation must be performed. We
+  /// pass in this API from the analysis manager in order to let the analysis
----------------
Rephrase beginning at "and" -- bad parallelism.


================
Comment at: include/llvm/IR/PassManager.h:384
+  /// analysis results and thus recursive invalidation must be performed. We
+  /// pass in this API from the analysis manager in order to let the analysis
+  /// results themselves define the dependency graph rather than tracking and
----------------
Nit, we don't really pass the API per se.  "We pass in an Invalidator", perhaps?


================
Comment at: include/llvm/IR/PassManager.h:386
+  /// results themselves define the dependency graph rather than tracking and
+  /// hard coding it anywhere.
+  class Invalidator {
----------------
Rephrase starting with "rather than".  I think this is important, because it's kind of the motivation for the whole design, but I don't grok what you're trying to get across.


================
Comment at: include/llvm/IR/PassManager.h:401
+
+      // Otherwise lookup the result object.
+      auto RI = Results.find({PassID, &IR});
----------------
"look up" is still the verb form.  I am losing this fight, but I have at least a few more years before the space is gone forever.  (The space makes the written form of the verb match the spoken form, which has two accented syllables -- the spoken noun form has only one accented syllable -- "LOOKup TAble", versus "LOOK UP 'TAble' in the dictionary".)


================
Comment at: include/llvm/IR/PassManager.h:589
+    // to an Invalidator instance to additionally memoize the calls to each
+    // result's invalidate routine.
+    SmallDenseMap<void *, bool, 8> IsResultInvalidated;
----------------
Kind of runs on -- split into two sentences?

  Track whether each pass's result is invalidated.  Memoize the results using the IsResultInvalidated map.


================
Comment at: include/llvm/IR/PassManager.h:595
+      // We don't directly use the Invalidator here because we have to operate
+      // on the type erased result where it doesn't, but we don't have to look
+      // up the result in the map where it does.
----------------
type-erased


================
Comment at: include/llvm/IR/PassManager.h:595
+      // We don't directly use the Invalidator here because we have to operate
+      // on the type erased result where it doesn't, but we don't have to look
+      // up the result in the map where it does.
----------------
jlebar wrote:
> type-erased
s/where/whereas/


================
Comment at: include/llvm/IR/PassManager.h:595
+      // We don't directly use the Invalidator here because we have to operate
+      // on the type erased result where it doesn't, but we don't have to look
+      // up the result in the map where it does.
----------------
jlebar wrote:
> jlebar wrote:
> > type-erased
> s/where/whereas/
s/but/and


================
Comment at: include/llvm/IR/PassManager.h:596
+      // on the type erased result where it doesn't, but we don't have to look
+      // up the result in the map where it does.
+      void *PassID = AnalysisResultPair.first;
----------------
again s/where/whereas/ (or "while") would help, I think.

Or maybe just

  This is basically the same thing as Invalidator::invalidate, but we can't call it here because we're operating on the type-erased result.  Moreover if we instead called invalidate() directly, it would do an unnecessary lookup in ResultsList.

Or maybe even leave out that second sentence, because it's a premature optimization.  :)


================
Comment at: include/llvm/IR/PassManager.h:604
+      if (!Inserted)
+        // This result was already handled via the invalidator.
+        continue;
----------------
s/invalidator/Invalidator/?


================
Comment at: include/llvm/IR/PassManager.h:613
+    // Now re-walk the list of results but this time erasing the ones which
+    // have been invalidated.
+    for (auto I = ResultsList.begin(), E = ResultsList.end(); I != E;) {
----------------
No need to set up a contrast, I think.  Maybe simply

  Now erase the results that were invalidated.


================
Comment at: include/llvm/IR/PassManager.h:626
+      I = ResultsList.erase(I);
+      AnalysisResults.erase({PassID, &IR});
     }
----------------
(I don't know why we have both a list and a map when we have things like MapVector, but...okay, let's assume there's a good reason for this.  :)


================
Comment at: include/llvm/IR/PassManagerInternal.h:99
   ///
   /// \returns true if the result is indeed invalid (the default).
+  virtual bool invalidate(IRUnitT &IR, const PreservedAnalysesT &PA,
----------------
Based on this comment I have no idea what I am supposed to do with the InvalidatorT object.


================
Comment at: lib/Analysis/CGSCCPassManager.cpp:76
 
+  // Invaliadtion was handled after each pass in the above loop for the current
+  // unit of IR. Therefore, the remaining analysis results in the
----------------
Invaliadtion

(I wonder how hard it would be to make a good C++ spellchecker.  You could imagine a tool that spellchecks only comments, and doesn't flag tokens that appear elsewhere in the code (outside comments)...  Catching these typos doesn't seem like a good job for hoomans.)

((Now I'm thinking about using whatever tech Chrome's online spellchecker -- which is hauntingly accurate -- uses, not just to catch typos in comments, but also bugs in code...))


================
Comment at: lib/Analysis/CGSCCPassManager.cpp:79
+  // AnalysisManager are preserved. We mark this with a set so that we don't
+  // need to inspect each one individually.
+  PA.preserve<AllAnalysesOn<LazyCallGraph::SCC>>();
----------------
I don't understand this comment, particularly "with a set".


================
Comment at: unittests/IR/PassManagerTest.cpp:392
+
+/// A test analysis pass which caches in its result another analyses pass and
+/// uses it to serve queries, and must therefore invalidate itself when its
----------------
s/analyses/analysis/


================
Comment at: unittests/IR/PassManagerTest.cpp:393
+/// A test analysis pass which caches in its result another analyses pass and
+/// uses it to serve queries, and must therefore invalidate itself when its
+/// dependency is invalidated.
----------------
Kind of a run-on sentence, maybe split?


================
Comment at: unittests/IR/PassManagerTest.cpp:426
+struct LambdaPass : public PassInfoMixin<LambdaPass> {
+  template <typename T> LambdaPass(T &&Arg) : Func(std::forward<T>(Arg)) {}
+
----------------
Can this constructor just take an std::function instead?  That would mean you have to spell out the type of the std::function twice, but I think it would be more explicit.


================
Comment at: unittests/IR/PassManagerTest.cpp:450
+  // First just use the analysis to get the instruction count, and preserve
+  // everything
+  FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
----------------
Nit, missing period.


================
Comment at: unittests/IR/PassManagerTest.cpp:458
+  // another function invalidate the indirect analysis, and for the final
+  // function invalidate both.
+  FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
----------------
The "for one function invalidate" form is awkward for me.  Maybe this would be easier to read as a bulleted list:

  Next, invalidate
    - the indirect analysis for g(),
    - the underlying analysis for h(), and
    - both analyses for f().

It might also make sense to rejigger the code so that we can change the comment to read "f()", "g()", and "h()".


================
Comment at: unittests/IR/PassManagerTest.cpp:469
+  }));
+  // Finally, use the analysis again on each function forcing re-computation
+  // for all of them.
----------------
comma before "forcing"


================
Comment at: unittests/IR/PassManagerTest.cpp:479
+
+  // There are generally two possible runs for ecah of the three functions. But
+  // for one function, we only invalidate the indirect analysis so the base one
----------------
ecah


================
Comment at: unittests/IR/PassManagerTest.cpp:483
+  EXPECT_EQ(5, AnalysisRuns);
+  // The indiract analysis is invalidate for each function (either directly or
+  // indirectly) and run twice total for each.
----------------
sp, indiract

is invalidated


================
Comment at: unittests/IR/PassManagerTest.cpp:484
+  // The indiract analysis is invalidate for each function (either directly or
+  // indirectly) and run twice total for each.
+  EXPECT_EQ(6, IndirectAnalysisRuns);
----------------
Not sure "total" is helpful.


================
Comment at: unittests/IR/PassManagerTest.cpp:488
+  // There are 5 total instructions in the module and we add the count three
+  // times total.
+  EXPECT_EQ(5 * 3, InstrCount);
----------------
Again not sure the second "total" helps.


https://reviews.llvm.org/D23738





More information about the llvm-commits mailing list