[Mlir-commits] [mlir] mlir/Presburger: contribute a free-standing parser (PR #94916)

Ramkumar Ramachandra llvmlistbot at llvm.org
Sun Jul 7 06:39:59 PDT 2024


================
@@ -0,0 +1,345 @@
+//===- ParseStructs.h - Presburger Parse Structrures ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_ANALYSIS_PRESBURGER_PARSER_PARSESTRUCTS_H
+#define MLIR_ANALYSIS_PRESBURGER_PARSER_PARSESTRUCTS_H
+
+#include "mlir/Analysis/Presburger/IntegerRelation.h"
+#include "mlir/Analysis/Presburger/PresburgerSpace.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include <cstdint>
+
+namespace mlir::presburger {
+using llvm::ArrayRef;
+using llvm::SmallVector;
+using llvm::SmallVectorImpl;
+
+/// This structure is central to the parser and flattener, and holds the number
+/// of dimensions, symbols, locals, and the constant term.
+struct ParseInfo {
+  unsigned numDims = 0;
+  unsigned numSymbols = 0;
+  unsigned numExprs = 0;
+  unsigned numDivs = 0;
+
+  constexpr unsigned getDimStartIdx() const { return 0; }
+  constexpr unsigned getSymbolStartIdx() const { return numDims; }
+  constexpr unsigned getLocalVarStartIdx() const {
+    return numDims + numSymbols;
+  }
+  constexpr unsigned getNumCols() const {
+    return numDims + numSymbols + numDivs + 1;
+  }
+  constexpr unsigned getConstantIdx() const { return getNumCols() - 1; }
+
+  constexpr bool isDimIdx(unsigned i) const { return i < getSymbolStartIdx(); }
+  constexpr bool isSymbolIdx(unsigned i) const {
+    return i >= getSymbolStartIdx() && i < getLocalVarStartIdx();
+  }
+  constexpr bool isLocalVarIdx(unsigned i) const {
+    return i >= getLocalVarStartIdx() && i < getConstantIdx();
+  }
+  constexpr bool isConstantIdx(unsigned i) const {
+    return i == getConstantIdx();
+  }
+};
+
+/// Helper for storing coefficients in canonical form: dims followed by symbols,
+/// followed by locals, and finally the constant term.
+///
+/// (x, y)[a, b]: y * 91 + x + 3 * a + 7
+/// coefficients: [1, 91, 3, 0, 7]
+struct CoefficientVector {
+  ParseInfo info;
+  SmallVector<int64_t, 8> coefficients;
+
+  CoefficientVector(const ParseInfo &info, int64_t c = 0) : info(info) {
+    coefficients.resize(info.getNumCols());
+    coefficients[info.getConstantIdx()] = c;
+  }
+
+  // Copyable and movable
+  CoefficientVector(const CoefficientVector &o) = default;
+  CoefficientVector &operator=(const CoefficientVector &o) = default;
+  CoefficientVector(CoefficientVector &&o)
+      : info(o.info), coefficients(std::move(o.coefficients)) {
+    o.coefficients.clear();
+  }
+
+  ArrayRef<int64_t> getCoefficients() const { return coefficients; }
+  int64_t getConstant() const { return coefficients[info.getConstantIdx()]; }
+  size_t size() const { return coefficients.size(); }
+  operator ArrayRef<int64_t>() const { return coefficients; }
+  void resize(size_t size) { coefficients.resize(size); }
+  operator bool() const {
+    return any_of(coefficients, [](int64_t c) { return c; });
+  }
+  int64_t &operator[](unsigned i) {
+    assert(i < coefficients.size());
+    return coefficients[i];
+  }
+  int64_t &back() { return coefficients.back(); }
+  int64_t back() const { return coefficients.back(); }
+  void clear() {
+    for_each(coefficients, [](auto &coeff) { coeff = 0; });
+  }
+
+  CoefficientVector &operator+=(const CoefficientVector &l) {
+    coefficients.resize(l.size());
+    for (auto [idx, c] : enumerate(l.getCoefficients()))
+      coefficients[idx] += c;
+    return *this;
+  }
+  CoefficientVector &operator*=(int64_t c) {
+    for_each(coefficients, [c](auto &coeff) { coeff *= c; });
+    return *this;
+  }
+  CoefficientVector &operator/=(int64_t c) {
+    assert(c && "Division by zero");
+    for_each(coefficients, [c](auto &coeff) { coeff /= c; });
+    return *this;
+  }
+
+  CoefficientVector operator+(const CoefficientVector &l) const {
+    CoefficientVector ret(*this);
+    return ret += l;
+  }
+  CoefficientVector operator*(int64_t c) const {
+    CoefficientVector ret(*this);
+    return ret *= c;
+  }
+  CoefficientVector operator/(int64_t c) const {
+    CoefficientVector ret(*this);
+    return ret /= c;
+  }
+
+  bool isConstant() const {
+    return all_of(drop_end(coefficients), [](int64_t c) { return !c; });
+  }
+  CoefficientVector getPadded(size_t newSize) const {
+    assert(newSize >= size() &&
+           "Padding size should be greater than expr size");
+    CoefficientVector ret(info);
+    ret.resize(newSize);
+
+    // Start constructing the result by taking the dims and symbols of the
+    // coefficients.
+    for (const auto &[col, coeff] : enumerate(drop_end(coefficients)))
+      ret[col] = coeff;
+
+    // Put the constant at the end.
+    ret.back() = back();
+    return ret;
+  }
+
+  uint64_t factorMulFromLinearTerm() const {
+    uint64_t gcd = 1;
+    for (int64_t val : coefficients)
+      gcd = std::gcd(gcd, std::abs(val));
+    return gcd;
+  }
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  bool hasMultipleCoefficients() const {
+    return count_if(coefficients, [](auto &coeff) { return coeff; }) > 1;
+  }
+  LLVM_DUMP_METHOD void dump() const;
+#endif
+};
+
+enum class DimOrSymbolKind {
+  DimId,
+  Symbol,
+};
+
+using DimOrSymbolExpr = std::pair<DimOrSymbolKind, unsigned>;
+enum class DivKind { FloorDiv, Mod };
+
+/// Represents a pure Affine expression. Linear expressions are represented with
+/// divisor = 1, and no nestedDivTerms.
+///
+/// 3 - a * (3 + (3 - x div 3) div 4 + y div 7) div 4
+/// ^ linearDivident = 3, mulFactor = 1, divisor = 1
+///   ^ nest: 1, mulFactor: -a
+///         ^ nest: 1, linearDividend
+///              ^ nest: 2, linearDividend
+///                     ^ nest: 3
+///                          ^ nest: 2
+///                                      ^ nest: 2
+///                               nest: 1, divisor ^
+///
+/// Where div = floordiv|mod; ceildiv is pre-reduced
+struct PureAffineExprImpl {
+  ParseInfo info;
+  DivKind kind = DivKind::FloorDiv;
+  using PureAffineExpr = std::unique_ptr<PureAffineExprImpl>;
+
+  int64_t mulFactor = 1;
+  CoefficientVector linearDividend;
+  int64_t divisor = 1;
+  SmallVector<PureAffineExpr, 4> nestedDivTerms;
----------------
artagnon wrote:

It is ineffiicient and wasteful to build Presburger structures piece-wise. They hold IntMatrices which will need to be resized every time we have a new column, besides cluttering the API of the structures with support for building them piece-wise. Besides, it's impossible to build divs piece-wise, as the non-linear coefficients of the div are unknown ahead-of-time, and we need a simple flattener after we have parsed all the equalities/inequalities.

https://github.com/llvm/llvm-project/pull/94916


More information about the Mlir-commits mailing list