2018-08-22 01:32:24 +08:00
|
|
|
//===- AffineStructures.cpp - MLIR Affine Structures Class-------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// Copyright 2019 The MLIR Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
// =============================================================================
|
|
|
|
//
|
|
|
|
// Structures for affine/polyhedral analysis of MLIR functions.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "mlir/Analysis/AffineStructures.h"
|
2018-09-13 01:21:23 +08:00
|
|
|
#include "mlir/Analysis/AffineAnalysis.h"
|
2018-10-09 02:10:11 +08:00
|
|
|
#include "mlir/IR/AffineExprVisitor.h"
|
2018-08-22 01:32:24 +08:00
|
|
|
#include "mlir/IR/AffineMap.h"
|
2018-10-11 05:23:30 +08:00
|
|
|
#include "mlir/IR/BuiltinOps.h"
|
2018-08-22 01:32:24 +08:00
|
|
|
#include "mlir/IR/IntegerSet.h"
|
2018-10-09 02:10:11 +08:00
|
|
|
#include "mlir/IR/MLValue.h"
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
|
|
#include "llvm/ADT/DenseSet.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2018-08-22 01:32:24 +08:00
|
|
|
|
2018-09-05 06:55:38 +08:00
|
|
|
using namespace mlir;
|
2018-10-09 02:10:11 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
// Affine map composition terminology:
|
|
|
|
// *) current: refers to the target map of the composition operation. It is the
|
|
|
|
// map into which results from the 'input' map are forward substituted.
|
|
|
|
// *) input: refers to the map which is being forward substituted into the
|
|
|
|
// 'current' map.
|
|
|
|
// *) output: refers to the resulting affine map after composition.
|
|
|
|
|
|
|
|
// AffineMapCompositionUpdate encapsulates the state necessary to compose
|
|
|
|
// AffineExprs for two affine maps using AffineExprComposer (see below).
|
|
|
|
struct AffineMapCompositionUpdate {
|
|
|
|
using PositionMap = DenseMap<unsigned, unsigned>;
|
|
|
|
|
2018-10-09 04:47:18 +08:00
|
|
|
explicit AffineMapCompositionUpdate(ArrayRef<AffineExpr> inputResults)
|
2018-10-09 02:10:11 +08:00
|
|
|
: inputResults(inputResults), outputNumDims(0), outputNumSymbols(0) {}
|
|
|
|
|
|
|
|
// Map from 'curr' affine map dim position to 'output' affine map
|
|
|
|
// dim position.
|
|
|
|
PositionMap currDimMap;
|
|
|
|
// Map from dim position of 'curr' affine map to index into 'inputResults'.
|
|
|
|
PositionMap currDimToInputResultMap;
|
|
|
|
// Map from 'curr' affine map symbol position to 'output' affine map
|
|
|
|
// symbol position.
|
|
|
|
PositionMap currSymbolMap;
|
|
|
|
// Map from 'input' affine map dim position to 'output' affine map
|
|
|
|
// dim position.
|
|
|
|
PositionMap inputDimMap;
|
|
|
|
// Map from 'input' affine map symbol position to 'output' affine map
|
|
|
|
// symbol position.
|
|
|
|
PositionMap inputSymbolMap;
|
|
|
|
// Results of 'input' affine map.
|
2018-10-09 04:47:18 +08:00
|
|
|
ArrayRef<AffineExpr> inputResults;
|
2018-10-09 02:10:11 +08:00
|
|
|
// Number of dimension operands for 'output' affine map.
|
|
|
|
unsigned outputNumDims;
|
|
|
|
// Number of symbol operands for 'output' affine map.
|
|
|
|
unsigned outputNumSymbols;
|
|
|
|
};
|
|
|
|
|
|
|
|
// AffineExprComposer composes two AffineExprs as specified by 'mapUpdate'.
|
|
|
|
class AffineExprComposer {
|
|
|
|
public:
|
|
|
|
// Compose two AffineExprs using dimension and symbol position update maps,
|
|
|
|
// as well as input map result AffineExprs specified in 'mapUpdate'.
|
|
|
|
AffineExprComposer(const AffineMapCompositionUpdate &mapUpdate)
|
|
|
|
: mapUpdate(mapUpdate), walkingInputMap(false) {}
|
|
|
|
|
2018-10-09 04:47:18 +08:00
|
|
|
AffineExpr walk(AffineExpr expr) {
|
2018-10-10 01:59:27 +08:00
|
|
|
switch (expr.getKind()) {
|
2018-10-09 02:10:11 +08:00
|
|
|
case AffineExprKind::Add:
|
|
|
|
return walkBinExpr(
|
2018-10-09 04:47:18 +08:00
|
|
|
expr, [](AffineExpr lhs, AffineExpr rhs) { return lhs + rhs; });
|
2018-10-09 02:10:11 +08:00
|
|
|
case AffineExprKind::Mul:
|
|
|
|
return walkBinExpr(
|
2018-10-09 04:47:18 +08:00
|
|
|
expr, [](AffineExpr lhs, AffineExpr rhs) { return lhs * rhs; });
|
2018-10-09 02:10:11 +08:00
|
|
|
case AffineExprKind::Mod:
|
|
|
|
return walkBinExpr(
|
2018-10-09 04:47:18 +08:00
|
|
|
expr, [](AffineExpr lhs, AffineExpr rhs) { return lhs % rhs; });
|
2018-10-09 02:10:11 +08:00
|
|
|
case AffineExprKind::FloorDiv:
|
2018-10-09 04:47:18 +08:00
|
|
|
return walkBinExpr(expr, [](AffineExpr lhs, AffineExpr rhs) {
|
2018-10-09 02:10:11 +08:00
|
|
|
return lhs.floorDiv(rhs);
|
|
|
|
});
|
|
|
|
case AffineExprKind::CeilDiv:
|
2018-10-09 04:47:18 +08:00
|
|
|
return walkBinExpr(expr, [](AffineExpr lhs, AffineExpr rhs) {
|
2018-10-09 02:10:11 +08:00
|
|
|
return lhs.ceilDiv(rhs);
|
|
|
|
});
|
|
|
|
case AffineExprKind::Constant:
|
|
|
|
return expr;
|
|
|
|
case AffineExprKind::DimId: {
|
2018-10-10 01:59:27 +08:00
|
|
|
unsigned dimPosition = expr.cast<AffineDimExpr>().getPosition();
|
2018-10-09 02:10:11 +08:00
|
|
|
if (walkingInputMap) {
|
|
|
|
return getAffineDimExpr(mapUpdate.inputDimMap.lookup(dimPosition),
|
2018-10-10 01:59:27 +08:00
|
|
|
expr.getContext());
|
2018-10-09 02:10:11 +08:00
|
|
|
}
|
|
|
|
// Check if we are just mapping this dim to another position.
|
|
|
|
if (mapUpdate.currDimMap.count(dimPosition) > 0) {
|
|
|
|
assert(mapUpdate.currDimToInputResultMap.count(dimPosition) == 0);
|
|
|
|
return getAffineDimExpr(mapUpdate.currDimMap.lookup(dimPosition),
|
2018-10-10 01:59:27 +08:00
|
|
|
expr.getContext());
|
2018-10-09 02:10:11 +08:00
|
|
|
}
|
|
|
|
// We are substituting an input map result at 'dimPositon'
|
|
|
|
// Forward substitute currDimToInputResultMap[dimPosition] into this
|
|
|
|
// map.
|
|
|
|
AffineExprComposer composer(mapUpdate, /*walkingInputMap=*/true);
|
|
|
|
unsigned inputResultIndex =
|
|
|
|
mapUpdate.currDimToInputResultMap.lookup(dimPosition);
|
|
|
|
assert(inputResultIndex < mapUpdate.inputResults.size());
|
|
|
|
return composer.walk(mapUpdate.inputResults[inputResultIndex]);
|
|
|
|
}
|
|
|
|
case AffineExprKind::SymbolId:
|
2018-10-10 01:59:27 +08:00
|
|
|
unsigned symbolPosition = expr.cast<AffineSymbolExpr>().getPosition();
|
2018-10-09 02:10:11 +08:00
|
|
|
if (walkingInputMap) {
|
|
|
|
return getAffineSymbolExpr(
|
2018-10-10 01:59:27 +08:00
|
|
|
mapUpdate.inputSymbolMap.lookup(symbolPosition), expr.getContext());
|
2018-10-09 02:10:11 +08:00
|
|
|
}
|
|
|
|
return getAffineSymbolExpr(mapUpdate.currSymbolMap.lookup(symbolPosition),
|
2018-10-10 01:59:27 +08:00
|
|
|
expr.getContext());
|
2018-10-09 02:10:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
AffineExprComposer(const AffineMapCompositionUpdate &mapUpdate,
|
|
|
|
bool walkingInputMap)
|
|
|
|
: mapUpdate(mapUpdate), walkingInputMap(walkingInputMap) {}
|
|
|
|
|
2018-10-09 04:47:18 +08:00
|
|
|
AffineExpr walkBinExpr(AffineExpr expr,
|
|
|
|
std::function<AffineExpr(AffineExpr, AffineExpr)> op) {
|
|
|
|
auto binOpExpr = expr.cast<AffineBinaryOpExpr>();
|
2018-10-10 01:59:27 +08:00
|
|
|
return op(walk(binOpExpr.getLHS()), walk(binOpExpr.getRHS()));
|
2018-10-09 02:10:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Map update specifies to dim and symbol postion maps, as well as the input
|
|
|
|
// result AffineExprs to forward subustitute into the input map.
|
|
|
|
const AffineMapCompositionUpdate &mapUpdate;
|
|
|
|
// True if we are walking an AffineExpr in the 'input' map, false if
|
|
|
|
// we are walking the 'input' map.
|
|
|
|
bool walkingInputMap;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
|
|
|
static void
|
2018-10-09 12:02:12 +08:00
|
|
|
forwardSubstituteMutableAffineMap(const AffineMapCompositionUpdate &mapUpdate,
|
|
|
|
MutableAffineMap *map) {
|
2018-10-09 02:10:11 +08:00
|
|
|
for (unsigned i = 0, e = map->getNumResults(); i < e; i++) {
|
|
|
|
AffineExprComposer composer(mapUpdate);
|
|
|
|
map->setResult(i, composer.walk(map->getResult(i)));
|
|
|
|
}
|
|
|
|
// TODO(andydavis) Evaluate if we need to update range sizes here.
|
|
|
|
map->setNumDims(mapUpdate.outputNumDims);
|
|
|
|
map->setNumSymbols(mapUpdate.outputNumSymbols);
|
|
|
|
}
|
2018-09-05 06:55:38 +08:00
|
|
|
|
2018-10-10 07:39:24 +08:00
|
|
|
MutableAffineMap::MutableAffineMap(AffineMap map)
|
|
|
|
: numDims(map.getNumDims()), numSymbols(map.getNumSymbols()),
|
|
|
|
// A map always has at leat 1 result by construction
|
|
|
|
context(map.getResult(0).getContext()) {
|
|
|
|
for (auto result : map.getResults())
|
2018-08-22 01:32:24 +08:00
|
|
|
results.push_back(result);
|
2018-10-10 07:39:24 +08:00
|
|
|
for (auto rangeSize : map.getRangeSizes())
|
2018-08-22 01:32:24 +08:00
|
|
|
results.push_back(rangeSize);
|
|
|
|
}
|
|
|
|
|
2018-08-31 08:35:15 +08:00
|
|
|
bool MutableAffineMap::isMultipleOf(unsigned idx, int64_t factor) const {
|
2018-10-10 01:59:27 +08:00
|
|
|
if (results[idx].isMultipleOf(factor))
|
2018-08-31 08:35:15 +08:00
|
|
|
return true;
|
|
|
|
|
2018-09-05 06:55:38 +08:00
|
|
|
// TODO(bondhugula): use simplifyAffineExpr and FlatAffineConstraints to
|
|
|
|
// complete this (for a more powerful analysis).
|
2018-08-31 08:35:15 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-09-05 06:55:38 +08:00
|
|
|
// Simplifies the result affine expressions of this map. The expressions have to
|
|
|
|
// be pure for the simplification implemented.
|
|
|
|
void MutableAffineMap::simplify() {
|
|
|
|
// Simplify each of the results if possible.
|
2018-10-04 06:39:12 +08:00
|
|
|
// TODO(ntv): functional-style map
|
2018-09-05 06:55:38 +08:00
|
|
|
for (unsigned i = 0, e = getNumResults(); i < e; i++) {
|
2018-10-04 06:39:12 +08:00
|
|
|
results[i] = simplifyAffineExpr(getResult(i), numDims, numSymbols);
|
2018-09-05 06:55:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-10 07:39:24 +08:00
|
|
|
AffineMap MutableAffineMap::getAffineMap() {
|
2018-10-09 04:47:18 +08:00
|
|
|
return AffineMap::get(numDims, numSymbols, results, rangeSizes);
|
2018-10-09 02:10:11 +08:00
|
|
|
}
|
|
|
|
|
2018-10-11 00:45:59 +08:00
|
|
|
MutableIntegerSet::MutableIntegerSet(IntegerSet set, MLIRContext *context)
|
|
|
|
: numDims(set.getNumDims()), numSymbols(set.getNumSymbols()),
|
2018-08-31 08:35:15 +08:00
|
|
|
context(context) {
|
2018-08-22 01:32:24 +08:00
|
|
|
// TODO(bondhugula)
|
|
|
|
}
|
|
|
|
|
2018-08-26 08:17:56 +08:00
|
|
|
// Universal set.
|
2018-08-31 08:35:15 +08:00
|
|
|
MutableIntegerSet::MutableIntegerSet(unsigned numDims, unsigned numSymbols,
|
|
|
|
MLIRContext *context)
|
|
|
|
: numDims(numDims), numSymbols(numSymbols), context(context) {}
|
2018-08-26 08:17:56 +08:00
|
|
|
|
2018-10-10 07:39:24 +08:00
|
|
|
AffineValueMap::AffineValueMap(const AffineApplyOp &op)
|
|
|
|
: map(op.getAffineMap()) {
|
2018-10-09 02:10:11 +08:00
|
|
|
for (auto *operand : op.getOperands())
|
|
|
|
operands.push_back(cast<MLValue>(const_cast<SSAValue *>(operand)));
|
|
|
|
for (unsigned i = 0, e = op.getNumResults(); i < e; i++)
|
|
|
|
results.push_back(cast<MLValue>(const_cast<SSAValue *>(op.getResult(i))));
|
|
|
|
}
|
|
|
|
|
2018-10-10 07:39:24 +08:00
|
|
|
AffineValueMap::AffineValueMap(AffineMap map, ArrayRef<MLValue *> operands)
|
|
|
|
: map(map) {
|
2018-10-09 02:10:11 +08:00
|
|
|
for (MLValue *operand : operands) {
|
|
|
|
this->operands.push_back(operand);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true and sets 'indexOfMatch' if 'valueToMatch' is found in
|
|
|
|
// 'valuesToSearch'. Returns false otherwise.
|
|
|
|
static bool findIndex(MLValue *valueToMatch, ArrayRef<MLValue *> valuesToSearch,
|
|
|
|
unsigned &indexOfMatch) {
|
|
|
|
unsigned size = valuesToSearch.size();
|
|
|
|
for (unsigned i = 0; i < size; ++i) {
|
|
|
|
if (valueToMatch == valuesToSearch[i]) {
|
|
|
|
indexOfMatch = i;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// AffineValueMap forward substitution composes results from the affine map
|
|
|
|
// associated with 'inputOp', with the map it currently represents. This is
|
|
|
|
// accomplished by updating its MutableAffineMap and operand list to represent
|
|
|
|
// a new 'output' map which is the composition of the 'current' and 'input'
|
|
|
|
// maps (see "Affine map composition terminology" above for details).
|
|
|
|
//
|
|
|
|
// Affine map forward substitution is comprised of the following steps:
|
|
|
|
// *) Compute input affine map result indices used by the current map.
|
|
|
|
// *) Gather all dim and symbol positions from all AffineExpr input results
|
|
|
|
// computed in previous step.
|
|
|
|
// *) Build output operand list:
|
|
|
|
// *) Add curr map dim operands:
|
|
|
|
// *) If curr dim operand is being forward substituted by result of input
|
|
|
|
// map, store mapping from curr postion to input result index.
|
|
|
|
// *) Else add curr dim operand to output operand list.
|
|
|
|
// *) Add input map dim operands:
|
|
|
|
// *) If input map dim operand is used (step 2), add to output operand
|
|
|
|
// list (scanning current list for dups before updating mapping).
|
|
|
|
// *) Add curr map dim symbols.
|
|
|
|
// *) Add input map dim symbols (if used from step 2), dedup if needed.
|
|
|
|
// *) Update operands and forward substitute new dim and symbol mappings
|
|
|
|
// into MutableAffineMap 'map'.
|
|
|
|
//
|
|
|
|
// TODO(andydavis) Move this to a function which can be shared with
|
2018-10-09 12:02:12 +08:00
|
|
|
// forwardSubstitute(const AffineValueMap &inputMap).
|
|
|
|
void AffineValueMap::forwardSubstitute(const AffineApplyOp &inputOp) {
|
2018-10-09 02:10:11 +08:00
|
|
|
unsigned currNumDims = map.getNumDims();
|
|
|
|
unsigned inputNumResults = inputOp.getNumResults();
|
|
|
|
|
|
|
|
// Gather result indices from 'inputOp' used by current map.
|
|
|
|
DenseSet<unsigned> inputResultsUsed;
|
|
|
|
DenseMap<unsigned, unsigned> currOperandToInputResult;
|
|
|
|
for (unsigned i = 0; i < currNumDims; ++i) {
|
|
|
|
for (unsigned j = 0; j < inputNumResults; ++j) {
|
|
|
|
if (operands[i] ==
|
|
|
|
cast<MLValue>(const_cast<SSAValue *>(inputOp.getResult(j)))) {
|
|
|
|
currOperandToInputResult[i] = j;
|
|
|
|
inputResultsUsed.insert(j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return if there were no uses of 'inputOp' results in 'operands'.
|
|
|
|
if (inputResultsUsed.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
class AffineExprPositionGatherer
|
|
|
|
: public AffineExprVisitor<AffineExprPositionGatherer> {
|
|
|
|
public:
|
|
|
|
unsigned numDims;
|
|
|
|
DenseSet<unsigned> *positions;
|
|
|
|
AffineExprPositionGatherer(unsigned numDims, DenseSet<unsigned> *positions)
|
|
|
|
: numDims(numDims), positions(positions) {}
|
2018-10-09 04:47:18 +08:00
|
|
|
void visitDimExpr(AffineDimExpr expr) {
|
2018-10-10 01:59:27 +08:00
|
|
|
positions->insert(expr.getPosition());
|
2018-10-09 02:10:11 +08:00
|
|
|
}
|
2018-10-09 04:47:18 +08:00
|
|
|
void visitSymbolExpr(AffineSymbolExpr expr) {
|
2018-10-10 01:59:27 +08:00
|
|
|
positions->insert(numDims + expr.getPosition());
|
2018-10-09 02:10:11 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Gather dim and symbol positions from 'inputOp' on which
|
|
|
|
// 'inputResultsUsed' depend.
|
2018-10-10 07:39:24 +08:00
|
|
|
AffineMap inputMap = inputOp.getAffineMap();
|
|
|
|
unsigned inputNumDims = inputMap.getNumDims();
|
2018-10-09 02:10:11 +08:00
|
|
|
DenseSet<unsigned> inputPositionsUsed;
|
|
|
|
AffineExprPositionGatherer gatherer(inputNumDims, &inputPositionsUsed);
|
|
|
|
for (unsigned i = 0; i < inputNumResults; ++i) {
|
|
|
|
if (inputResultsUsed.count(i) == 0)
|
|
|
|
continue;
|
2018-10-10 07:39:24 +08:00
|
|
|
gatherer.walkPostOrder(inputMap.getResult(i));
|
2018-10-09 02:10:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Build new output operands list and map update.
|
|
|
|
SmallVector<MLValue *, 4> outputOperands;
|
|
|
|
unsigned outputOperandPosition = 0;
|
2018-10-10 07:39:24 +08:00
|
|
|
AffineMapCompositionUpdate mapUpdate(inputOp.getAffineMap().getResults());
|
2018-10-09 02:10:11 +08:00
|
|
|
|
|
|
|
// Add dim operands from current map.
|
|
|
|
for (unsigned i = 0; i < currNumDims; ++i) {
|
|
|
|
if (currOperandToInputResult.count(i) > 0) {
|
|
|
|
mapUpdate.currDimToInputResultMap[i] = currOperandToInputResult[i];
|
|
|
|
} else {
|
|
|
|
mapUpdate.currDimMap[i] = outputOperandPosition++;
|
|
|
|
outputOperands.push_back(operands[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add dim operands from input map.
|
|
|
|
for (unsigned i = 0; i < inputNumDims; ++i) {
|
|
|
|
// Skip input dim operands that we won't use.
|
|
|
|
if (inputPositionsUsed.count(i) == 0)
|
|
|
|
continue;
|
|
|
|
// Check if input operand has a dup in current operand list.
|
|
|
|
auto *inputOperand =
|
|
|
|
cast<MLValue>(const_cast<SSAValue *>(inputOp.getOperand(i)));
|
|
|
|
unsigned outputIndex;
|
|
|
|
if (findIndex(inputOperand, outputOperands, outputIndex)) {
|
|
|
|
mapUpdate.inputDimMap[i] = outputIndex;
|
|
|
|
} else {
|
|
|
|
mapUpdate.inputDimMap[i] = outputOperandPosition++;
|
|
|
|
outputOperands.push_back(inputOperand);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Done adding dimension operands, so store new output num dims.
|
|
|
|
unsigned outputNumDims = outputOperandPosition;
|
|
|
|
|
|
|
|
// Add symbol operands from current map.
|
|
|
|
unsigned currNumOperands = operands.size();
|
|
|
|
for (unsigned i = currNumDims; i < currNumOperands; ++i) {
|
|
|
|
unsigned currSymbolPosition = i - currNumDims;
|
|
|
|
unsigned outputSymbolPosition = outputOperandPosition - outputNumDims;
|
|
|
|
mapUpdate.currSymbolMap[currSymbolPosition] = outputSymbolPosition;
|
|
|
|
outputOperands.push_back(operands[i]);
|
|
|
|
++outputOperandPosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add symbol operands from input map.
|
|
|
|
unsigned inputNumOperands = inputOp.getNumOperands();
|
|
|
|
for (unsigned i = inputNumDims; i < inputNumOperands; ++i) {
|
|
|
|
// Skip input symbol operands that we won't use.
|
|
|
|
if (inputPositionsUsed.count(i) == 0)
|
|
|
|
continue;
|
|
|
|
unsigned inputSymbolPosition = i - inputNumDims;
|
|
|
|
// Check if input operand has a dup in current operand list.
|
|
|
|
auto *inputOperand =
|
|
|
|
cast<MLValue>(const_cast<SSAValue *>(inputOp.getOperand(i)));
|
|
|
|
// Find output operand index of 'inputOperand' dup.
|
|
|
|
unsigned outputIndex;
|
|
|
|
if (findIndex(inputOperand, outputOperands, outputIndex)) {
|
|
|
|
unsigned outputSymbolPosition = outputIndex - outputNumDims;
|
|
|
|
mapUpdate.inputSymbolMap[inputSymbolPosition] = outputSymbolPosition;
|
|
|
|
} else {
|
|
|
|
unsigned outputSymbolPosition = outputOperandPosition - outputNumDims;
|
|
|
|
mapUpdate.inputSymbolMap[inputSymbolPosition] = outputSymbolPosition;
|
|
|
|
outputOperands.push_back(inputOperand);
|
|
|
|
++outputOperandPosition;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set output number of dimension and symbol operands.
|
|
|
|
mapUpdate.outputNumDims = outputNumDims;
|
|
|
|
mapUpdate.outputNumSymbols = outputOperands.size() - outputNumDims;
|
|
|
|
|
|
|
|
// Update 'operands' with new 'outputOperands'.
|
|
|
|
operands.swap(outputOperands);
|
|
|
|
// Forward substitute 'mapUpdate' into 'map'.
|
2018-10-09 12:02:12 +08:00
|
|
|
forwardSubstituteMutableAffineMap(mapUpdate, &map);
|
2018-08-22 01:32:24 +08:00
|
|
|
}
|
|
|
|
|
2018-08-31 08:35:15 +08:00
|
|
|
inline bool AffineValueMap::isMultipleOf(unsigned idx, int64_t factor) const {
|
|
|
|
return map.isMultipleOf(idx, factor);
|
2018-08-22 01:32:24 +08:00
|
|
|
}
|
|
|
|
|
2018-10-09 02:10:11 +08:00
|
|
|
unsigned AffineValueMap::getNumOperands() const { return operands.size(); }
|
|
|
|
|
|
|
|
SSAValue *AffineValueMap::getOperand(unsigned i) const {
|
|
|
|
return static_cast<SSAValue *>(operands[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
ArrayRef<MLValue *> AffineValueMap::getOperands() const {
|
|
|
|
return ArrayRef<MLValue *>(operands);
|
|
|
|
}
|
|
|
|
|
2018-10-10 07:39:24 +08:00
|
|
|
AffineMap AffineValueMap::getAffineMap() { return map.getAffineMap(); }
|
2018-10-09 02:10:11 +08:00
|
|
|
|
2018-08-22 01:32:24 +08:00
|
|
|
AffineValueMap::~AffineValueMap() {}
|
|
|
|
|
2018-08-31 08:35:15 +08:00
|
|
|
void FlatAffineConstraints::addEquality(ArrayRef<int64_t> eq) {
|
|
|
|
assert(eq.size() == getNumCols());
|
|
|
|
unsigned offset = equalities.size();
|
|
|
|
equalities.resize(equalities.size() + eq.size());
|
|
|
|
for (unsigned i = 0, e = eq.size(); i < e; i++) {
|
|
|
|
equalities[offset + i] = eq[i];
|
|
|
|
}
|
|
|
|
}
|