blob: 5b29467fc4434715eef1bbe9c7245f9e90b077c9 [file] [log] [blame]
//===- AffineOps.cpp - MLIR Affine Operations -----------------------------===//
//
// 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.
// =============================================================================
#include "mlir/AffineOps/AffineOps.h"
#include "mlir/IR/Block.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/OpImplementation.h"
using namespace mlir;
//===----------------------------------------------------------------------===//
// AffineOpsDialect
//===----------------------------------------------------------------------===//
AffineOpsDialect::AffineOpsDialect(MLIRContext *context)
: Dialect(/*namePrefix=*/"", context) {
addOperations<AffineIfOp>();
}
//===----------------------------------------------------------------------===//
// AffineIfOp
//===----------------------------------------------------------------------===//
void AffineIfOp::build(Builder *builder, OperationState *result,
IntegerSet condition,
ArrayRef<Value *> conditionOperands) {
result->addAttribute(getConditionAttrName(), IntegerSetAttr::get(condition));
result->addOperands(conditionOperands);
// Reserve 2 block lists, one for the 'then' and one for the 'else' regions.
result->reserveBlockLists(2);
}
bool AffineIfOp::verify() const {
// Verify that we have a condition attribute.
auto conditionAttr = getAttrOfType<IntegerSetAttr>(getConditionAttrName());
if (!conditionAttr)
return emitOpError("requires an integer set attribute named 'condition'");
// Verify that the operands are valid dimension/symbols.
IntegerSet condition = conditionAttr.getValue();
for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
const Value *operand = getOperand(i);
if (i < condition.getNumDims() && !operand->isValidDim())
return emitOpError("operand cannot be used as a dimension id");
if (i >= condition.getNumDims() && !operand->isValidSymbol())
return emitOpError("operand cannot be used as a symbol");
}
// Verify that the entry of each child blocklist does not have arguments.
for (const auto &blockList : getInstruction()->getBlockLists()) {
if (blockList.empty())
continue;
// TODO(riverriddle) We currently do not allow multiple blocks in child
// block lists.
if (std::next(blockList.begin()) != blockList.end())
return emitOpError(
"expects only one block per 'if' or 'else' block list");
if (blockList.front().getTerminator())
return emitOpError("expects region block to not have a terminator");
for (const auto &b : blockList)
if (b.getNumArguments() != 0)
return emitOpError(
"requires that child entry blocks have no arguments");
}
return false;
}
bool AffineIfOp::parse(OpAsmParser *parser, OperationState *result) {
// Parse the condition attribute set.
IntegerSetAttr conditionAttr;
unsigned numDims;
if (parser->parseAttribute(conditionAttr, getConditionAttrName().data(),
result->attributes) ||
parseDimAndSymbolList(parser, result->operands, numDims))
return true;
// Verify the condition operands.
auto set = conditionAttr.getValue();
if (set.getNumDims() != numDims)
return parser->emitError(
parser->getNameLoc(),
"dim operand count and integer set dim count must match");
if (numDims + set.getNumSymbols() != result->operands.size())
return parser->emitError(
parser->getNameLoc(),
"symbol operand count and integer set symbol count must match");
// Parse the 'then' block list.
if (parser->parseBlockList())
return true;
// If we find an 'else' keyword then parse the else block list.
if (!parser->parseOptionalKeyword("else")) {
if (parser->parseBlockList())
return true;
}
// Reserve 2 block lists, one for the 'then' and one for the 'else' regions.
result->reserveBlockLists(2);
return false;
}
void AffineIfOp::print(OpAsmPrinter *p) const {
auto conditionAttr = getAttrOfType<IntegerSetAttr>(getConditionAttrName());
*p << "if " << conditionAttr;
printDimAndSymbolList(operand_begin(), operand_end(),
conditionAttr.getValue().getNumDims(), p);
p->printBlockList(getInstruction()->getBlockList(0));
// Print the 'else' block list if it has any blocks.
const auto &elseBlockList = getInstruction()->getBlockList(1);
if (!elseBlockList.empty()) {
*p << " else";
p->printBlockList(elseBlockList);
}
}
IntegerSet AffineIfOp::getIntegerSet() const {
return getAttrOfType<IntegerSetAttr>(getConditionAttrName()).getValue();
}
void AffineIfOp::setIntegerSet(IntegerSet newSet) {
setAttr(
Identifier::get(getConditionAttrName(), getInstruction()->getContext()),
IntegerSetAttr::get(newSet));
}
/// Returns the list of 'then' blocks.
BlockList &AffineIfOp::getThenBlocks() {
return getInstruction()->getBlockList(0);
}
/// Returns the list of 'else' blocks.
BlockList &AffineIfOp::getElseBlocks() {
return getInstruction()->getBlockList(1);
}