[mlir][NFC] Move the definition of AffineApplyOp to ODS

This has been a long standing cleanup TODO.

Differential Revision: https://reviews.llvm.org/D76019
This commit is contained in:
River Riddle
2020-03-12 14:06:01 -07:00
parent 483f82b146
commit 7c211cf3af
5 changed files with 71 additions and 88 deletions

View File

@@ -23,6 +23,7 @@
#include "mlir/Transforms/LoopLikeInterface.h"
namespace mlir {
class AffineApplyOp;
class AffineBound;
class AffineDimExpr;
class AffineValueMap;
@@ -46,57 +47,6 @@ public:
Location loc) override;
};
/// The "affine.apply" operation applies an affine map to a list of operands,
/// yielding a single result. The operand list must be the same size as the
/// number of arguments to the affine mapping. All operands and the result are
/// of type 'Index'. This operation requires a single affine map attribute named
/// "map". For example:
///
/// %y = "affine.apply" (%x) { map: (d0) -> (d0 + 1) } :
/// (index) -> (index)
///
/// equivalently:
///
/// #map42 = (d0)->(d0+1)
/// %y = affine.apply #map42(%x)
///
class AffineApplyOp : public Op<AffineApplyOp, OpTrait::VariadicOperands,
OpTrait::OneResult, OpTrait::HasNoSideEffect> {
public:
using Op::Op;
/// Builds an affine apply op with the specified map and operands.
static void build(Builder *builder, OperationState &result, AffineMap map,
ValueRange operands);
/// Returns the affine map to be applied by this operation.
AffineMap getAffineMap() {
return getAttrOfType<AffineMapAttr>("map").getValue();
}
/// Returns the affine value map computed from this operation.
AffineValueMap getAffineValueMap();
/// Returns true if the result of this operation can be used as dimension id.
bool isValidDim();
/// Returns true if the result of this operation is a symbol.
bool isValidSymbol();
static StringRef getOperationName() { return "affine.apply"; }
operand_range getMapOperands() { return getOperands(); }
// Hooks to customize behavior of this op.
static ParseResult parse(OpAsmParser &parser, OperationState &result);
void print(OpAsmPrinter &p);
LogicalResult verify();
OpFoldResult fold(ArrayRef<Attribute> operands);
static void getCanonicalizationPatterns(OwningRewritePatternList &results,
MLIRContext *context);
};
/// AffineDmaStartOp starts a non-blocking DMA operation that transfers data
/// from a source memref to a destination memref. The source and destination
/// memref need not be of the same dimensionality, but need to have the same

View File

