[PATCH] D137505: [SCEV] Cache ZExt SCEV expressions.

Florian Hahn via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Sun Nov 27 16:13:31 PST 2022


fhahn marked 3 inline comments as done.
fhahn added inline comments.


================
Comment at: llvm/include/llvm/Analysis/ScalarEvolution.h:73
+
+class FoldID {
+  SmallVector<unsigned, 4> Bits;
----------------
mkazantsev wrote:
> It looks general enough to be moved to some utils, no? Just to think in the future.
It is similar to `FoldingSetNodeID` which is used in multiple places. I played around with that quite a bit, but didn't manage to reach the same performance as with the version inline here.

Having this separate here is not ideal, but at the moment I don't see an easy way to unify/share the code.


================
Comment at: llvm/include/llvm/Analysis/ScalarEvolution.h:79
+  void addInteger(unsigned I) { Bits.push_back(I); }
+  void addInteger(int I) { Bits.push_back(I); }
+
----------------
mkazantsev wrote:
> The fact that we have different API for signed and unsigned leads me to think that we might be able to distinguish between them, e.g. distinguish set with single `(int)1` from set with `(unsigned) 1`, but in fact we can't. What was the intention?
> 
> Maybe better remove signed version.
The main reason for the integer overload is to avoid ambiguous function calls when `addInteger` is called with signed ints. In the end the signdness doesn't really matter, as we only look at the bits. 


================
Comment at: llvm/include/llvm/Analysis/ScalarEvolution.h:84
+    addInteger(unsigned(I >> 32));
+  }
+
----------------
mkazantsev wrote:
> What worries me is that how easy to get a collision here. Basically, `{0, 0, ~0, ~0, 0, 0}` will collide with `{0ULL, ~0ULL, 0ULL}`. In your use case it should really be fine, because we add a lot of pointers, but if it is to be done more universal, need to think on making it harder to cheat (mix in types into hash?).
Yeah, unfortunately this is a potential issue. I went with your suggestion to include the number of entries in the vector in the hash, which should hopefully help a bit.


================
Comment at: llvm/include/llvm/Analysis/ScalarEvolution.h:97
+  unsigned computeHash() const {
+    unsigned Hash = Bits[0];
+    for (unsigned I = 1; I != Bits.size(); ++I)
----------------
mkazantsev wrote:
> `assert(!Bits.empty())`?
> Otherwise, if we want to allow empty sets (dunno why, just for generality), maybe start with `Hash =Bits.size()` and then mix in all elements?
> Otherwise, if we want to allow empty sets (dunno why, just for generality), maybe start with Hash =Bits.size() and then mix in all elements?

I went with adding `Hash = Bits.size()`. 


================
Comment at: llvm/include/llvm/Analysis/ScalarEvolution.h:125
+  static unsigned getHashValue(const FoldID &Val) {
+    return Val.computeHash() & ~(1 << (8 * sizeof(unsigned) - 1));
+  }
----------------
mkazantsev wrote:
> is it just `& std::max<int>()`?  Not asking to change, just trying to understand what was the intention.
The main reason was to avoid potential conflicts with the empty/tombstone values, but that shouldn't really help much. Also, now that the hash uses ` Hash = Bits.size()` it should be even less of an issue.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D137505/new/

https://reviews.llvm.org/D137505



More information about the llvm-commits mailing list