1 //===- AffineStructuresParserTest.cpp - FAC parsing unit 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 contains tests for parsing IntegerSets to FlatAffineConstraints.
10 // The tests with invalid input check that the parser only accepts well-formed
11 // IntegerSets. The tests with well-formed input compare the returned FACs to
12 // manually constructed FACs with a PresburgerSet equality check.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #include "./AffineStructuresParser.h"
17 #include "mlir/Analysis/Presburger/PresburgerSet.h"
18 
19 #include <gtest/gtest.h>
20 
21 namespace mlir {
22 
23 /// Construct a FlatAffineConstraints from a set of inequality, equality, and
24 /// division onstraints.
25 static FlatAffineConstraints makeFACFromConstraints(
26     unsigned dims, unsigned syms, ArrayRef<SmallVector<int64_t, 4>> ineqs,
27     ArrayRef<SmallVector<int64_t, 4>> eqs = {},
28     ArrayRef<std::pair<SmallVector<int64_t, 4>, int64_t>> divs = {}) {
29   FlatAffineConstraints fac(ineqs.size(), eqs.size(), dims + syms + 1, dims,
30                             syms, 0);
31   for (const auto &div : divs)
32     fac.addLocalFloorDiv(div.first, div.second);
33   for (const auto &eq : eqs)
34     fac.addEquality(eq);
35   for (const auto &ineq : ineqs)
36     fac.addInequality(ineq);
37   return fac;
38 }
39 
40 TEST(ParseFACTest, InvalidInputTest) {
41   MLIRContext context;
42   FailureOr<FlatAffineConstraints> fac;
43 
44   fac = parseIntegerSetToFAC("(x)", &context, false);
45   EXPECT_TRUE(failed(fac))
46       << "should not accept strings with no constraint list";
47 
48   fac = parseIntegerSetToFAC("(x)[] : ())", &context, false);
49   EXPECT_TRUE(failed(fac))
50       << "should not accept strings that contain remaining characters";
51 
52   fac = parseIntegerSetToFAC("(x)[] : (x - >= 0)", &context, false);
53   EXPECT_TRUE(failed(fac))
54       << "should not accept strings that contain incomplete constraints";
55 
56   fac = parseIntegerSetToFAC("(x)[] : (y == 0)", &context, false);
57   EXPECT_TRUE(failed(fac))
58       << "should not accept strings that contain unkown identifiers";
59 
60   fac = parseIntegerSetToFAC("(x, x) : (2 * x >= 0)", &context, false);
61   EXPECT_TRUE(failed(fac))
62       << "should not accept strings that contain repeated identifier names";
63 
64   fac = parseIntegerSetToFAC("(x)[x] : (2 * x >= 0)", &context, false);
65   EXPECT_TRUE(failed(fac))
66       << "should not accept strings that contain repeated identifier names";
67 
68   fac = parseIntegerSetToFAC("(x) : (2 * x + 9223372036854775808 >= 0)",
69                              &context, false);
70   EXPECT_TRUE(failed(fac)) << "should not accept strings with integer literals "
71                               "that do not fit into int64_t";
72 }
73 
74 /// Parses and compares the `str` to the `ex`. The equality check is performed
75 /// by using PresburgerSet::isEqual
76 static bool parseAndCompare(StringRef str, const FlatAffineConstraints &ex,
77                             MLIRContext *context) {
78   FailureOr<FlatAffineConstraints> fac = parseIntegerSetToFAC(str, context);
79 
80   EXPECT_TRUE(succeeded(fac));
81 
82   return PresburgerSet(*fac).isEqual(PresburgerSet(ex));
83 }
84 
85 TEST(ParseFACTest, ParseAndCompareTest) {
86   MLIRContext context;
87   // simple ineq
88   EXPECT_TRUE(parseAndCompare(
89       "(x)[] : (x >= 0)", makeFACFromConstraints(1, 0, {{1, 0}}), &context));
90 
91   // simple eq
92   EXPECT_TRUE(parseAndCompare("(x)[] : (x == 0)",
93                               makeFACFromConstraints(1, 0, {}, {{1, 0}}),
94                               &context));
95 
96   // multiple constraints
97   EXPECT_TRUE(parseAndCompare("(x)[] : (7 * x >= 0, -7 * x + 5 >= 0)",
98                               makeFACFromConstraints(1, 0, {{7, 0}, {-7, 5}}),
99                               &context));
100 
101   // multiple dimensions
102   EXPECT_TRUE(parseAndCompare("(x,y,z)[] : (x + y - z >= 0)",
103                               makeFACFromConstraints(3, 0, {{1, 1, -1, 0}}),
104                               &context));
105 
106   // dimensions and symbols
107   EXPECT_TRUE(parseAndCompare(
108       "(x,y,z)[a,b] : (x + y - z + 2 * a - 15 * b >= 0)",
109       makeFACFromConstraints(3, 2, {{1, 1, -1, 2, -15, 0}}), &context));
110 
111   // only symbols
112   EXPECT_TRUE(parseAndCompare("()[a] : (2 * a - 4 == 0)",
113                               makeFACFromConstraints(0, 1, {}, {{2, -4}}),
114                               &context));
115 
116   // simple floordiv
117   EXPECT_TRUE(parseAndCompare(
118       "(x, y) : (y - 3 * ((x + y - 13) floordiv 3) - 42 == 0)",
119       makeFACFromConstraints(2, 0, {}, {{0, 1, -3, -42}}, {{{1, 1, -13}, 3}}),
120       &context));
121 
122   // multiple floordiv
123   EXPECT_TRUE(parseAndCompare(
124       "(x, y) : (y - x floordiv 3 - y floordiv 2 == 0)",
125       makeFACFromConstraints(2, 0, {}, {{0, 1, -1, -1, 0}},
126                              {{{1, 0, 0}, 3}, {{0, 1, 0, 0}, 2}}),
127       &context));
128 
129   // nested floordiv
130   EXPECT_TRUE(parseAndCompare(
131       "(x, y) : (y - (x + y floordiv 2) floordiv 3 == 0)",
132       makeFACFromConstraints(2, 0, {}, {{0, 1, 0, -1, 0}},
133                              {{{0, 1, 0}, 2}, {{1, 0, 1, 0}, 3}}),
134       &context));
135 }
136 
137 } // namespace mlir
138