@@ -40,6 +40,60 @@ class Affine_Op<string mnemonic, list<OpTrait> traits = []> :
def ImplicitAffineTerminator
: SingleBlockImplicitTerminator<"AffineTerminatorOp">;
def AffineApplyOp : Affine_Op<"apply", [NoSideEffect]> {
let summary = "affine apply operation";
let description = [{
The affine.apply operation applies an affine mapping to a list of SSA
values, yielding a single SSA value. The number of dimension and symbol
arguments to affine.apply must be equal to the respective number of
dimensional and symbolic inputs to the affine mapping; the affine mapping
has to be one-dimensional, and so the affine.apply operation always returns
one value. The input operands and result must all have index type.
Example:
```mlir
#map10 = affine_map<(d0, d1) -> (d0 floordiv 8 + d1 floordiv 128)>
...
%1 = affine.apply #map10 (%s, %t)
// Inline example.
%2 = affine.apply affine_map<(i)[s0] -> (i+s0)> (%42)[%n]
```
}];
let arguments = (ins AffineMapAttr:$map, Variadic<Index>:$mapOperands);
let results = (outs Index);
// TODO: The auto-generated builders should check to see if the return type
// has a constant builder. That way we wouldn't need to explicitly specify the
// result types here.
let builders = [
OpBuilder<"Builder *builder, OperationState &result, "
"AffineMap map, ValueRange mapOperands", [{
build(builder, result, builder->getIndexType(), map, mapOperands);
}]>
];
let extraClassDeclaration = [{
/// Returns the affine map to be applied by this operation.
AffineMap getAffineMap() { return map(); }
/// Returns the affine value map computed from this operation.
AffineValueMap getAffineValueMap();
/// Returns true if the result of this operation can be used as dimension id.
bool isValidDim();
/// Returns true if the result of this operation is a symbol.
bool isValidSymbol();
operand_range getMapOperands() { return getOperands(); }
}];
let hasCanonicalizer = 1;
let hasFolder = 1;
}
def AffineForOp : Affine_Op<"for",
[ImplicitAffineTerminator, RecursiveSideEffects,
DeclareOpInterfaceMethods<LoopLikeOpInterface>]> {

View File

@@ -69,8 +69,7 @@ struct AffineInlinerInterface : public DialectInlinerInterface {
AffineOpsDialect::AffineOpsDialect(MLIRContext *context)
: Dialect(getDialectNamespace(), context) {
addOperations<AffineApplyOp, AffineDmaStartOp, AffineDmaWaitOp, AffineLoadOp,
AffineStoreOp,
addOperations<AffineDmaStartOp, AffineDmaWaitOp, AffineLoadOp, AffineStoreOp,
#define GET_OP_LIST
#include "mlir/Dialect/AffineOps/AffineOps.cpp.inc"
>();
@@ -217,18 +216,12 @@ verifyDimAndSymbolIdentifiers(OpTy &op, Operation::operand_range operands,
// AffineApplyOp
//===----------------------------------------------------------------------===//
void AffineApplyOp::build(Builder *builder, OperationState &result,
AffineMap map, ValueRange operands) {
result.addOperands(operands);
result.types.append(map.getNumResults(), builder->getIndexType());
result.addAttribute("map", AffineMapAttr::get(map));
}
AffineValueMap AffineApplyOp::getAffineValueMap() {
return AffineValueMap(getAffineMap(), getOperands(), getResult());
}
ParseResult AffineApplyOp::parse(OpAsmParser &parser, OperationState &result) {
static ParseResult parseAffineApplyOp(OpAsmParser &parser,
OperationState &result) {
auto &builder = parser.getBuilder();
auto indexTy = builder.getIndexType();
@@ -250,39 +243,25 @@ ParseResult AffineApplyOp::parse(OpAsmParser &parser, OperationState &result) {
return success();
}
void AffineApplyOp::print(OpAsmPrinter &p) {
p << "affine.apply " << getAttr("map");
printDimAndSymbolList(operand_begin(), operand_end(),
getAffineMap().getNumDims(), p);
p.printOptionalAttrDict(getAttrs(), /*elidedAttrs=*/{"map"});
static void print(OpAsmPrinter &p, AffineApplyOp op) {
p << AffineApplyOp::getOperationName() << " " << op.mapAttr();
printDimAndSymbolList(op.operand_begin(), op.operand_end(),
op.getAffineMap().getNumDims(), p);
p.printOptionalAttrDict(op.getAttrs(), /*elidedAttrs=*/{"map"});
}
LogicalResult AffineApplyOp::verify() {
// Check that affine map attribute was specified.
auto affineMapAttr = getAttrOfType<AffineMapAttr>("map");
if (!affineMapAttr)
return emitOpError("requires an affine map");
static LogicalResult verify(AffineApplyOp op) {
// Check input and output dimensions match.
auto map = affineMapAttr.getValue();
auto map = op.map();
// Verify that operand count matches affine map dimension and symbol count.
if (getNumOperands() != map.getNumDims() + map.getNumSymbols())
return emitOpError(
if (op.getNumOperands() != map.getNumDims() + map.getNumSymbols())
return op.emitOpError(
"operand count and affine map dimension and symbol count must match");
// Verify that all operands are of `index` type.
for (Type t : getOperandTypes()) {
if (!t.isIndex())
return emitOpError("operands must be of type 'index'");
}
if (!getResult().getType().isIndex())
return emitOpError("result must be of type 'index'");
// Verify that the map only produces one result.
if (map.getNumResults() != 1)
return emitOpError("mapping must produce one value");
return op.emitOpError("mapping must produce one value");
return success();
}

View File

@@ -5,7 +5,7 @@
func @affine_apply_operand_non_index(%arg0 : i32) {
// Custom parser automatically assigns all arguments the `index` so we must
// use the generic syntax here to exercise the verifier.
// expected-error@+1 {{operands must be of type 'index'}}
// expected-error@+1 {{op operand #0 must be index, but got 'i32'}}
%0 = "affine.apply"(%arg0) {map = affine_map<(d0) -> (d0)>} : (i32) -> (index)
return
}
@@ -15,7 +15,7 @@ func @affine_apply_operand_non_index(%arg0 : i32) {
func @affine_apply_resul_non_index(%arg0 : index) {
// Custom parser automatically assigns `index` as the result type so we must
// use the generic syntax here to exercise the verifier.
// expected-error@+1 {{result must be of type 'index'}}
// expected-error@+1 {{op result #0 must be index, but got 'i32'}}
%0 = "affine.apply"(%arg0) {map = affine_map<(d0) -> (d0)>} : (index) -> (i32)
return
}

View File

@@ -58,7 +58,7 @@ func @constant_wrong_type() {
func @affine_apply_no_map() {
^bb0:
%i = constant 0 : index
%x = "affine.apply" (%i) { } : (index) -> (index) // expected-error {{'affine.apply' op requires an affine map}}
%x = "affine.apply" (%i) { } : (index) -> (index) // expected-error {{'affine.apply' op requires attribute 'map'}}
return
}