blob: 069f3eda7563b7b8eb7ecbb3f6872e21c799e38d [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 Lattner85ee1512018-07-25 11:15:20 -070020#include "mlir/IR/Builders.h"
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -070021#include "mlir/IR/OpImplementation.h"
Chris Lattnerff0d5902018-07-05 09:12:11 -070022#include "mlir/IR/OperationSet.h"
Chris Lattner9361fb32018-07-24 08:34:58 -070023#include "mlir/IR/SSAValue.h"
24#include "mlir/IR/Types.h"
Chris Lattnerff0d5902018-07-05 09:12:11 -070025#include "llvm/Support/raw_ostream.h"
26using namespace mlir;
27
MLIR Team39a3a602018-07-24 17:43:56 -070028// TODO: Have verify functions return std::string to enable more descriptive
29// error messages.
Chris Lattner85ee1512018-07-25 11:15:20 -070030OpAsmParserResult AddFOp::parse(OpAsmParser *parser) {
31 SmallVector<OpAsmParser::OperandType, 2> ops;
32 Type *type;
33 SSAValue *lhs, *rhs;
34 if (parser->parseOperandList(ops, 2) || parser->parseColonType(type) ||
35 parser->resolveOperand(ops[0], type, lhs) ||
36 parser->resolveOperand(ops[1], type, rhs))
37 return {};
38
39 return OpAsmParserResult({lhs, rhs}, type);
40}
41
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -070042void AddFOp::print(OpAsmPrinter *p) const {
43 *p << "addf " << *getOperand(0) << ", " << *getOperand(1) << " : "
44 << *getType();
Chris Lattnerff0d5902018-07-05 09:12:11 -070045}
46
Chris Lattner21e67f62018-07-06 10:46:19 -070047// Return an error message on failure.
48const char *AddFOp::verify() const {
49 // TODO: Check that the types of the LHS and RHS match.
50 // TODO: This should be a refinement of TwoOperands.
51 // TODO: There should also be a OneResultWhoseTypeMatchesFirstOperand.
52 return nullptr;
53}
54
Chris Lattner9361fb32018-07-24 08:34:58 -070055/// The constant op requires an attribute, and furthermore requires that it
56/// matches the return type.
57const char *ConstantOp::verify() const {
58 auto *value = getValue();
59 if (!value)
60 return "requires a 'value' attribute";
61
62 auto *type = this->getType();
Chris Lattner1ec70572018-07-24 10:41:30 -070063 if (isa<IntegerType>(type) || type->isAffineInt()) {
Chris Lattner9361fb32018-07-24 08:34:58 -070064 if (!isa<IntegerAttr>(value))
65 return "requires 'value' to be an integer for an integer result type";
66 return nullptr;
67 }
68
69 if (isa<FunctionType>(type)) {
70 // TODO: Verify a function attr.
71 }
72
73 return "requires a result type that aligns with the 'value' attribute";
74}
75
76/// ConstantIntOp only matches values whose result type is an IntegerType.
77bool ConstantIntOp::isClassFor(const Operation *op) {
78 return ConstantOp::isClassFor(op) &&
79 isa<IntegerType>(op->getResult(0)->getType());
80}
81
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -070082void DimOp::print(OpAsmPrinter *p) const {
83 *p << "dim " << *getOperand() << ", " << getIndex() << " : "
84 << *getOperand()->getType();
Chris Lattnerff0d5902018-07-05 09:12:11 -070085}
86
Chris Lattner85ee1512018-07-25 11:15:20 -070087OpAsmParserResult DimOp::parse(OpAsmParser *parser) {
88 OpAsmParser::OperandType operandInfo;
89 IntegerAttr *indexAttr;
90 Type *type;
91 SSAValue *operand;
92 if (parser->parseOperand(operandInfo) || parser->parseComma() ||
93 parser->parseAttribute(indexAttr) || parser->parseColonType(type) ||
94 parser->resolveOperand(operandInfo, type, operand))
95 return {};
96
97 auto &builder = parser->getBuilder();
98 return OpAsmParserResult(
99 operand, builder.getAffineIntType(),
100 NamedAttribute(builder.getIdentifier("index"), indexAttr));
101}
102
Chris Lattner21e67f62018-07-06 10:46:19 -0700103const char *DimOp::verify() const {
Chris Lattner21e67f62018-07-06 10:46:19 -0700104 // Check that we have an integer index operand.
105 auto indexAttr = getAttrOfType<IntegerAttr>("index");
106 if (!indexAttr)
Chris Lattner9361fb32018-07-24 08:34:58 -0700107 return "requires an integer attribute named 'index'";
108 uint64_t index = (uint64_t)indexAttr->getValue();
Chris Lattner21e67f62018-07-06 10:46:19 -0700109
Chris Lattner9361fb32018-07-24 08:34:58 -0700110 auto *type = getOperand()->getType();
111 if (auto *tensorType = dyn_cast<RankedTensorType>(type)) {
112 if (index >= tensorType->getRank())
113 return "index is out of range";
114 } else if (auto *memrefType = dyn_cast<MemRefType>(type)) {
115 if (index >= memrefType->getRank())
116 return "index is out of range";
117
118 } else if (isa<UnrankedTensorType>(type)) {
119 // ok, assumed to be in-range.
120 } else {
121 return "requires an operand with tensor or memref type";
122 }
Chris Lattner21e67f62018-07-06 10:46:19 -0700123
124 return nullptr;
125}
126
Chris Lattner85ee1512018-07-25 11:15:20 -0700127void LoadOp::print(OpAsmPrinter *p) const {
128 *p << "load " << *getMemRef() << '[';
129 p->printOperands(getIndices());
130 *p << "] : " << *getMemRef()->getType();
131}
132
133OpAsmParserResult LoadOp::parse(OpAsmParser *parser) {
134 OpAsmParser::OperandType memrefInfo;
135 SmallVector<OpAsmParser::OperandType, 4> indexInfo;
136 MemRefType *type;
137 SmallVector<SSAValue *, 4> operands;
138
139 auto affineIntTy = parser->getBuilder().getAffineIntType();
140 if (parser->parseOperand(memrefInfo) ||
141 parser->parseOperandList(indexInfo, -1,
142 OpAsmParser::Delimeter::SquareDelimeter) ||
143 parser->parseColonType(type) ||
144 parser->resolveOperands(memrefInfo, type, operands) ||
145 parser->resolveOperands(indexInfo, affineIntTy, operands))
146 return {};
147
148 return OpAsmParserResult(operands, type->getElementType());
149}
150
151const char *LoadOp::verify() const {
152 // TODO: Check load
153 return nullptr;
154}
155
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700156void AffineApplyOp::print(OpAsmPrinter *p) const {
157 // TODO: Print operands etc.
158 *p << "affine_apply map: " << *getAffineMap();
MLIR Team3fa00ab2018-07-24 10:13:31 -0700159}
160
161const char *AffineApplyOp::verify() const {
MLIR Team3fa00ab2018-07-24 10:13:31 -0700162 // Check that affine map attribute was specified
163 auto affineMapAttr = getAttrOfType<AffineMapAttr>("map");
164 if (!affineMapAttr)
165 return "requires an affine map.";
166
MLIR Team39a3a602018-07-24 17:43:56 -0700167 // Check input and output dimensions match.
168 auto *map = affineMapAttr->getValue();
169
170 // Verify that operand count matches affine map dimension and symbol count.
171 if (getNumOperands() != map->getNumDims() + map->getNumSymbols())
172 return "operand count and affine map dimension and symbol count must match";
173
174 // Verify that result count matches affine map result count.
175 if (getNumResults() != map->getNumResults())
176 return "result count and affine map result count must match";
177
MLIR Team3fa00ab2018-07-24 10:13:31 -0700178 return nullptr;
179}
180
Chris Lattnerff0d5902018-07-05 09:12:11 -0700181/// Install the standard operations in the specified operation set.
182void mlir::registerStandardOperations(OperationSet &opSet) {
Chris Lattner85ee1512018-07-25 11:15:20 -0700183 opSet.addOperations<AddFOp, ConstantOp, DimOp, LoadOp, AffineApplyOp>(
184 /*prefix=*/"");
Chris Lattnerff0d5902018-07-05 09:12:11 -0700185}