2018-10-11 05:23:30 +08:00
|
|
|
//===- BuiltinOps.cpp - Builtin MLIR 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/IR/BuiltinOps.h"
|
|
|
|
#include "mlir/IR/AffineExpr.h"
|
|
|
|
#include "mlir/IR/AffineMap.h"
|
|
|
|
#include "mlir/IR/Builders.h"
|
2019-01-15 05:23:18 +08:00
|
|
|
#include "mlir/IR/Matchers.h"
|
2018-10-11 05:23:30 +08:00
|
|
|
#include "mlir/IR/OpImplementation.h"
|
2019-01-04 23:23:28 +08:00
|
|
|
#include "mlir/IR/PatternMatch.h"
|
2019-01-04 06:29:52 +08:00
|
|
|
#include "mlir/IR/StandardTypes.h"
|
2018-12-28 06:35:10 +08:00
|
|
|
#include "mlir/IR/Value.h"
|
2018-10-11 05:23:30 +08:00
|
|
|
#include "mlir/Support/MathExtras.h"
|
|
|
|
#include "mlir/Support/STLExtras.h"
|
2019-01-11 13:54:34 +08:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2018-10-11 05:23:30 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2019-01-08 12:28:18 +08:00
|
|
|
|
2018-10-11 05:23:30 +08:00
|
|
|
using namespace mlir;
|
|
|
|
|
2018-10-22 10:49:31 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// BuiltinDialect
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
BuiltinDialect::BuiltinDialect(MLIRContext *context)
|
2019-01-03 01:26:35 +08:00
|
|
|
: Dialect(/*namePrefix=*/"", context) {
|
2019-02-05 08:15:13 +08:00
|
|
|
addOperations<BranchOp, CondBranchOp, ConstantOp, ReturnOp>();
|
2019-01-08 01:58:34 +08:00
|
|
|
addTypes<FunctionType, IndexType, UnknownType, FloatType, IntegerType,
|
|
|
|
VectorType, RankedTensorType, UnrankedTensorType, MemRefType>();
|
2018-10-22 10:49:31 +08:00
|
|
|
}
|
|
|
|
|
2019-02-05 02:34:20 +08:00
|
|
|
void mlir::printDimAndSymbolList(Instruction::const_operand_iterator begin,
|
|
|
|
Instruction::const_operand_iterator end,
|
2018-10-11 05:23:30 +08:00
|
|
|
unsigned numDims, OpAsmPrinter *p) {
|
|
|
|
*p << '(';
|
|
|
|
p->printOperands(begin, begin + numDims);
|
|
|
|
*p << ')';
|
|
|
|
|
|
|
|
if (begin + numDims != end) {
|
|
|
|
*p << '[';
|
|
|
|
p->printOperands(begin + numDims, end);
|
|
|
|
*p << ']';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parses dimension and symbol list, and sets 'numDims' to the number of
|
|
|
|
// dimension operands parsed.
|
|
|
|
// Returns 'false' on success and 'true' on error.
|
|
|
|
bool mlir::parseDimAndSymbolList(OpAsmParser *parser,
|
2018-12-28 06:35:10 +08:00
|
|
|
SmallVector<Value *, 4> &operands,
|
2018-10-11 05:23:30 +08:00
|
|
|
unsigned &numDims) {
|
|
|
|
SmallVector<OpAsmParser::OperandType, 8> opInfos;
|
|
|
|
if (parser->parseOperandList(opInfos, -1, OpAsmParser::Delimiter::Paren))
|
|
|
|
return true;
|
|
|
|
// Store number of dimensions for validation by caller.
|
|
|
|
numDims = opInfos.size();
|
|
|
|
|
|
|
|
// Parse the optional symbol operands.
|
2018-10-31 05:59:22 +08:00
|
|
|
auto affineIntTy = parser->getBuilder().getIndexType();
|
2018-10-11 05:23:30 +08:00
|
|
|
if (parser->parseOperandList(opInfos, -1,
|
|
|
|
OpAsmParser::Delimiter::OptionalSquare) ||
|
|
|
|
parser->resolveOperands(opInfos, affineIntTy, operands))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-11-14 01:49:27 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// BranchOp
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-12-29 05:07:39 +08:00
|
|
|
void BranchOp::build(Builder *builder, OperationState *result, Block *dest,
|
2018-12-28 06:35:10 +08:00
|
|
|
ArrayRef<Value *> operands) {
|
2018-11-16 01:56:06 +08:00
|
|
|
result->addSuccessor(dest, operands);
|
|
|
|
}
|
2018-11-14 01:49:27 +08:00
|
|
|
|
|
|
|
bool BranchOp::parse(OpAsmParser *parser, OperationState *result) {
|
2018-12-29 05:07:39 +08:00
|
|
|
Block *dest;
|
2018-12-28 06:35:10 +08:00
|
|
|
SmallVector<Value *, 4> destOperands;
|
2018-11-16 01:56:06 +08:00
|
|
|
if (parser->parseSuccessorAndUseList(dest, destOperands))
|
|
|
|
return true;
|
|
|
|
result->addSuccessor(dest, destOperands);
|
|
|
|
return false;
|
2018-11-14 01:49:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void BranchOp::print(OpAsmPrinter *p) const {
|
|
|
|
*p << "br ";
|
2018-12-28 20:14:52 +08:00
|
|
|
p->printSuccessorAndUseList(getInstruction(), 0);
|
2018-11-14 01:49:27 +08:00
|
|
|
}
|
|
|
|
|
2018-12-29 05:07:39 +08:00
|
|
|
Block *BranchOp::getDest() { return getInstruction()->getSuccessor(0); }
|
2018-11-16 01:56:06 +08:00
|
|
|
|
2018-12-29 05:07:39 +08:00
|
|
|
void BranchOp::setDest(Block *block) {
|
2018-12-28 20:14:52 +08:00
|
|
|
return getInstruction()->setSuccessor(block, 0);
|
2018-11-16 01:56:06 +08:00
|
|
|
}
|
|
|
|
|
2018-11-21 06:03:41 +08:00
|
|
|
void BranchOp::eraseOperand(unsigned index) {
|
2018-12-28 20:14:52 +08:00
|
|
|
getInstruction()->eraseSuccessorOperand(0, index);
|
2018-11-21 06:03:41 +08:00
|
|
|
}
|
|
|
|
|
2018-11-14 01:49:27 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// CondBranchOp
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-01-15 05:23:18 +08:00
|
|
|
namespace {
|
|
|
|
/// cond_br true, ^bb1, ^bb2 -> br ^bb1
|
|
|
|
/// cond_br false, ^bb1, ^bb2 -> br ^bb2
|
|
|
|
///
|
|
|
|
struct SimplifyConstCondBranchPred : public RewritePattern {
|
|
|
|
SimplifyConstCondBranchPred(MLIRContext *context)
|
|
|
|
: RewritePattern(CondBranchOp::getOperationName(), 1, context) {}
|
|
|
|
|
2019-02-05 02:34:20 +08:00
|
|
|
PatternMatchResult match(Instruction *op) const override {
|
2019-01-15 05:23:18 +08:00
|
|
|
auto condbr = op->cast<CondBranchOp>();
|
|
|
|
if (matchPattern(condbr->getCondition(), m_Op<ConstantOp>()))
|
|
|
|
return matchSuccess();
|
|
|
|
|
|
|
|
return matchFailure();
|
|
|
|
}
|
2019-02-05 02:34:20 +08:00
|
|
|
void rewrite(Instruction *op, PatternRewriter &rewriter) const override {
|
2019-01-15 05:23:18 +08:00
|
|
|
auto condbr = op->cast<CondBranchOp>();
|
|
|
|
Block *foldedDest;
|
|
|
|
SmallVector<Value *, 4> branchArgs;
|
|
|
|
|
|
|
|
// If the condition is known to evaluate to false we fold to a branch to the
|
|
|
|
// false destination. Otherwise, we fold to a branch to the true
|
|
|
|
// destination.
|
|
|
|
if (matchPattern(condbr->getCondition(), m_Zero())) {
|
|
|
|
foldedDest = condbr->getFalseDest();
|
|
|
|
branchArgs.assign(condbr->false_operand_begin(),
|
|
|
|
condbr->false_operand_end());
|
|
|
|
} else {
|
|
|
|
foldedDest = condbr->getTrueDest();
|
|
|
|
branchArgs.assign(condbr->true_operand_begin(),
|
|
|
|
condbr->true_operand_end());
|
|
|
|
}
|
|
|
|
|
|
|
|
rewriter.replaceOpWithNewOp<BranchOp>(op, foldedDest, branchArgs);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end anonymous namespace.
|
|
|
|
|
2018-11-14 01:49:27 +08:00
|
|
|
void CondBranchOp::build(Builder *builder, OperationState *result,
|
2018-12-29 05:07:39 +08:00
|
|
|
Value *condition, Block *trueDest,
|
|
|
|
ArrayRef<Value *> trueOperands, Block *falseDest,
|
2018-12-28 06:35:10 +08:00
|
|
|
ArrayRef<Value *> falseOperands) {
|
2018-11-14 01:49:27 +08:00
|
|
|
result->addOperands(condition);
|
2018-12-26 09:11:06 +08:00
|
|
|
result->addSuccessor(trueDest, trueOperands);
|
|
|
|
result->addSuccessor(falseDest, falseOperands);
|
2018-11-14 01:49:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CondBranchOp::parse(OpAsmParser *parser, OperationState *result) {
|
2018-12-28 06:35:10 +08:00
|
|
|
SmallVector<Value *, 4> destOperands;
|
2018-12-29 05:07:39 +08:00
|
|
|
Block *dest;
|
2018-11-14 01:49:27 +08:00
|
|
|
OpAsmParser::OperandType condInfo;
|
|
|
|
|
2018-11-16 01:56:06 +08:00
|
|
|
// Parse the condition.
|
2018-11-29 03:49:26 +08:00
|
|
|
Type int1Ty = parser->getBuilder().getI1Type();
|
2018-11-16 01:56:06 +08:00
|
|
|
if (parser->parseOperand(condInfo) || parser->parseComma() ||
|
|
|
|
parser->resolveOperand(condInfo, int1Ty, result->operands)) {
|
2018-11-14 01:49:27 +08:00
|
|
|
return parser->emitError(parser->getNameLoc(),
|
|
|
|
"expected condition type was boolean (i1)");
|
|
|
|
}
|
2018-11-16 01:56:06 +08:00
|
|
|
|
|
|
|
// Parse the true successor.
|
|
|
|
if (parser->parseSuccessorAndUseList(dest, destOperands))
|
|
|
|
return true;
|
|
|
|
result->addSuccessor(dest, destOperands);
|
|
|
|
|
|
|
|
// Parse the false successor.
|
|
|
|
destOperands.clear();
|
|
|
|
if (parser->parseComma() ||
|
|
|
|
parser->parseSuccessorAndUseList(dest, destOperands))
|
|
|
|
return true;
|
|
|
|
result->addSuccessor(dest, destOperands);
|
|
|
|
|
|
|
|
// Return false on success.
|
2018-11-14 01:49:27 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CondBranchOp::print(OpAsmPrinter *p) const {
|
|
|
|
*p << "cond_br ";
|
|
|
|
p->printOperand(getCondition());
|
2018-11-16 01:56:06 +08:00
|
|
|
*p << ", ";
|
2018-12-28 20:14:52 +08:00
|
|
|
p->printSuccessorAndUseList(getInstruction(), trueIndex);
|
2018-11-16 01:56:06 +08:00
|
|
|
*p << ", ";
|
2018-12-28 20:14:52 +08:00
|
|
|
p->printSuccessorAndUseList(getInstruction(), falseIndex);
|
2018-11-14 01:49:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CondBranchOp::verify() const {
|
|
|
|
if (!getCondition()->getType().isInteger(1))
|
|
|
|
return emitOpError("expected condition type was boolean (i1)");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-01-15 05:23:18 +08:00
|
|
|
void CondBranchOp::getCanonicalizationPatterns(
|
|
|
|
OwningRewritePatternList &results, MLIRContext *context) {
|
|
|
|
results.push_back(std::make_unique<SimplifyConstCondBranchPred>(context));
|
|
|
|
}
|
|
|
|
|
2018-12-29 05:07:39 +08:00
|
|
|
Block *CondBranchOp::getTrueDest() {
|
2018-12-28 20:14:52 +08:00
|
|
|
return getInstruction()->getSuccessor(trueIndex);
|
2018-11-16 01:56:06 +08:00
|
|
|
}
|
|
|
|
|
2018-12-29 05:07:39 +08:00
|
|
|
Block *CondBranchOp::getFalseDest() {
|
2018-12-28 20:14:52 +08:00
|
|
|
return getInstruction()->getSuccessor(falseIndex);
|
2018-11-16 01:56:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned CondBranchOp::getNumTrueOperands() const {
|
2018-12-28 20:14:52 +08:00
|
|
|
return getInstruction()->getNumSuccessorOperands(trueIndex);
|
2018-11-16 01:56:06 +08:00
|
|
|
}
|
|
|
|
|
2018-11-21 06:03:41 +08:00
|
|
|
void CondBranchOp::eraseTrueOperand(unsigned index) {
|
2018-12-28 20:14:52 +08:00
|
|
|
getInstruction()->eraseSuccessorOperand(trueIndex, index);
|
2018-11-21 06:03:41 +08:00
|
|
|
}
|
|
|
|
|
2018-11-16 01:56:06 +08:00
|
|
|
unsigned CondBranchOp::getNumFalseOperands() const {
|
2018-12-28 20:14:52 +08:00
|
|
|
return getInstruction()->getNumSuccessorOperands(falseIndex);
|
2018-11-16 01:56:06 +08:00
|
|
|
}
|
|
|
|
|
2018-11-21 06:03:41 +08:00
|
|
|
void CondBranchOp::eraseFalseOperand(unsigned index) {
|
2018-12-28 20:14:52 +08:00
|
|
|
getInstruction()->eraseSuccessorOperand(falseIndex, index);
|
2018-11-21 06:03:41 +08:00
|
|
|
}
|
|
|
|
|
2018-10-11 05:23:30 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Constant*Op
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// Builds a constant op with the specified attribute value and result type.
|
2019-01-15 05:36:02 +08:00
|
|
|
void ConstantOp::build(Builder *builder, OperationState *result, Type type,
|
|
|
|
Attribute value) {
|
2019-02-03 22:15:43 +08:00
|
|
|
auto attr = value.dyn_cast<NumericAttr>();
|
|
|
|
assert(attr && "expected numeric value");
|
|
|
|
assert(attr.getType() == type && "value should be of the given type");
|
|
|
|
(void)attr;
|
|
|
|
|
2018-10-11 05:23:30 +08:00
|
|
|
result->addAttribute("value", value);
|
|
|
|
result->types.push_back(type);
|
|
|
|
}
|
|
|
|
|
2019-02-07 04:27:30 +08:00
|
|
|
void ConstantOp::build(Builder *builder, OperationState *result,
|
|
|
|
NumericAttr value) {
|
|
|
|
result->addAttribute("value", value);
|
|
|
|
result->types.push_back(value.getType());
|
|
|
|
}
|
|
|
|
|
2018-10-11 05:23:30 +08:00
|
|
|
void ConstantOp::print(OpAsmPrinter *p) const {
|
2018-11-18 00:24:07 +08:00
|
|
|
*p << "constant ";
|
2018-10-11 05:23:30 +08:00
|
|
|
p->printOptionalAttrDict(getAttrs(), /*elidedAttrs=*/"value");
|
|
|
|
|
2018-11-18 00:24:07 +08:00
|
|
|
if (getAttrs().size() > 1)
|
|
|
|
*p << ' ';
|
|
|
|
*p << getValue();
|
2018-10-26 06:46:10 +08:00
|
|
|
if (!getValue().isa<FunctionAttr>())
|
2018-10-31 05:59:22 +08:00
|
|
|
*p << " : " << getType();
|
2018-10-11 05:23:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ConstantOp::parse(OpAsmParser *parser, OperationState *result) {
|
2018-10-26 06:46:10 +08:00
|
|
|
Attribute valueAttr;
|
2018-10-31 05:59:22 +08:00
|
|
|
Type type;
|
2018-10-11 05:23:30 +08:00
|
|
|
|
2018-11-18 00:24:07 +08:00
|
|
|
if (parser->parseOptionalAttributeDict(result->attributes) ||
|
|
|
|
parser->parseAttribute(valueAttr, "value", result->attributes))
|
2018-10-11 05:23:30 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// 'constant' taking a function reference doesn't get a redundant type
|
|
|
|
// specifier. The attribute itself carries it.
|
2018-10-26 06:46:10 +08:00
|
|
|
if (auto fnAttr = valueAttr.dyn_cast<FunctionAttr>())
|
|
|
|
return parser->addTypeToList(fnAttr.getValue()->getType(), result->types);
|
2018-10-11 05:23:30 +08:00
|
|
|
|
2018-11-16 09:53:51 +08:00
|
|
|
if (auto intAttr = valueAttr.dyn_cast<IntegerAttr>()) {
|
|
|
|
type = intAttr.getType();
|
|
|
|
} else if (auto fpAttr = valueAttr.dyn_cast<FloatAttr>()) {
|
|
|
|
type = fpAttr.getType();
|
|
|
|
} else if (parser->parseColonType(type)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return parser->addTypeToList(type, result->types);
|
2018-10-11 05:23:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// The constant op requires an attribute, and furthermore requires that it
|
|
|
|
/// matches the return type.
|
|
|
|
bool ConstantOp::verify() const {
|
2018-10-26 06:46:10 +08:00
|
|
|
auto value = getValue();
|
2018-10-11 05:23:30 +08:00
|
|
|
if (!value)
|
|
|
|
return emitOpError("requires a 'value' attribute");
|
|
|
|
|
2018-10-31 05:59:22 +08:00
|
|
|
auto type = this->getType();
|
|
|
|
if (type.isa<IntegerType>() || type.isIndex()) {
|
2018-11-21 09:51:07 +08:00
|
|
|
auto intAttr = value.dyn_cast<IntegerAttr>();
|
|
|
|
if (!intAttr)
|
2018-10-11 05:23:30 +08:00
|
|
|
return emitOpError(
|
|
|
|
"requires 'value' to be an integer for an integer result type");
|
2018-11-21 09:51:07 +08:00
|
|
|
|
|
|
|
// If the type has a known bitwidth we verify that the value can be
|
|
|
|
// represented with the given bitwidth.
|
|
|
|
if (!type.isIndex()) {
|
|
|
|
auto bitwidth = type.cast<IntegerType>().getWidth();
|
|
|
|
auto intVal = intAttr.getValue();
|
|
|
|
if (!intVal.isSignedIntN(bitwidth) && !intVal.isIntN(bitwidth))
|
|
|
|
return emitOpError("requires 'value' to be an integer within the range "
|
|
|
|
"of the integer result type");
|
|
|
|
}
|
2018-10-11 05:23:30 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-10-31 05:59:22 +08:00
|
|
|
if (type.isa<FloatType>()) {
|
2018-10-26 06:46:10 +08:00
|
|
|
if (!value.isa<FloatAttr>())
|
2018-10-11 05:23:30 +08:00
|
|
|
return emitOpError("requires 'value' to be a floating point constant");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-10-31 05:59:22 +08:00
|
|
|
if (type.isa<VectorOrTensorType>()) {
|
2018-10-30 01:22:49 +08:00
|
|
|
if (!value.isa<ElementsAttr>())
|
|
|
|
return emitOpError("requires 'value' to be a vector/tensor constant");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-10-31 05:59:22 +08:00
|
|
|
if (type.isa<FunctionType>()) {
|
2018-10-26 06:46:10 +08:00
|
|
|
if (!value.isa<FunctionAttr>())
|
2018-10-11 05:23:30 +08:00
|
|
|
return emitOpError("requires 'value' to be a function reference");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return emitOpError(
|
|
|
|
"requires a result type that aligns with the 'value' attribute");
|
|
|
|
}
|
|
|
|
|
2018-10-26 06:46:10 +08:00
|
|
|
Attribute ConstantOp::constantFold(ArrayRef<Attribute> operands,
|
|
|
|
MLIRContext *context) const {
|
2018-10-11 05:23:30 +08:00
|
|
|
assert(operands.empty() && "constant has no operands");
|
|
|
|
return getValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConstantFloatOp::build(Builder *builder, OperationState *result,
|
2018-10-31 05:59:22 +08:00
|
|
|
const APFloat &value, FloatType type) {
|
2019-01-15 05:36:02 +08:00
|
|
|
ConstantOp::build(builder, result, type, builder->getFloatAttr(type, value));
|
2018-10-11 05:23:30 +08:00
|
|
|
}
|
|
|
|
|
2019-02-05 02:34:20 +08:00
|
|
|
bool ConstantFloatOp::isClassFor(const Instruction *op) {
|
2018-10-11 05:23:30 +08:00
|
|
|
return ConstantOp::isClassFor(op) &&
|
2018-10-31 05:59:22 +08:00
|
|
|
op->getResult(0)->getType().isa<FloatType>();
|
2018-10-11 05:23:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ConstantIntOp only matches values whose result type is an IntegerType.
|
2019-02-05 02:34:20 +08:00
|
|
|
bool ConstantIntOp::isClassFor(const Instruction *op) {
|
2018-10-11 05:23:30 +08:00
|
|
|
return ConstantOp::isClassFor(op) &&
|
2018-10-31 05:59:22 +08:00
|
|
|
op->getResult(0)->getType().isa<IntegerType>();
|
2018-10-11 05:23:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ConstantIntOp::build(Builder *builder, OperationState *result,
|
|
|
|
int64_t value, unsigned width) {
|
2018-11-16 09:53:51 +08:00
|
|
|
Type type = builder->getIntegerType(width);
|
2019-01-15 05:36:02 +08:00
|
|
|
ConstantOp::build(builder, result, type,
|
|
|
|
builder->getIntegerAttr(type, value));
|
2018-10-11 05:23:30 +08:00
|
|
|
}
|
|
|
|
|
2018-10-12 08:21:55 +08:00
|
|
|
/// Build a constant int op producing an integer with the specified type,
|
|
|
|
/// which must be an integer type.
|
|
|
|
void ConstantIntOp::build(Builder *builder, OperationState *result,
|
2018-10-31 05:59:22 +08:00
|
|
|
int64_t value, Type type) {
|
|
|
|
assert(type.isa<IntegerType>() && "ConstantIntOp can only have integer type");
|
2019-01-15 05:36:02 +08:00
|
|
|
ConstantOp::build(builder, result, type,
|
|
|
|
builder->getIntegerAttr(type, value));
|
2018-10-12 08:21:55 +08:00
|
|
|
}
|
|
|
|
|
2018-10-11 05:23:30 +08:00
|
|
|
/// ConstantIndexOp only matches values whose result type is Index.
|
2019-02-05 02:34:20 +08:00
|
|
|
bool ConstantIndexOp::isClassFor(const Instruction *op) {
|
2018-10-31 05:59:22 +08:00
|
|
|
return ConstantOp::isClassFor(op) && op->getResult(0)->getType().isIndex();
|
2018-10-11 05:23:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ConstantIndexOp::build(Builder *builder, OperationState *result,
|
|
|
|
int64_t value) {
|
2018-11-16 09:53:51 +08:00
|
|
|
Type type = builder->getIndexType();
|
2019-01-15 05:36:02 +08:00
|
|
|
ConstantOp::build(builder, result, type,
|
|
|
|
builder->getIntegerAttr(type, value));
|
2018-10-11 05:23:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ReturnOp
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
void ReturnOp::build(Builder *builder, OperationState *result,
|
2018-12-28 06:35:10 +08:00
|
|
|
ArrayRef<Value *> results) {
|
2018-10-11 05:23:30 +08:00
|
|
|
result->addOperands(results);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ReturnOp::parse(OpAsmParser *parser, OperationState *result) {
|
|
|
|
SmallVector<OpAsmParser::OperandType, 2> opInfo;
|
2018-10-31 05:59:22 +08:00
|
|
|
SmallVector<Type, 2> types;
|
2018-10-11 05:23:30 +08:00
|
|
|
llvm::SMLoc loc;
|
|
|
|
return parser->getCurrentLocation(&loc) || parser->parseOperandList(opInfo) ||
|
|
|
|
(!opInfo.empty() && parser->parseColonTypeList(types)) ||
|
|
|
|
parser->resolveOperands(opInfo, types, loc, result->operands);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReturnOp::print(OpAsmPrinter *p) const {
|
|
|
|
*p << "return";
|
|
|
|
if (getNumOperands() > 0) {
|
|
|
|
*p << ' ';
|
|
|
|
p->printOperands(operand_begin(), operand_end());
|
|
|
|
*p << " : ";
|
2018-12-28 06:35:10 +08:00
|
|
|
interleave(
|
|
|
|
operand_begin(), operand_end(),
|
|
|
|
[&](const Value *e) { p->printType(e->getType()); },
|
|
|
|
[&]() { *p << ", "; });
|
2018-10-11 05:23:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ReturnOp::verify() const {
|
2018-12-28 20:14:52 +08:00
|
|
|
auto *function = getInstruction()->getFunction();
|
2018-11-14 01:49:27 +08:00
|
|
|
|
|
|
|
// The operand number and types must match the function signature.
|
|
|
|
const auto &results = function->getType().getResults();
|
|
|
|
if (getNumOperands() != results.size())
|
|
|
|
return emitOpError("has " + Twine(getNumOperands()) +
|
|
|
|
" operands, but enclosing function returns " +
|
|
|
|
Twine(results.size()));
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = results.size(); i != e; ++i)
|
2018-12-08 01:30:25 +08:00
|
|
|
if (getOperand(i)->getType() != results[i])
|
|
|
|
return emitError("type of return operand " + Twine(i) +
|
|
|
|
" doesn't match function result type");
|
2018-11-14 01:49:27 +08:00
|
|
|
|
|
|
|
return false;
|
2018-10-11 05:23:30 +08:00
|
|
|
}
|