1 //===- Utils.h - Utils for Presburger Tests ---------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines helper functions for Presburger unittests.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef MLIR_UNITTESTS_ANALYSIS_PRESBURGER_UTILS_H
14 #define MLIR_UNITTESTS_ANALYSIS_PRESBURGER_UTILS_H
15 
16 #include "../../Dialect/Affine/Analysis/AffineStructuresParser.h"
17 #include "mlir/Analysis/Presburger/IntegerRelation.h"
18 #include "mlir/Analysis/Presburger/PWMAFunction.h"
19 #include "mlir/Analysis/Presburger/PresburgerRelation.h"
20 #include "mlir/Analysis/Presburger/Simplex.h"
21 #include "mlir/IR/MLIRContext.h"
22 #include "mlir/Support/LLVM.h"
23 
24 #include <gtest/gtest.h>
25 
26 namespace mlir {
27 namespace presburger {
28 
29 /// Parses a IntegerPolyhedron from a StringRef. It is expected that the
30 /// string represents a valid IntegerSet, otherwise it will violate a gtest
31 /// assertion.
parsePoly(StringRef str)32 inline IntegerPolyhedron parsePoly(StringRef str) {
33   MLIRContext context(MLIRContext::Threading::DISABLED);
34   FailureOr<IntegerPolyhedron> poly = parseIntegerSetToFAC(str, &context);
35   EXPECT_TRUE(succeeded(poly));
36   return *poly;
37 }
38 
39 /// Parse a list of StringRefs to IntegerRelation and combine them into a
40 /// PresburgerSet be using the union operation. It is expected that the strings
41 /// are all valid IntegerSet representation and that all of them have the same
42 /// number of dimensions as is specified by the numDims argument.
43 inline PresburgerSet
44 parsePresburgerSetFromPolyStrings(unsigned numDims, ArrayRef<StringRef> strs,
45                                   unsigned numSymbols = 0) {
46   PresburgerSet set = PresburgerSet::getEmpty(
47       PresburgerSpace::getSetSpace(numDims, numSymbols));
48   for (StringRef str : strs)
49     set.unionInPlace(parsePoly(str));
50   return set;
51 }
52 
makeMatrix(unsigned numRow,unsigned numColumns,ArrayRef<SmallVector<int64_t,8>> matrix)53 inline Matrix makeMatrix(unsigned numRow, unsigned numColumns,
54                          ArrayRef<SmallVector<int64_t, 8>> matrix) {
55   Matrix results(numRow, numColumns);
56   assert(matrix.size() == numRow);
57   for (unsigned i = 0; i < numRow; ++i) {
58     assert(matrix[i].size() == numColumns &&
59            "Output expression has incorrect dimensionality!");
60     for (unsigned j = 0; j < numColumns; ++j)
61       results(i, j) = matrix[i][j];
62   }
63   return results;
64 }
65 
66 /// Construct a PWMAFunction given the dimensionalities and an array describing
67 /// the list of pieces. Each piece is given by a string describing the domain
68 /// and a 2D array that represents the output.
69 inline PWMAFunction parsePWMAF(
70     unsigned numInputs, unsigned numOutputs,
71     ArrayRef<std::pair<StringRef, SmallVector<SmallVector<int64_t, 8>, 8>>>
72         data,
73     unsigned numSymbols = 0) {
74   static MLIRContext context;
75 
76   PWMAFunction result(PresburgerSpace::getSetSpace(
77                           /*numDims=*/numInputs - numSymbols, numSymbols),
78                       numOutputs);
79   for (const auto &pair : data) {
80     IntegerPolyhedron domain = parsePoly(pair.first);
81 
82     result.addPiece(
83         domain, makeMatrix(numOutputs, domain.getNumVars() + 1, pair.second));
84   }
85   return result;
86 }
87 
88 /// lhs and rhs represent non-negative integers or positive infinity. The
89 /// infinity case corresponds to when the Optional is empty.
infinityOrUInt64LE(Optional<uint64_t> lhs,Optional<uint64_t> rhs)90 inline bool infinityOrUInt64LE(Optional<uint64_t> lhs, Optional<uint64_t> rhs) {
91   // No constraint.
92   if (!rhs)
93     return true;
94   // Finite rhs provided so lhs has to be finite too.
95   if (!lhs)
96     return false;
97   return *lhs <= *rhs;
98 }
99 
100 /// Expect that the computed volume is a valid overapproximation of
101 /// the true volume `trueVolume`, while also being at least as good an
102 /// approximation as `resultBound`.
103 inline void
expectComputedVolumeIsValidOverapprox(Optional<uint64_t> computedVolume,Optional<uint64_t> trueVolume,Optional<uint64_t> resultBound)104 expectComputedVolumeIsValidOverapprox(Optional<uint64_t> computedVolume,
105                                       Optional<uint64_t> trueVolume,
106                                       Optional<uint64_t> resultBound) {
107   assert(infinityOrUInt64LE(trueVolume, resultBound) &&
108          "can't expect result to be less than the true volume");
109   EXPECT_TRUE(infinityOrUInt64LE(trueVolume, computedVolume));
110   EXPECT_TRUE(infinityOrUInt64LE(computedVolume, resultBound));
111 }
112 
113 } // namespace presburger
114 } // namespace mlir
115 
116 #endif // MLIR_UNITTESTS_ANALYSIS_PRESBURGER_UTILS_H
117