[PATCH] D80860: Exact integer emptiness checks for FlatAffineConstraints
Jean-Michel Gorius via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Sun May 31 16:13:55 PDT 2020
Kayjukh requested changes to this revision.
Kayjukh added a comment.
This revision now requires changes to proceed.
I added quite a lot of inline comments. To avoid redundancies for some of them, here are more general ones that apply to all the files:
- Don't use Doxygen tags in your comments.
- Use `///` for top-level comments (e.g. outside of functions).
- Prefer `SmallVector` over `std::vector` since the former can potentially be more efficient for small sizes.
- `Fraction` and `Matrix` look like they are only ever used with `int64_t` elements. Is there a need for them to be template classes?
================
Comment at: mlir/include/mlir/Analysis/AffineStructures.h:142
+ // \returns True if the set of constraints has no integer solution, and False
+ // if it does have a solution.
----------------
This looks like a Doxygen leftover.
================
Comment at: mlir/include/mlir/Analysis/AffineStructures.h:150
+ // Returns such a point if one exists, or an empty llvm::Optional otherwise.
+ llvm::Optional<std::vector<int64_t>> findIntegerSample() const;
+
----------------
`std::vector` is certainly not the right data structure to represent a point.
================
Comment at: mlir/include/mlir/Analysis/Presburger/Fraction.h:1
+//===- Simplex.h - MLIR Fraction Class --------------------------*- C++ -*-===//
+//
----------------
`Simplex.h` -> `Fraction.h`
================
Comment at: mlir/include/mlir/Analysis/Presburger/Fraction.h:33
+int compare(const Fraction<T> &x, const Fraction<T> &y) {
+ auto diff = x.num * y.den - y.num * x.den;
+ if (diff > 0)
----------------
These kinds of operations may be dangerous in case someone would instantiate a `Fraction` with a small element type (e.g. `Fraction<int8_t>`). I see two possible alternatives here: either check for overflow and handle it gracefully or tighten the constraints on `Fraction` 's element type.
================
Comment at: mlir/include/mlir/Analysis/Presburger/Fraction.h:100
+}
+} // namespace mlir
+#endif // MLIR_ANALYSIS_PRESBURGER_FRACTION_H
----------------
nit: Add blank lines before and after `} // namespace mlir`.
================
Comment at: mlir/include/mlir/Analysis/Presburger/Matrix.h:9
+//
+// This a simplex 2D matrix class that supports reading, writing, resizing,
+// and swapping rows, and swapping columns.
----------------
`This a simplex 2D matrix class` -> `This is a simple 2D matric class`?
================
Comment at: mlir/include/mlir/Analysis/Presburger/Matrix.h:10
+// This a simplex 2D matrix class that supports reading, writing, resizing,
+// and swapping rows, and swapping columns.
+//
----------------
nit: Remove redundant `and`.
================
Comment at: mlir/include/mlir/Analysis/Presburger/Matrix.h:20
+#include <cassert>
+#include <vector>
+
----------------
If we are going to use vectors, `SmallVector` may be a better choice. Especially if you have an idea of the typical matrix size.
================
Comment at: mlir/include/mlir/Analysis/Presburger/Matrix.h:27
+/// The data is stored in the form of a vector of vectors.
+template <typename INT>
+class Matrix {
----------------
I guess the `INT` means that the `Matrix` type should only be instantiated with integers. Maybe you could `static_assert` if it isn't the case or use SFINAE to constrain the possible template types.
================
Comment at: mlir/include/mlir/Analysis/Presburger/Matrix.h:36
+
+ static Matrix getIdentityMatrix(unsigned dimension);
+
----------------
What about `identity`?
================
Comment at: mlir/include/mlir/Analysis/Presburger/Matrix.h:66
+ unsigned nColumns;
+ std::vector<std::vector<INT>> data;
+};
----------------
Why not store the matrix data in a one-dimensional array?
================
Comment at: mlir/include/mlir/Analysis/Presburger/Matrix.h:148
+void Matrix<INT>::print(llvm::raw_ostream &os) const {
+ os << "Dumping matrix, rows = " << getNumRows()
+ << ", columns: " << getNumColumns() << '\n';
----------------
This seems to be a very specific way to print a matrix. Do you need the `print` method or would `dump` be enough?
Also, I would probably not include the `Dumping matrix` part.
================
Comment at: mlir/include/mlir/Analysis/Presburger/Matrix.h:151
+ os << "r/c ";
+ for (unsigned column = 0; column < getNumColumns(); ++column)
+ os << "| " << column << " ";
----------------
This should probably be written as
```
for (unsigned column = 0, end = getNumColumns(); column < end; ++column)
```
(https://llvm.org/docs/CodingStandards.html#don-t-evaluate-end-every-time-through-a-loop)
================
Comment at: mlir/include/mlir/Analysis/Presburger/Matrix.h:155
+ os << std::string(5 + getNumColumns() * 5, '-') << '\n';
+ for (unsigned row = 0; row < getNumRows(); ++row) {
+ os << row << " | ";
----------------
Same comment as above.
================
Comment at: mlir/include/mlir/Analysis/Presburger/Matrix.h:157
+ os << row << " | ";
+ for (unsigned column = 0; column < getNumColumns(); ++column)
+ os << data[row][column] << " ";
----------------
Same for this loop.
================
Comment at: mlir/include/mlir/Analysis/Presburger/Matrix.h:168
+
+} // namespace mlir
+#endif // MLIR_ANALYSIS_PRESBURGER_MATRIX_H
----------------
nit: Add a space after this line.
================
Comment at: mlir/include/mlir/Analysis/Presburger/Simplex.h:9
+//
+// This class can perform analysis on FlatAffineConstraints. In particular,
+// it can be used to perform emptiness checks.
----------------
nit: Since this is a top-level comment, maybe rephrase it to be less specific to the class. `This class` feels like it is too tied to a specific class in the file.
================
Comment at: mlir/include/mlir/Analysis/Presburger/Simplex.h:44
+public:
+ enum class Direction { UP, DOWN };
+ enum class UndoOp {
----------------
Don't use SCREAMING_CASE for enumerators.
================
Comment at: mlir/include/mlir/Analysis/Presburger/Simplex.h:47
+ DEALLOCATE,
+ UNMARK_EMPTY,
+ };
----------------
Same comment as above regarding the case.
Remove the trailing comma.
================
Comment at: mlir/include/mlir/Analysis/Presburger/Simplex.h:56
+
+ /// \returns True if the tableau is empty (has conflicting constraints),
+ /// False otherwise.
----------------
Remove all the Doxygen tags in the file. There are quite a few places where you use `\returns` or `\p`.
================
Comment at: mlir/include/mlir/Analysis/Presburger/Simplex.h:66
+ /// \returns the number of variables in the tableau.
+ unsigned numberVariables() const;
+
----------------
`numberVariables` -> `numVariables`?
================
Comment at: mlir/include/mlir/Analysis/Presburger/Simplex.h:69
+ /// \returns the number of constraints in the tableau.
+ unsigned numberConstraints() const;
+
----------------
`numberConstraints` -> `numConstraints`?
================
Comment at: mlir/include/mlir/Analysis/Presburger/Simplex.h:126
+ bool restricted;
+ unsigned pos;
+ };
----------------
nit: Reorder members by decreasing bit-width to limit padding.
================
Comment at: mlir/include/mlir/Analysis/Presburger/Simplex.h:136
+ ///
+ /// \returns a [row, col] pair denoting a pivot, or an empty llvm::Optional if
+ /// no valid pivot exists.
----------------
The pair notation seems inconsistent with previous ones.
================
Comment at: mlir/include/mlir/Analysis/Presburger/Simplex.h:138
+ /// no valid pivot exists.
+ llvm::Optional<std::pair<unsigned, unsigned>>
+ findPivot(int row, Direction direction) const;
----------------
Could `std::pair` be replaced by a struct with more descriptive member names?
================
Comment at: mlir/include/mlir/Analysis/Presburger/Simplex.h:223
+ /// Holds a log of operations, used for rolling back to a previoous state.
+ std::vector<std::pair<UndoOp, llvm::Optional<int>>> undoLog;
+
----------------
This `vector` as well as the four that follow could be `SmallVector`s.
================
Comment at: mlir/lib/Analysis/AffineStructures.cpp:1051
+ Simplex simplex(*this);
+ return simplex.findIntegerSample();
+}
----------------
`return Simplex(*this).findIntegerSample();`?
================
Comment at: mlir/lib/Analysis/Presburger/Simplex.cpp:25
+ for (unsigned i = 0; i < nVar; ++i) {
+ var.push_back(
+ Unknown(/*ownsRow=*/false, /*restricted=*/false, /*pos=*/nCol));
----------------
Replace `push_back` by `emplace_back`.
================
Comment at: mlir/lib/Analysis/Presburger/Simplex.cpp:34
+ : Simplex(constraints.getNumIds()) {
+ for (unsigned i = 0; i < constraints.getNumInequalities(); ++i)
+ addInequality(constraints.getInequality(i));
----------------
Same comment as above regarding the evaluation of the terminating condition, for this loop and the following one.
================
Comment at: mlir/lib/Analysis/Presburger/Simplex.cpp:42
+ assert(index != nullIndex && "nullIndex passed to unknownFromIndex");
+ return index >= 0 ? var[index] : con[~index];
+}
----------------
Why do you need Python-style access?
================
Comment at: mlir/lib/Analysis/Presburger/Simplex.cpp:88
+
+ nRow++;
+ if (nRow >= tableau.getNumRows())
----------------
nit: `++nRow;`
================
Comment at: mlir/lib/Analysis/Presburger/Simplex.cpp:91
+ tableau.resize(nRow, tableau.getNumColumns());
+ rowVar.push_back(~con.size());
+ con.emplace_back(true, false, nRow - 1);
----------------
This probably needs more documentation.
================
Comment at: mlir/lib/Analysis/Presburger/Simplex.cpp:128
+
+// Normalize the row by removing common factors that are common between the
+// denominator and all the numerator coefficients.
----------------
nit: Duplicate `common`.
================
Comment at: mlir/lib/Analysis/Presburger/Simplex.cpp:151
+// Find a pivot to change the sample value of `row` in the specified direction.
+// The returned pivot row will involve `row` if and only if the unknown is
+// unbounded in the specified direction.
----------------
nit: The usage of backticks here is inconsistent with previous code comments.
================
Comment at: mlir/lib/Analysis/Presburger/Simplex.cpp:183
+ auto opt = findPivotRow(row, newDirection, *col);
+ return std::pair<unsigned, unsigned>{opt.getValueOr(row), *col};
+}
----------------
If we choose to use `std::pair` then this should probably be a call to `std::make_pair`.
================
Comment at: mlir/lib/Analysis/Presburger/Simplex.cpp:392
+
+void Simplex::undoOp(UndoOp op, llvm::Optional<int> index) {
+ if (op == UndoOp::DEALLOCATE) {
----------------
This function seems to be a good candidate to be split into two different functions. The branch on the value of `op` seems very unnatural.
================
Comment at: mlir/lib/Analysis/Presburger/Simplex.cpp:481
+template <typename T>
+std::vector<T> concat(const std::vector<T> &v, const std::vector<T> &w) {
+ auto result = v;
----------------
This seems inefficient.
The function should have static linkage since it is only used as a helper in this file.
================
Comment at: mlir/lib/Analysis/Presburger/Simplex.cpp:878
+void Simplex::print(llvm::raw_ostream &os) const {
+ os << "Dumping Simplex, rows = " << nRow << ", columns = " << nCol << "\n";
+ if (empty)
----------------
Same comment as for the `Matrix::print` method.
================
Comment at: mlir/unittests/Analysis/Presburger/MatrixTest.cpp:89
+}
+} // namespace mlir
----------------
nit: Add a blank line above this one.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D80860/new/
https://reviews.llvm.org/D80860
More information about the llvm-commits
mailing list