1 //===- PWMAFunction.h - MLIR PWMAFunction Class------------------*- 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 // Support for piece-wise multi-affine functions. These are functions that are 10 // defined on a domain that is a union of IntegerPolyhedrons, and on each domain 11 // the value of the function is a tuple of integers, with each value in the 12 // tuple being an affine expression in the vars of the IntegerPolyhedron. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #ifndef MLIR_ANALYSIS_PRESBURGER_PWMAFUNCTION_H 17 #define MLIR_ANALYSIS_PRESBURGER_PWMAFUNCTION_H 18 19 #include "mlir/Analysis/Presburger/IntegerRelation.h" 20 #include "mlir/Analysis/Presburger/PresburgerRelation.h" 21 22 namespace mlir { 23 namespace presburger { 24 25 /// This class represents a multi-affine function whose domain is given by an 26 /// IntegerPolyhedron. This can be thought of as an IntegerPolyhedron with a 27 /// tuple of integer values attached to every point in the polyhedron, with the 28 /// value of each element of the tuple given by an affine expression in the vars 29 /// of the polyhedron. For example we could have the domain 30 /// 31 /// (x, y) : (x >= 5, y >= x) 32 /// 33 /// and a tuple of three integers defined at every point in the polyhedron: 34 /// 35 /// (x, y) -> (x + 2, 2*x - 3y + 5, 2*x + y). 36 /// 37 /// In this way every point in the polyhedron has a tuple of integers associated 38 /// with it. If the integer polyhedron has local vars, then the output 39 /// expressions can use them as well. The output expressions are represented as 40 /// a matrix with one row for every element in the output vector one column for 41 /// each var, and an extra column at the end for the constant term. 42 /// 43 /// Checking equality of two such functions is supported, as well as finding the 44 /// value of the function at a specified point. 45 class MultiAffineFunction { 46 public: MultiAffineFunction(const IntegerPolyhedron & domain,const Matrix & output)47 MultiAffineFunction(const IntegerPolyhedron &domain, const Matrix &output) 48 : domainSet(domain), output(output) {} MultiAffineFunction(const Matrix & output,const PresburgerSpace & space)49 MultiAffineFunction(const Matrix &output, const PresburgerSpace &space) 50 : domainSet(space), output(output) {} 51 getNumInputs()52 unsigned getNumInputs() const { return domainSet.getNumDimAndSymbolVars(); } getNumOutputs()53 unsigned getNumOutputs() const { return output.getNumRows(); } isConsistent()54 bool isConsistent() const { 55 return output.getNumColumns() == domainSet.getNumVars() + 1; 56 } 57 58 /// Get the space of the input domain of this function. getDomainSpace()59 const PresburgerSpace &getDomainSpace() const { return domainSet.getSpace(); } 60 /// Get the input domain of this function. getDomain()61 const IntegerPolyhedron &getDomain() const { return domainSet; } 62 /// Get a matrix with each row representing row^th output expression. getOutputMatrix()63 const Matrix &getOutputMatrix() const { return output; } 64 /// Get the `i^th` output expression. getOutputExpr(unsigned i)65 ArrayRef<int64_t> getOutputExpr(unsigned i) const { return output.getRow(i); } 66 67 /// Insert `num` variables of the specified kind at position `pos`. 68 /// Positions are relative to the kind of variable. The coefficient columns 69 /// corresponding to the added variables are initialized to zero. Return the 70 /// absolute column position (i.e., not relative to the kind of variable) 71 /// of the first added variable. 72 unsigned insertVar(VarKind kind, unsigned pos, unsigned num = 1); 73 74 /// Remove the specified range of vars. 75 void removeVarRange(VarKind kind, unsigned varStart, unsigned varLimit); 76 77 /// Given a MAF `other`, merges local variables such that both funcitons 78 /// have union of local vars, without changing the set of points in domain or 79 /// the output. 80 void mergeLocalVars(MultiAffineFunction &other); 81 82 /// Return whether the outputs of `this` and `other` agree wherever both 83 /// functions are defined, i.e., the outputs should be equal for all points in 84 /// the intersection of the domains. 85 bool isEqualWhereDomainsOverlap(MultiAffineFunction other) const; 86 87 /// Return whether the `this` and `other` are equal. This is the case if 88 /// they lie in the same space, i.e. have the same dimensions, and their 89 /// domains are identical and their outputs are equal on their domain. 90 bool isEqual(const MultiAffineFunction &other) const; 91 92 /// Get the value of the function at the specified point. If the point lies 93 /// outside the domain, an empty optional is returned. 94 Optional<SmallVector<int64_t, 8>> valueAt(ArrayRef<int64_t> point) const; 95 96 /// Truncate the output dimensions to the first `count` dimensions. 97 /// 98 /// TODO: refactor so that this can be accomplished through removeVarRange. 99 void truncateOutput(unsigned count); 100 101 void print(raw_ostream &os) const; 102 void dump() const; 103 104 private: 105 /// The IntegerPolyhedron representing the domain over which the function is 106 /// defined. 107 IntegerPolyhedron domainSet; 108 109 /// The function's output is a tuple of integers, with the ith element of the 110 /// tuple defined by the affine expression given by the ith row of this output 111 /// matrix. 112 Matrix output; 113 }; 114 115 /// This class represents a piece-wise MultiAffineFunction. This can be thought 116 /// of as a list of MultiAffineFunction with disjoint domains, with each having 117 /// their own affine expressions for their output tuples. For example, we could 118 /// have a function with two input variables (x, y), defined as 119 /// 120 /// f(x, y) = (2*x + y, y - 4) if x >= 0, y >= 0 121 /// = (-2*x + y, y + 4) if x < 0, y < 0 122 /// = (4, 1) if x < 0, y >= 0 123 /// 124 /// Note that the domains all have to be *disjoint*. Otherwise, the behaviour of 125 /// this class is undefined. The domains need not cover all possible points; 126 /// this represents a partial function and so could be undefined at some points. 127 /// 128 /// As in PresburgerSets, the input vars are partitioned into dimension vars and 129 /// symbolic vars. 130 /// 131 /// Support is provided to compare equality of two such functions as well as 132 /// finding the value of the function at a point. 133 class PWMAFunction { 134 public: PWMAFunction(const PresburgerSpace & space,unsigned numOutputs)135 PWMAFunction(const PresburgerSpace &space, unsigned numOutputs) 136 : space(space), numOutputs(numOutputs) { 137 assert(space.getNumDomainVars() == 0 && 138 "Set type space should have zero domain vars."); 139 assert(space.getNumLocalVars() == 0 && 140 "PWMAFunction cannot have local vars."); 141 assert(numOutputs >= 1 && "The function must output something!"); 142 } 143 getSpace()144 const PresburgerSpace &getSpace() const { return space; } 145 146 void addPiece(const MultiAffineFunction &piece); 147 void addPiece(const IntegerPolyhedron &domain, const Matrix &output); 148 void addPiece(const PresburgerSet &domain, const Matrix &output); 149 getPiece(unsigned i)150 const MultiAffineFunction &getPiece(unsigned i) const { return pieces[i]; } getNumPieces()151 unsigned getNumPieces() const { return pieces.size(); } getNumOutputs()152 unsigned getNumOutputs() const { return numOutputs; } getNumInputs()153 unsigned getNumInputs() const { return space.getNumVars(); } getPiece(unsigned i)154 MultiAffineFunction &getPiece(unsigned i) { return pieces[i]; } 155 156 /// Return the domain of this piece-wise MultiAffineFunction. This is the 157 /// union of the domains of all the pieces. 158 PresburgerSet getDomain() const; 159 160 /// Return the value at the specified point and an empty optional if the 161 /// point does not lie in the domain. 162 Optional<SmallVector<int64_t, 8>> valueAt(ArrayRef<int64_t> point) const; 163 164 /// Return whether `this` and `other` are equal as PWMAFunctions, i.e. whether 165 /// they have the same dimensions, the same domain and they take the same 166 /// value at every point in the domain. 167 bool isEqual(const PWMAFunction &other) const; 168 169 /// Truncate the output dimensions to the first `count` dimensions. 170 /// 171 /// TODO: refactor so that this can be accomplished through removeVarRange. 172 void truncateOutput(unsigned count); 173 174 /// Return a function defined on the union of the domains of this and func, 175 /// such that when only one of the functions is defined, it outputs the same 176 /// as that function, and if both are defined, it outputs the lexmax/lexmin of 177 /// the two outputs. On points where neither function is defined, the returned 178 /// function is not defined either. 179 /// 180 /// Currently this does not support PWMAFunctions which have pieces containing 181 /// local variables. 182 /// TODO: Support local variables in peices. 183 PWMAFunction unionLexMin(const PWMAFunction &func); 184 PWMAFunction unionLexMax(const PWMAFunction &func); 185 186 void print(raw_ostream &os) const; 187 void dump() const; 188 189 private: 190 /// Return a function defined on the union of the domains of `this` and 191 /// `func`, such that when only one of the functions is defined, it outputs 192 /// the same as that function, and if neither is defined, the returned 193 /// function is not defined either. 194 /// 195 /// The provided `tiebreak` function determines which of the two functions' 196 /// output should be used on inputs where both the functions are defined. More 197 /// precisely, given two `MultiAffineFunction`s `mafA` and `mafB`, `tiebreak` 198 /// returns the subset of the intersection of the two functions' domains where 199 /// the output of `mafA` should be used. 200 /// 201 /// The PresburgerSet returned by `tiebreak` should be disjoint. 202 /// TODO: Remove this constraint of returning disjoint set. 203 PWMAFunction 204 unionFunction(const PWMAFunction &func, 205 llvm::function_ref<PresburgerSet(MultiAffineFunction mafA, 206 MultiAffineFunction mafB)> 207 tiebreak) const; 208 209 PresburgerSpace space; 210 211 /// The list of pieces in this piece-wise MultiAffineFunction. 212 SmallVector<MultiAffineFunction, 4> pieces; 213 214 /// The number of output vars. 215 unsigned numOutputs; 216 }; 217 218 } // namespace presburger 219 } // namespace mlir 220 221 #endif // MLIR_ANALYSIS_PRESBURGER_PWMAFUNCTION_H 222