[PATCH] D86465: [analyzer][solver] Redesign constraint ranges data structure
Balázs Benics via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 27 09:11:56 PDT 2020
steakhal added a comment.
Previously, I liked this. Now I love it!
The benchmarks look promising as well.
I think I can not convince you about not modifying iterators using `++`,`--`, etc. outside of //loop-expressions//. So be it :D
================
Comment at: clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h:110
+public:
+ using iterator = ImplType::const_iterator;
+
----------------
Shouldn't we call this `const_iterator`?
================
Comment at: clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h:209
+ private:
+ /// Return a persistent version of the given container.
+ RangeSet makePersistent(ContainerType &&From);
----------------
================
Comment at: clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h:211
+ RangeSet makePersistent(ContainerType &&From);
+ /// Construct a new persistent version of the given container.
+ ContainerType *construct(ContainerType &&From);
----------------
================
Comment at: clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h:278
+private:
+ /* implicit */ RangeSet(ContainerType *RawContainer) : Impl(RawContainer) {}
+ /* implicit */ RangeSet(UnderlyingType Ptr) : Impl(Ptr) {}
----------------
Btw in C++20 we will have a way expressing this: `explicit(false)`
================
Comment at: clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h:281-290
+ /// Pin given points to the type represented by the current range set.
+ ///
+ /// This makes parameter points to be in-out parameters.
+ /// In order to maintain consistent types across all of the ranges in the set
+ /// and to keep all the operations to compare ONLY points of the same type, we
+ /// need to pin every point before any operation.
+ ///
----------------
Aww, excellent. Thanks.
================
Comment at: clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h:51
}
-};
+ void print(raw_ostream &OS) const;
----------------
steakhal wrote:
> We have `dump` methods all over the place. Except this.
> I propose to rename this to `dump`.
How about marking this `LLVM_DUMP_METHOD`?
Also, defining the `operator<<` would come handly later.
================
Comment at: clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h:53-55
+ // In order to keep non-overlapping ranges sorted, we can compare only From
+ // points.
+ inline bool operator<(const Range &RHS) const { return From() < RHS.From(); }
----------------
vsavchenko wrote:
> steakhal wrote:
> > It's a good practice to define comparison operators as //friend// functions inline.
> > Even if we don't rely on implicit conversions.
> It doesn't seem like there is a single opinion on this in the codebase.
Okay.
================
Comment at: clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h:135
+ /// @{
+ RangeSet getSet(Range Origin);
+ RangeSet getSet(const llvm::APSInt &From, const llvm::APSInt &To) {
----------------
vsavchenko wrote:
> steakhal wrote:
> > NoQ wrote:
> > > "But what about `setGet()`???" - some user, probably :)
> > Why don't we call this `createSetOf`?
> > And `createEmptySet`.
> > I know that we don't create the empty set, but then what does a //factory// if not create stuff?
> The naming is this way to be consistent with `ImmutableSet::Factory`
Makes sense.
================
Comment at: clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h:272-273
+private:
+ RangeSet(ContainerType *RawContainer) : Impl(RawContainer) {}
+ RangeSet(UnderlyingType Ptr) : Impl(Ptr) {}
----------------
vsavchenko wrote:
> steakhal wrote:
> > vsavchenko wrote:
> > > steakhal wrote:
> > > > Missing `explicit`.
> > > More like missing `/* implicit */` because it is intentional
> > It doesn't have a too long identifier.
> > The users can always refer to it `auto R = RangeSet(...)`, so we still don't repeat ourselves.
> > Do you have any particular counterexample?
> > Probably the tests will become slightly more bloated but eh. whatever.
> These constructors are `private` and used in `Factory` methods. IMO they make those methods less cluttered.
Okay.
================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:326
+
+ // If we ran out of ranges in one set, but not the other,
+ // it means that those elements are definitely not in the
----------------
================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:462-470
// Negate all other ranges.
- for (iterator e = end(); i != e; ++i) {
+ for (; It != End; ++It) {
// Negate int values.
- const llvm::APSInt &newFrom = BV.getValue(-i->To());
- const llvm::APSInt &newTo = BV.getValue(-i->From());
- // Add a negated range.
- newRanges = F.add(newRanges, Range(newFrom, newTo));
- }
-
- if (newRanges.isSingleton())
- return newRanges;
+ const llvm::APSInt &NewFrom = ValueFactory.getValue(-It->To());
+ const llvm::APSInt &NewTo = ValueFactory.getValue(-It->From());
+ // Add a negated range.
----------------
It might be overkill, but we can do this using transform.
================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:495-507
+void RangeSet::dump(raw_ostream &OS) const {
bool isFirst = true;
- os << "{ ";
- for (iterator i = begin(), e = end(); i != e; ++i) {
+ OS << "{ ";
+ for (const Range &R : *this) {
if (isFirst)
isFirst = false;
else
----------------
Hmm, we could simplify this further, assuming `Range::operator<<` is defined.
================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:322-325
+ auto swap = [&First, &FirstEnd, &Second, &SecondEnd]() {
+ std::swap(First, Second);
+ std::swap(FirstEnd, SecondEnd);
+ };
----------------
vsavchenko wrote:
> steakhal wrote:
> > vsavchenko wrote:
> > > steakhal wrote:
> > > > It could definitely bear a longer name.
> > > I think that there is nothing wrong in spelling out `std::swap` twice.
> > > And do we have a naming convention for lambdas, is it a variable or a function from a naming perspective?
> > That's a good question :)
> > I would say that its a variable, since you can mark it `const`, otherwise you could overwrite it. xD But that's a different story I think.
> > About the `swap` thingie, its a good practice to respect ADL for functions which know to be used via ADL.
> > Even if we don't depend on ADL in this particular case.
> I'm sorry but I still don't get the importance of dropping `std::` here.
Since we don't rely on Argument Dependent Lookup in this particular case, both versions do the same.
So **it's perfectly fine as-is**.
You should interpret my previous comment in a broader sense, like a guideline.
Which is meaningful mostly in //generic// programming.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D86465/new/
https://reviews.llvm.org/D86465
More information about the cfe-commits
mailing list