blob: 4da0d60d49aa1f296664b804de193ce5b6a5412f [file] [log] [blame]
Chris Lattnerff0d5902018-07-05 09:12:11 -07001//===- StandardOps.cpp - Standard MLIR Operations -------------------------===//
2//
3// Copyright 2019 The MLIR Authors.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16// =============================================================================
17
18#include "mlir/IR/StandardOps.h"
MLIR Team3fa00ab2018-07-24 10:13:31 -070019#include "mlir/IR/AffineMap.h"
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -070020#include "mlir/IR/OpImplementation.h"
Chris Lattnerff0d5902018-07-05 09:12:11 -070021#include "mlir/IR/OperationSet.h"
Chris Lattner9361fb32018-07-24 08:34:58 -070022#include "mlir/IR/SSAValue.h"
23#include "mlir/IR/Types.h"
Chris Lattnerff0d5902018-07-05 09:12:11 -070024#include "llvm/Support/raw_ostream.h"
25using namespace mlir;
26
MLIR Team39a3a602018-07-24 17:43:56 -070027// TODO: Have verify functions return std::string to enable more descriptive
28// error messages.
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -070029void AddFOp::print(OpAsmPrinter *p) const {
30 *p << "addf " << *getOperand(0) << ", " << *getOperand(1) << " : "
31 << *getType();
Chris Lattnerff0d5902018-07-05 09:12:11 -070032}
33
Chris Lattner21e67f62018-07-06 10:46:19 -070034// Return an error message on failure.
35const char *AddFOp::verify() const {
36 // TODO: Check that the types of the LHS and RHS match.
37 // TODO: This should be a refinement of TwoOperands.
38 // TODO: There should also be a OneResultWhoseTypeMatchesFirstOperand.
39 return nullptr;
40}
41
Chris Lattner9361fb32018-07-24 08:34:58 -070042/// The constant op requires an attribute, and furthermore requires that it
43/// matches the return type.
44const char *ConstantOp::verify() const {
45 auto *value = getValue();
46 if (!value)
47 return "requires a 'value' attribute";
48
49 auto *type = this->getType();
Chris Lattner1ec70572018-07-24 10:41:30 -070050 if (isa<IntegerType>(type) || type->isAffineInt()) {
Chris Lattner9361fb32018-07-24 08:34:58 -070051 if (!isa<IntegerAttr>(value))
52 return "requires 'value' to be an integer for an integer result type";
53 return nullptr;
54 }
55
56 if (isa<FunctionType>(type)) {
57 // TODO: Verify a function attr.
58 }
59
60 return "requires a result type that aligns with the 'value' attribute";
61}
62
63/// ConstantIntOp only matches values whose result type is an IntegerType.
64bool ConstantIntOp::isClassFor(const Operation *op) {
65 return ConstantOp::isClassFor(op) &&
66 isa<IntegerType>(op->getResult(0)->getType());
67}
68
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -070069void DimOp::print(OpAsmPrinter *p) const {
70 *p << "dim " << *getOperand() << ", " << getIndex() << " : "
71 << *getOperand()->getType();
Chris Lattnerff0d5902018-07-05 09:12:11 -070072}
73
Chris Lattner21e67f62018-07-06 10:46:19 -070074const char *DimOp::verify() const {
Chris Lattner21e67f62018-07-06 10:46:19 -070075 // Check that we have an integer index operand.
76 auto indexAttr = getAttrOfType<IntegerAttr>("index");
77 if (!indexAttr)
Chris Lattner9361fb32018-07-24 08:34:58 -070078 return "requires an integer attribute named 'index'";
79 uint64_t index = (uint64_t)indexAttr->getValue();
Chris Lattner21e67f62018-07-06 10:46:19 -070080
Chris Lattner9361fb32018-07-24 08:34:58 -070081 auto *type = getOperand()->getType();
82 if (auto *tensorType = dyn_cast<RankedTensorType>(type)) {
83 if (index >= tensorType->getRank())
84 return "index is out of range";
85 } else if (auto *memrefType = dyn_cast<MemRefType>(type)) {
86 if (index >= memrefType->getRank())
87 return "index is out of range";
88
89 } else if (isa<UnrankedTensorType>(type)) {
90 // ok, assumed to be in-range.
91 } else {
92 return "requires an operand with tensor or memref type";
93 }
Chris Lattner21e67f62018-07-06 10:46:19 -070094
95 return nullptr;
96}
97
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -070098void AffineApplyOp::print(OpAsmPrinter *p) const {
99 // TODO: Print operands etc.
100 *p << "affine_apply map: " << *getAffineMap();
MLIR Team3fa00ab2018-07-24 10:13:31 -0700101}
102
103const char *AffineApplyOp::verify() const {
MLIR Team3fa00ab2018-07-24 10:13:31 -0700104 // Check that affine map attribute was specified
105 auto affineMapAttr = getAttrOfType<AffineMapAttr>("map");
106 if (!affineMapAttr)
107 return "requires an affine map.";
108
MLIR Team39a3a602018-07-24 17:43:56 -0700109 // Check input and output dimensions match.
110 auto *map = affineMapAttr->getValue();
111
112 // Verify that operand count matches affine map dimension and symbol count.
113 if (getNumOperands() != map->getNumDims() + map->getNumSymbols())
114 return "operand count and affine map dimension and symbol count must match";
115
116 // Verify that result count matches affine map result count.
117 if (getNumResults() != map->getNumResults())
118 return "result count and affine map result count must match";
119
MLIR Team3fa00ab2018-07-24 10:13:31 -0700120 return nullptr;
121}
122
Chris Lattnerff0d5902018-07-05 09:12:11 -0700123/// Install the standard operations in the specified operation set.
124void mlir::registerStandardOperations(OperationSet &opSet) {
MLIR Team3fa00ab2018-07-24 10:13:31 -0700125 opSet.addOperations<AddFOp, ConstantOp, DimOp, AffineApplyOp>(/*prefix=*/"");
Chris Lattnerff0d5902018-07-05 09:12:11 -0700126}