2019-01-15 10:53:22 -08:00
|
|
|
//===- LLVMDialect.cpp - LLVM IR Ops and Dialect registration -------------===//
|
|
|
|
//
|
2020-01-26 03:58:30 +00:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
2019-12-23 09:35:36 -08:00
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2019-01-15 10:53:22 -08:00
|
|
|
//
|
2019-12-23 09:35:36 -08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-01-15 10:53:22 -08:00
|
|
|
//
|
|
|
|
// This file defines the types and operation details for the LLVM IR dialect in
|
|
|
|
// MLIR, and the LLVM IR dialect. It also registers the dialect.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2019-08-19 11:00:47 -07:00
|
|
|
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
|
2021-03-11 11:24:43 -08:00
|
|
|
#include "TypeDetail.h"
|
2020-08-04 11:37:50 +02:00
|
|
|
#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
|
2019-04-02 15:33:54 -07:00
|
|
|
#include "mlir/IR/Builders.h"
|
2020-11-19 10:43:12 -08:00
|
|
|
#include "mlir/IR/BuiltinOps.h"
|
2020-12-03 17:22:29 -08:00
|
|
|
#include "mlir/IR/BuiltinTypes.h"
|
2019-11-01 14:47:42 -07:00
|
|
|
#include "mlir/IR/DialectImplementation.h"
|
2019-11-28 11:50:47 -08:00
|
|
|
#include "mlir/IR/FunctionImplementation.h"
|
2019-01-15 10:53:22 -08:00
|
|
|
#include "mlir/IR/MLIRContext.h"
|
2022-01-05 20:34:01 -05:00
|
|
|
#include "mlir/IR/Matchers.h"
|
2019-01-15 10:53:22 -08:00
|
|
|
|
2020-03-01 01:11:12 +00:00
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
2021-03-05 06:38:59 +00:00
|
|
|
#include "llvm/ADT/TypeSwitch.h"
|
2019-01-15 10:53:22 -08:00
|
|
|
#include "llvm/AsmParser/Parser.h"
|
2020-04-16 13:14:43 +02:00
|
|
|
#include "llvm/Bitcode/BitcodeReader.h"
|
|
|
|
#include "llvm/Bitcode/BitcodeWriter.h"
|
2019-03-06 09:34:53 -08:00
|
|
|
#include "llvm/IR/Attributes.h"
|
2019-04-02 15:33:54 -07:00
|
|
|
#include "llvm/IR/Function.h"
|
2019-01-15 10:53:22 -08:00
|
|
|
#include "llvm/IR/Type.h"
|
2019-05-22 14:56:07 -07:00
|
|
|
#include "llvm/Support/Mutex.h"
|
2019-01-15 10:53:22 -08:00
|
|
|
#include "llvm/Support/SourceMgr.h"
|
|
|
|
|
[mlir] Add support for VariadicOfVariadic operands
This revision adds native ODS support for VariadicOfVariadic operand
groups. An example of this is the SwitchOp, which has a variadic number
of nested operand ranges for each of the case statements, where the
number of case statements is variadic. Builtin ODS support allows for
generating proper accessors for the nested operand ranges, builder
support, and declarative format support. VariadicOfVariadic operands
are supported by providing a segment attribute to use to store the
operand groups, mapping similarly to the AttrSizedOperand trait
(but with a user defined attribute name).
`build` methods for VariadicOfVariadic operand expect inputs of the
form `ArrayRef<ValueRange>`. Accessors for the variadic ranges
return a new `OperandRangeRange` type, which represents a
contiguous range of `OperandRange`. In the declarative assembly
format, VariadicOfVariadic operands and types are by default
formatted as a comma delimited list of value lists:
`(<value>, <value>), (), (<value>)`.
Differential Revision: https://reviews.llvm.org/D107774
2021-08-23 20:23:09 +00:00
|
|
|
#include <numeric>
|
2021-05-12 08:45:25 +02:00
|
|
|
|
2019-01-15 10:53:22 -08:00
|
|
|
using namespace mlir;
|
|
|
|
using namespace mlir::LLVM;
|
2021-09-03 21:18:39 +00:00
|
|
|
using mlir::LLVM::linkage::getMaxEnumValForLinkage;
|
2019-01-15 10:53:22 -08:00
|
|
|
|
2021-06-28 22:54:11 +00:00
|
|
|
#include "mlir/Dialect/LLVMIR/LLVMOpsDialect.cpp.inc"
|
|
|
|
|
2020-07-27 10:19:48 +03:00
|
|
|
static constexpr const char kVolatileAttrName[] = "volatile_";
|
|
|
|
static constexpr const char kNonTemporalAttrName[] = "nontemporal";
|
|
|
|
|
2019-08-19 11:00:47 -07:00
|
|
|
#include "mlir/Dialect/LLVMIR/LLVMOpsEnums.cpp.inc"
|
2021-01-07 13:56:37 +01:00
|
|
|
#include "mlir/Dialect/LLVMIR/LLVMOpsInterfaces.cpp.inc"
|
2021-03-05 06:38:59 +00:00
|
|
|
#define GET_ATTRDEF_CLASSES
|
|
|
|
#include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc"
|
2021-01-07 13:56:37 +01:00
|
|
|
|
|
|
|
static auto processFMFAttr(ArrayRef<NamedAttribute> attrs) {
|
|
|
|
SmallVector<NamedAttribute, 8> filteredAttrs(
|
|
|
|
llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
|
2021-11-18 05:23:32 +00:00
|
|
|
if (attr.getName() == "fastmathFlags") {
|
|
|
|
auto defAttr = FMFAttr::get(attr.getValue().getContext(), {});
|
|
|
|
return defAttr != attr.getValue();
|
2021-01-07 13:56:37 +01:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}));
|
|
|
|
return filteredAttrs;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ParseResult parseLLVMOpAttrs(OpAsmParser &parser,
|
|
|
|
NamedAttrList &result) {
|
|
|
|
return parser.parseOptionalAttrDict(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void printLLVMOpAttrs(OpAsmPrinter &printer, Operation *op,
|
|
|
|
DictionaryAttr attrs) {
|
|
|
|
printer.printOptionalAttrDict(processFMFAttr(attrs.getValue()));
|
|
|
|
}
|
2019-07-15 05:45:08 -07:00
|
|
|
|
2021-10-20 15:14:54 +05:30
|
|
|
/// Verifies `symbol`'s use in `op` to ensure the symbol is a valid and
|
|
|
|
/// fully defined llvm.func.
|
|
|
|
static LogicalResult verifySymbolAttrUse(FlatSymbolRefAttr symbol,
|
|
|
|
Operation *op,
|
|
|
|
SymbolTableCollection &symbolTable) {
|
|
|
|
StringRef name = symbol.getValue();
|
|
|
|
auto func =
|
|
|
|
symbolTable.lookupNearestSymbolFrom<LLVMFuncOp>(op, symbol.getAttr());
|
|
|
|
if (!func)
|
|
|
|
return op->emitOpError("'")
|
|
|
|
<< name << "' does not reference a valid LLVM function";
|
|
|
|
if (func.isExternal())
|
|
|
|
return op->emitOpError("'") << name << "' does not have a definition";
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-08-08 18:29:23 -07:00
|
|
|
// Printing/parsing for LLVM::CmpOp.
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
2022-02-07 17:54:04 -08:00
|
|
|
|
|
|
|
void ICmpOp::print(OpAsmPrinter &p) {
|
|
|
|
p << " \"" << stringifyICmpPredicate(getPredicate()) << "\" " << getOperand(0)
|
|
|
|
<< ", " << getOperand(1);
|
|
|
|
p.printOptionalAttrDict((*this)->getAttrs(), {"predicate"});
|
|
|
|
p << " : " << getLhs().getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
void FCmpOp::print(OpAsmPrinter &p) {
|
|
|
|
p << " \"" << stringifyFCmpPredicate(getPredicate()) << "\" " << getOperand(0)
|
|
|
|
<< ", " << getOperand(1);
|
|
|
|
p.printOptionalAttrDict(processFMFAttr((*this)->getAttrs()), {"predicate"});
|
|
|
|
p << " : " << getLhs().getType();
|
2019-08-08 18:29:23 -07:00
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
// <operation> ::= `llvm.icmp` string-literal ssa-use `,` ssa-use
|
|
|
|
// attribute-dict? `:` type
|
2019-08-08 18:29:23 -07:00
|
|
|
// <operation> ::= `llvm.fcmp` string-literal ssa-use `,` ssa-use
|
|
|
|
// attribute-dict? `:` type
|
|
|
|
template <typename CmpPredicateType>
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseCmpOp(OpAsmParser &parser, OperationState &result) {
|
2019-09-20 11:36:49 -07:00
|
|
|
Builder &builder = parser.getBuilder();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
StringAttr predicateAttr;
|
2019-04-02 15:33:54 -07:00
|
|
|
OpAsmParser::OperandType lhs, rhs;
|
|
|
|
Type type;
|
2022-01-26 15:49:53 -08:00
|
|
|
SMLoc predicateLoc, trailingTypeLoc;
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.getCurrentLocation(&predicateLoc) ||
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
parser.parseAttribute(predicateAttr, "predicate", result.attributes) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.parseOperand(lhs) || parser.parseComma() ||
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
parser.parseOperand(rhs) ||
|
|
|
|
parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
|
|
|
|
parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type) ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.resolveOperand(lhs, type, result.operands) ||
|
|
|
|
parser.resolveOperand(rhs, type, result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
// Replace the string attribute `predicate` with an integer attribute.
|
2019-08-08 18:29:23 -07:00
|
|
|
int64_t predicateValue = 0;
|
|
|
|
if (std::is_same<CmpPredicateType, ICmpPredicate>()) {
|
|
|
|
Optional<ICmpPredicate> predicate =
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
symbolizeICmpPredicate(predicateAttr.getValue());
|
2019-08-08 18:29:23 -07:00
|
|
|
if (!predicate)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(predicateLoc)
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
<< "'" << predicateAttr.getValue()
|
2019-08-08 18:29:23 -07:00
|
|
|
<< "' is an incorrect value of the 'predicate' attribute";
|
|
|
|
predicateValue = static_cast<int64_t>(predicate.getValue());
|
|
|
|
} else {
|
|
|
|
Optional<FCmpPredicate> predicate =
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
symbolizeFCmpPredicate(predicateAttr.getValue());
|
2019-08-08 18:29:23 -07:00
|
|
|
if (!predicate)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(predicateLoc)
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
<< "'" << predicateAttr.getValue()
|
2019-08-08 18:29:23 -07:00
|
|
|
<< "' is an incorrect value of the 'predicate' attribute";
|
|
|
|
predicateValue = static_cast<int64_t>(predicate.getValue());
|
|
|
|
}
|
|
|
|
|
2020-05-06 13:48:36 -07:00
|
|
|
result.attributes.set("predicate",
|
|
|
|
parser.getBuilder().getI64IntegerAttr(predicateValue));
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
// The result type is either i1 or a vector type <? x i1> if the inputs are
|
|
|
|
// vectors.
|
[mlir] replace LLVMIntegerType with built-in integer type
The LLVM dialect type system has been closed until now, i.e. did not support
types from other dialects inside containers. While this has had obvious
benefits of deriving from a common base class, it has led to some simple types
being almost identical with the built-in types, namely integer and floating
point types. This in turn has led to a lot of larger-scale complexity: simple
types must still be converted, numerous operations that correspond to LLVM IR
intrinsics are replicated to produce versions operating on either LLVM dialect
or built-in types leading to quasi-duplicate dialects, lowering to the LLVM
dialect is essentially required to be one-shot because of type conversion, etc.
In this light, it is reasonable to trade off some local complexity in the
internal implementation of LLVM dialect types for removing larger-scale system
complexity. Previous commits to the LLVM dialect type system have adapted the
API to support types from other dialects.
Replace LLVMIntegerType with the built-in IntegerType plus additional checks
that such types are signless (these are isolated in a utility function that
replaced `isa<LLVMType>` and in the parser). Temporarily keep the possibility
to parse `!llvm.i32` as a synonym for `i32`, but add a deprecation notice.
Reviewed By: mehdi_amini, silvas, antiagainst
Differential Revision: https://reviews.llvm.org/D94178
2021-01-06 16:19:04 +01:00
|
|
|
Type resultType = IntegerType::get(builder.getContext(), 1);
|
2021-01-05 16:22:53 +01:00
|
|
|
if (!isCompatibleType(type))
|
|
|
|
return parser.emitError(trailingTypeLoc,
|
|
|
|
"expected LLVM dialect-compatible type");
|
2021-04-22 09:29:02 +01:00
|
|
|
if (LLVM::isCompatibleVectorType(type)) {
|
2021-10-12 14:26:01 +01:00
|
|
|
if (LLVM::isScalableVectorType(type)) {
|
|
|
|
resultType = LLVM::getVectorType(
|
|
|
|
resultType, LLVM::getVectorNumElements(type).getKnownMinValue(),
|
|
|
|
/*isScalable=*/true);
|
2021-04-22 09:29:02 +01:00
|
|
|
} else {
|
2021-10-12 14:26:01 +01:00
|
|
|
resultType = LLVM::getVectorType(
|
|
|
|
resultType, LLVM::getVectorNumElements(type).getFixedValue(),
|
|
|
|
/*isScalable=*/false);
|
2021-04-22 09:29:02 +01:00
|
|
|
}
|
|
|
|
}
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes({resultType});
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult ICmpOp::parse(OpAsmParser &parser, OperationState &result) {
|
|
|
|
return parseCmpOp<ICmpPredicate>(parser, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
ParseResult FCmpOp::parse(OpAsmParser &parser, OperationState &result) {
|
|
|
|
return parseCmpOp<FCmpPredicate>(parser, result);
|
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::AllocaOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
void AllocaOp::print(OpAsmPrinter &p) {
|
|
|
|
auto elemTy = getType().cast<LLVM::LLVMPointerType>().getElementType();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
auto funcTy =
|
|
|
|
FunctionType::get(getContext(), {getArraySize().getType()}, {getType()});
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
p << ' ' << getArraySize() << " x " << elemTy;
|
|
|
|
if (getAlignment().hasValue() && *getAlignment() != 0)
|
|
|
|
p.printOptionalAttrDict((*this)->getAttrs());
|
2019-08-18 18:54:50 -07:00
|
|
|
else
|
2022-02-07 17:54:04 -08:00
|
|
|
p.printOptionalAttrDict((*this)->getAttrs(), {"alignment"});
|
2019-09-20 20:43:02 -07:00
|
|
|
p << " : " << funcTy;
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.alloca` ssa-use `x` type attribute-dict?
|
|
|
|
// `:` type `,` type
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult AllocaOp::parse(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
OpAsmParser::OperandType arraySize;
|
|
|
|
Type type, elemType;
|
2022-01-26 15:49:53 -08:00
|
|
|
SMLoc trailingTypeLoc;
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperand(arraySize) || parser.parseKeyword("x") ||
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
parser.parseType(elemType) ||
|
|
|
|
parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
|
|
|
|
parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2020-10-26 19:29:28 +01:00
|
|
|
Optional<NamedAttribute> alignmentAttr =
|
|
|
|
result.attributes.getNamed("alignment");
|
|
|
|
if (alignmentAttr.hasValue()) {
|
2021-11-18 05:23:32 +00:00
|
|
|
auto alignmentInt =
|
|
|
|
alignmentAttr.getValue().getValue().dyn_cast<IntegerAttr>();
|
2020-10-26 19:29:28 +01:00
|
|
|
if (!alignmentInt)
|
|
|
|
return parser.emitError(parser.getNameLoc(),
|
|
|
|
"expected integer alignment");
|
|
|
|
if (alignmentInt.getValue().isNullValue())
|
|
|
|
result.attributes.erase("alignment");
|
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
// Extract the result type from the trailing function type.
|
|
|
|
auto funcType = type.dyn_cast<FunctionType>();
|
|
|
|
if (!funcType || funcType.getNumInputs() != 1 ||
|
|
|
|
funcType.getNumResults() != 1)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(
|
2019-04-02 15:33:54 -07:00
|
|
|
trailingTypeLoc,
|
|
|
|
"expected trailing function type with one argument and one result");
|
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
if (parser.resolveOperand(arraySize, funcType.getInput(0), result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes({funcType.getResult(0)});
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2020-03-05 12:40:23 -08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// LLVM::BrOp
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-04-29 16:09:43 -07:00
|
|
|
Optional<MutableOperandRange>
|
|
|
|
BrOp::getMutableSuccessorOperands(unsigned index) {
|
2020-03-05 12:40:23 -08:00
|
|
|
assert(index == 0 && "invalid successor index");
|
2021-10-24 18:36:33 -07:00
|
|
|
return getDestOperandsMutable();
|
2020-03-05 12:40:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// LLVM::CondBrOp
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-04-29 16:09:43 -07:00
|
|
|
Optional<MutableOperandRange>
|
|
|
|
CondBrOp::getMutableSuccessorOperands(unsigned index) {
|
2020-03-05 12:40:23 -08:00
|
|
|
assert(index < getNumSuccessors() && "invalid successor index");
|
2021-10-24 18:36:33 -07:00
|
|
|
return index == 0 ? getTrueDestOperandsMutable()
|
|
|
|
: getFalseDestOperandsMutable();
|
2020-03-05 12:40:23 -08:00
|
|
|
}
|
|
|
|
|
[mlir][LLVMIR] Add 'llvm.switch' op
The LLVM IR 'switch' instruction allows control flow to be transferred
to one of any number of branches depending on an integer control value,
or a default value if the control does not match any branch values. This patch
adds `llvm.switch` to the MLIR LLVMIR dialect, as well as translation routines
for lowering it to LLVM IR.
To store a variable number of operands for a variable number of branch
destinations, the new op makes use of the `AttrSizedOperandSegments`
trait. It stores its default branch operands as one segment, and all
remaining case branches' operands as another. It also stores pairs of
begin and end offset values to delineate the sub-range of each case branch's
operands. There's probably a better way to implement this, since the
offset computation complicates several parts of the op definition. This is the
approach I settled on because in doing so I was able to delegate to the default
op builder member functions. However, it may be preferable to instead specify
`skipDefaultBuilders` in the op's ODS, or use a completely separate
approach; feedback is welcome!
Another contentious part of this patch may be the custom printer and
parser functions for the op. Ideally I would have liked the MLIR to be
printed in this way:
```
llvm.switch %0, ^bb1(%1 : !llvm.i32) [
1: ^bb2,
2: ^bb3(%2, %3 : !llvm.i32, !llvm.i32)
]
```
The above would resemble how LLVM IR is formatted for the 'switch'
instruction. But I found it difficult to print and parse something like
this, whether I used the declarative assembly format or custom functions.
I also was not sure a multi-line format would be welcome -- it seems
like most MLIR ops do not use newlines. Again, I'd be happy to hear any
feedback here as well, or on any other aspect of the patch.
Differential Revision: https://reviews.llvm.org/D93005
2020-12-09 22:37:20 -05:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// LLVM::SwitchOp
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
void SwitchOp::build(OpBuilder &builder, OperationState &result, Value value,
|
|
|
|
Block *defaultDestination, ValueRange defaultOperands,
|
|
|
|
ArrayRef<int32_t> caseValues, BlockRange caseDestinations,
|
|
|
|
ArrayRef<ValueRange> caseOperands,
|
|
|
|
ArrayRef<int32_t> branchWeights) {
|
|
|
|
ElementsAttr caseValuesAttr;
|
|
|
|
if (!caseValues.empty())
|
|
|
|
caseValuesAttr = builder.getI32VectorAttr(caseValues);
|
|
|
|
|
|
|
|
ElementsAttr weightsAttr;
|
|
|
|
if (!branchWeights.empty())
|
|
|
|
weightsAttr = builder.getI32VectorAttr(llvm::to_vector<4>(branchWeights));
|
|
|
|
|
[mlir] Add support for VariadicOfVariadic operands
This revision adds native ODS support for VariadicOfVariadic operand
groups. An example of this is the SwitchOp, which has a variadic number
of nested operand ranges for each of the case statements, where the
number of case statements is variadic. Builtin ODS support allows for
generating proper accessors for the nested operand ranges, builder
support, and declarative format support. VariadicOfVariadic operands
are supported by providing a segment attribute to use to store the
operand groups, mapping similarly to the AttrSizedOperand trait
(but with a user defined attribute name).
`build` methods for VariadicOfVariadic operand expect inputs of the
form `ArrayRef<ValueRange>`. Accessors for the variadic ranges
return a new `OperandRangeRange` type, which represents a
contiguous range of `OperandRange`. In the declarative assembly
format, VariadicOfVariadic operands and types are by default
formatted as a comma delimited list of value lists:
`(<value>, <value>), (), (<value>)`.
Differential Revision: https://reviews.llvm.org/D107774
2021-08-23 20:23:09 +00:00
|
|
|
build(builder, result, value, defaultOperands, caseOperands, caseValuesAttr,
|
|
|
|
weightsAttr, defaultDestination, caseDestinations);
|
[mlir][LLVMIR] Add 'llvm.switch' op
The LLVM IR 'switch' instruction allows control flow to be transferred
to one of any number of branches depending on an integer control value,
or a default value if the control does not match any branch values. This patch
adds `llvm.switch` to the MLIR LLVMIR dialect, as well as translation routines
for lowering it to LLVM IR.
To store a variable number of operands for a variable number of branch
destinations, the new op makes use of the `AttrSizedOperandSegments`
trait. It stores its default branch operands as one segment, and all
remaining case branches' operands as another. It also stores pairs of
begin and end offset values to delineate the sub-range of each case branch's
operands. There's probably a better way to implement this, since the
offset computation complicates several parts of the op definition. This is the
approach I settled on because in doing so I was able to delegate to the default
op builder member functions. However, it may be preferable to instead specify
`skipDefaultBuilders` in the op's ODS, or use a completely separate
approach; feedback is welcome!
Another contentious part of this patch may be the custom printer and
parser functions for the op. Ideally I would have liked the MLIR to be
printed in this way:
```
llvm.switch %0, ^bb1(%1 : !llvm.i32) [
1: ^bb2,
2: ^bb3(%2, %3 : !llvm.i32, !llvm.i32)
]
```
The above would resemble how LLVM IR is formatted for the 'switch'
instruction. But I found it difficult to print and parse something like
this, whether I used the declarative assembly format or custom functions.
I also was not sure a multi-line format would be welcome -- it seems
like most MLIR ops do not use newlines. Again, I'd be happy to hear any
feedback here as well, or on any other aspect of the patch.
Differential Revision: https://reviews.llvm.org/D93005
2020-12-09 22:37:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <cases> ::= integer `:` bb-id (`(` ssa-use-and-type-list `)`)?
|
|
|
|
/// ( `,` integer `:` bb-id (`(` ssa-use-and-type-list `)`)? )?
|
[mlir] Add support for VariadicOfVariadic operands
This revision adds native ODS support for VariadicOfVariadic operand
groups. An example of this is the SwitchOp, which has a variadic number
of nested operand ranges for each of the case statements, where the
number of case statements is variadic. Builtin ODS support allows for
generating proper accessors for the nested operand ranges, builder
support, and declarative format support. VariadicOfVariadic operands
are supported by providing a segment attribute to use to store the
operand groups, mapping similarly to the AttrSizedOperand trait
(but with a user defined attribute name).
`build` methods for VariadicOfVariadic operand expect inputs of the
form `ArrayRef<ValueRange>`. Accessors for the variadic ranges
return a new `OperandRangeRange` type, which represents a
contiguous range of `OperandRange`. In the declarative assembly
format, VariadicOfVariadic operands and types are by default
formatted as a comma delimited list of value lists:
`(<value>, <value>), (), (<value>)`.
Differential Revision: https://reviews.llvm.org/D107774
2021-08-23 20:23:09 +00:00
|
|
|
static ParseResult parseSwitchOpCases(
|
2021-11-15 20:13:33 -05:00
|
|
|
OpAsmParser &parser, Type flagType, ElementsAttr &caseValues,
|
[mlir] Add support for VariadicOfVariadic operands
This revision adds native ODS support for VariadicOfVariadic operand
groups. An example of this is the SwitchOp, which has a variadic number
of nested operand ranges for each of the case statements, where the
number of case statements is variadic. Builtin ODS support allows for
generating proper accessors for the nested operand ranges, builder
support, and declarative format support. VariadicOfVariadic operands
are supported by providing a segment attribute to use to store the
operand groups, mapping similarly to the AttrSizedOperand trait
(but with a user defined attribute name).
`build` methods for VariadicOfVariadic operand expect inputs of the
form `ArrayRef<ValueRange>`. Accessors for the variadic ranges
return a new `OperandRangeRange` type, which represents a
contiguous range of `OperandRange`. In the declarative assembly
format, VariadicOfVariadic operands and types are by default
formatted as a comma delimited list of value lists:
`(<value>, <value>), (), (<value>)`.
Differential Revision: https://reviews.llvm.org/D107774
2021-08-23 20:23:09 +00:00
|
|
|
SmallVectorImpl<Block *> &caseDestinations,
|
|
|
|
SmallVectorImpl<SmallVector<OpAsmParser::OperandType>> &caseOperands,
|
|
|
|
SmallVectorImpl<SmallVector<Type>> &caseOperandTypes) {
|
2021-11-15 20:13:33 -05:00
|
|
|
SmallVector<APInt> values;
|
|
|
|
unsigned bitWidth = flagType.getIntOrFloatBitWidth();
|
[mlir][LLVMIR] Add 'llvm.switch' op
The LLVM IR 'switch' instruction allows control flow to be transferred
to one of any number of branches depending on an integer control value,
or a default value if the control does not match any branch values. This patch
adds `llvm.switch` to the MLIR LLVMIR dialect, as well as translation routines
for lowering it to LLVM IR.
To store a variable number of operands for a variable number of branch
destinations, the new op makes use of the `AttrSizedOperandSegments`
trait. It stores its default branch operands as one segment, and all
remaining case branches' operands as another. It also stores pairs of
begin and end offset values to delineate the sub-range of each case branch's
operands. There's probably a better way to implement this, since the
offset computation complicates several parts of the op definition. This is the
approach I settled on because in doing so I was able to delegate to the default
op builder member functions. However, it may be preferable to instead specify
`skipDefaultBuilders` in the op's ODS, or use a completely separate
approach; feedback is welcome!
Another contentious part of this patch may be the custom printer and
parser functions for the op. Ideally I would have liked the MLIR to be
printed in this way:
```
llvm.switch %0, ^bb1(%1 : !llvm.i32) [
1: ^bb2,
2: ^bb3(%2, %3 : !llvm.i32, !llvm.i32)
]
```
The above would resemble how LLVM IR is formatted for the 'switch'
instruction. But I found it difficult to print and parse something like
this, whether I used the declarative assembly format or custom functions.
I also was not sure a multi-line format would be welcome -- it seems
like most MLIR ops do not use newlines. Again, I'd be happy to hear any
feedback here as well, or on any other aspect of the patch.
Differential Revision: https://reviews.llvm.org/D93005
2020-12-09 22:37:20 -05:00
|
|
|
do {
|
2021-11-15 20:13:33 -05:00
|
|
|
int64_t value = 0;
|
[mlir][LLVMIR] Add 'llvm.switch' op
The LLVM IR 'switch' instruction allows control flow to be transferred
to one of any number of branches depending on an integer control value,
or a default value if the control does not match any branch values. This patch
adds `llvm.switch` to the MLIR LLVMIR dialect, as well as translation routines
for lowering it to LLVM IR.
To store a variable number of operands for a variable number of branch
destinations, the new op makes use of the `AttrSizedOperandSegments`
trait. It stores its default branch operands as one segment, and all
remaining case branches' operands as another. It also stores pairs of
begin and end offset values to delineate the sub-range of each case branch's
operands. There's probably a better way to implement this, since the
offset computation complicates several parts of the op definition. This is the
approach I settled on because in doing so I was able to delegate to the default
op builder member functions. However, it may be preferable to instead specify
`skipDefaultBuilders` in the op's ODS, or use a completely separate
approach; feedback is welcome!
Another contentious part of this patch may be the custom printer and
parser functions for the op. Ideally I would have liked the MLIR to be
printed in this way:
```
llvm.switch %0, ^bb1(%1 : !llvm.i32) [
1: ^bb2,
2: ^bb3(%2, %3 : !llvm.i32, !llvm.i32)
]
```
The above would resemble how LLVM IR is formatted for the 'switch'
instruction. But I found it difficult to print and parse something like
this, whether I used the declarative assembly format or custom functions.
I also was not sure a multi-line format would be welcome -- it seems
like most MLIR ops do not use newlines. Again, I'd be happy to hear any
feedback here as well, or on any other aspect of the patch.
Differential Revision: https://reviews.llvm.org/D93005
2020-12-09 22:37:20 -05:00
|
|
|
OptionalParseResult integerParseResult = parser.parseOptionalInteger(value);
|
|
|
|
if (values.empty() && !integerParseResult.hasValue())
|
|
|
|
return success();
|
|
|
|
|
|
|
|
if (!integerParseResult.hasValue() || integerParseResult.getValue())
|
|
|
|
return failure();
|
2021-11-15 20:13:33 -05:00
|
|
|
values.push_back(APInt(bitWidth, value));
|
[mlir][LLVMIR] Add 'llvm.switch' op
The LLVM IR 'switch' instruction allows control flow to be transferred
to one of any number of branches depending on an integer control value,
or a default value if the control does not match any branch values. This patch
adds `llvm.switch` to the MLIR LLVMIR dialect, as well as translation routines
for lowering it to LLVM IR.
To store a variable number of operands for a variable number of branch
destinations, the new op makes use of the `AttrSizedOperandSegments`
trait. It stores its default branch operands as one segment, and all
remaining case branches' operands as another. It also stores pairs of
begin and end offset values to delineate the sub-range of each case branch's
operands. There's probably a better way to implement this, since the
offset computation complicates several parts of the op definition. This is the
approach I settled on because in doing so I was able to delegate to the default
op builder member functions. However, it may be preferable to instead specify
`skipDefaultBuilders` in the op's ODS, or use a completely separate
approach; feedback is welcome!
Another contentious part of this patch may be the custom printer and
parser functions for the op. Ideally I would have liked the MLIR to be
printed in this way:
```
llvm.switch %0, ^bb1(%1 : !llvm.i32) [
1: ^bb2,
2: ^bb3(%2, %3 : !llvm.i32, !llvm.i32)
]
```
The above would resemble how LLVM IR is formatted for the 'switch'
instruction. But I found it difficult to print and parse something like
this, whether I used the declarative assembly format or custom functions.
I also was not sure a multi-line format would be welcome -- it seems
like most MLIR ops do not use newlines. Again, I'd be happy to hear any
feedback here as well, or on any other aspect of the patch.
Differential Revision: https://reviews.llvm.org/D93005
2020-12-09 22:37:20 -05:00
|
|
|
|
|
|
|
Block *destination;
|
2020-12-22 02:19:31 +01:00
|
|
|
SmallVector<OpAsmParser::OperandType> operands;
|
[mlir] Add support for VariadicOfVariadic operands
This revision adds native ODS support for VariadicOfVariadic operand
groups. An example of this is the SwitchOp, which has a variadic number
of nested operand ranges for each of the case statements, where the
number of case statements is variadic. Builtin ODS support allows for
generating proper accessors for the nested operand ranges, builder
support, and declarative format support. VariadicOfVariadic operands
are supported by providing a segment attribute to use to store the
operand groups, mapping similarly to the AttrSizedOperand trait
(but with a user defined attribute name).
`build` methods for VariadicOfVariadic operand expect inputs of the
form `ArrayRef<ValueRange>`. Accessors for the variadic ranges
return a new `OperandRangeRange` type, which represents a
contiguous range of `OperandRange`. In the declarative assembly
format, VariadicOfVariadic operands and types are by default
formatted as a comma delimited list of value lists:
`(<value>, <value>), (), (<value>)`.
Differential Revision: https://reviews.llvm.org/D107774
2021-08-23 20:23:09 +00:00
|
|
|
SmallVector<Type> operandTypes;
|
[mlir][LLVMIR] Add 'llvm.switch' op
The LLVM IR 'switch' instruction allows control flow to be transferred
to one of any number of branches depending on an integer control value,
or a default value if the control does not match any branch values. This patch
adds `llvm.switch` to the MLIR LLVMIR dialect, as well as translation routines
for lowering it to LLVM IR.
To store a variable number of operands for a variable number of branch
destinations, the new op makes use of the `AttrSizedOperandSegments`
trait. It stores its default branch operands as one segment, and all
remaining case branches' operands as another. It also stores pairs of
begin and end offset values to delineate the sub-range of each case branch's
operands. There's probably a better way to implement this, since the
offset computation complicates several parts of the op definition. This is the
approach I settled on because in doing so I was able to delegate to the default
op builder member functions. However, it may be preferable to instead specify
`skipDefaultBuilders` in the op's ODS, or use a completely separate
approach; feedback is welcome!
Another contentious part of this patch may be the custom printer and
parser functions for the op. Ideally I would have liked the MLIR to be
printed in this way:
```
llvm.switch %0, ^bb1(%1 : !llvm.i32) [
1: ^bb2,
2: ^bb3(%2, %3 : !llvm.i32, !llvm.i32)
]
```
The above would resemble how LLVM IR is formatted for the 'switch'
instruction. But I found it difficult to print and parse something like
this, whether I used the declarative assembly format or custom functions.
I also was not sure a multi-line format would be welcome -- it seems
like most MLIR ops do not use newlines. Again, I'd be happy to hear any
feedback here as well, or on any other aspect of the patch.
Differential Revision: https://reviews.llvm.org/D93005
2020-12-09 22:37:20 -05:00
|
|
|
if (parser.parseColon() || parser.parseSuccessor(destination))
|
|
|
|
return failure();
|
|
|
|
if (!parser.parseOptionalLParen()) {
|
|
|
|
if (parser.parseRegionArgumentList(operands) ||
|
[mlir] Add support for VariadicOfVariadic operands
This revision adds native ODS support for VariadicOfVariadic operand
groups. An example of this is the SwitchOp, which has a variadic number
of nested operand ranges for each of the case statements, where the
number of case statements is variadic. Builtin ODS support allows for
generating proper accessors for the nested operand ranges, builder
support, and declarative format support. VariadicOfVariadic operands
are supported by providing a segment attribute to use to store the
operand groups, mapping similarly to the AttrSizedOperand trait
(but with a user defined attribute name).
`build` methods for VariadicOfVariadic operand expect inputs of the
form `ArrayRef<ValueRange>`. Accessors for the variadic ranges
return a new `OperandRangeRange` type, which represents a
contiguous range of `OperandRange`. In the declarative assembly
format, VariadicOfVariadic operands and types are by default
formatted as a comma delimited list of value lists:
`(<value>, <value>), (), (<value>)`.
Differential Revision: https://reviews.llvm.org/D107774
2021-08-23 20:23:09 +00:00
|
|
|
parser.parseColonTypeList(operandTypes) || parser.parseRParen())
|
[mlir][LLVMIR] Add 'llvm.switch' op
The LLVM IR 'switch' instruction allows control flow to be transferred
to one of any number of branches depending on an integer control value,
or a default value if the control does not match any branch values. This patch
adds `llvm.switch` to the MLIR LLVMIR dialect, as well as translation routines
for lowering it to LLVM IR.
To store a variable number of operands for a variable number of branch
destinations, the new op makes use of the `AttrSizedOperandSegments`
trait. It stores its default branch operands as one segment, and all
remaining case branches' operands as another. It also stores pairs of
begin and end offset values to delineate the sub-range of each case branch's
operands. There's probably a better way to implement this, since the
offset computation complicates several parts of the op definition. This is the
approach I settled on because in doing so I was able to delegate to the default
op builder member functions. However, it may be preferable to instead specify
`skipDefaultBuilders` in the op's ODS, or use a completely separate
approach; feedback is welcome!
Another contentious part of this patch may be the custom printer and
parser functions for the op. Ideally I would have liked the MLIR to be
printed in this way:
```
llvm.switch %0, ^bb1(%1 : !llvm.i32) [
1: ^bb2,
2: ^bb3(%2, %3 : !llvm.i32, !llvm.i32)
]
```
The above would resemble how LLVM IR is formatted for the 'switch'
instruction. But I found it difficult to print and parse something like
this, whether I used the declarative assembly format or custom functions.
I also was not sure a multi-line format would be welcome -- it seems
like most MLIR ops do not use newlines. Again, I'd be happy to hear any
feedback here as well, or on any other aspect of the patch.
Differential Revision: https://reviews.llvm.org/D93005
2020-12-09 22:37:20 -05:00
|
|
|
return failure();
|
|
|
|
}
|
|
|
|
caseDestinations.push_back(destination);
|
[mlir] Add support for VariadicOfVariadic operands
This revision adds native ODS support for VariadicOfVariadic operand
groups. An example of this is the SwitchOp, which has a variadic number
of nested operand ranges for each of the case statements, where the
number of case statements is variadic. Builtin ODS support allows for
generating proper accessors for the nested operand ranges, builder
support, and declarative format support. VariadicOfVariadic operands
are supported by providing a segment attribute to use to store the
operand groups, mapping similarly to the AttrSizedOperand trait
(but with a user defined attribute name).
`build` methods for VariadicOfVariadic operand expect inputs of the
form `ArrayRef<ValueRange>`. Accessors for the variadic ranges
return a new `OperandRangeRange` type, which represents a
contiguous range of `OperandRange`. In the declarative assembly
format, VariadicOfVariadic operands and types are by default
formatted as a comma delimited list of value lists:
`(<value>, <value>), (), (<value>)`.
Differential Revision: https://reviews.llvm.org/D107774
2021-08-23 20:23:09 +00:00
|
|
|
caseOperands.emplace_back(operands);
|
|
|
|
caseOperandTypes.emplace_back(operandTypes);
|
[mlir][LLVMIR] Add 'llvm.switch' op
The LLVM IR 'switch' instruction allows control flow to be transferred
to one of any number of branches depending on an integer control value,
or a default value if the control does not match any branch values. This patch
adds `llvm.switch` to the MLIR LLVMIR dialect, as well as translation routines
for lowering it to LLVM IR.
To store a variable number of operands for a variable number of branch
destinations, the new op makes use of the `AttrSizedOperandSegments`
trait. It stores its default branch operands as one segment, and all
remaining case branches' operands as another. It also stores pairs of
begin and end offset values to delineate the sub-range of each case branch's
operands. There's probably a better way to implement this, since the
offset computation complicates several parts of the op definition. This is the
approach I settled on because in doing so I was able to delegate to the default
op builder member functions. However, it may be preferable to instead specify
`skipDefaultBuilders` in the op's ODS, or use a completely separate
approach; feedback is welcome!
Another contentious part of this patch may be the custom printer and
parser functions for the op. Ideally I would have liked the MLIR to be
printed in this way:
```
llvm.switch %0, ^bb1(%1 : !llvm.i32) [
1: ^bb2,
2: ^bb3(%2, %3 : !llvm.i32, !llvm.i32)
]
```
The above would resemble how LLVM IR is formatted for the 'switch'
instruction. But I found it difficult to print and parse something like
this, whether I used the declarative assembly format or custom functions.
I also was not sure a multi-line format would be welcome -- it seems
like most MLIR ops do not use newlines. Again, I'd be happy to hear any
feedback here as well, or on any other aspect of the patch.
Differential Revision: https://reviews.llvm.org/D93005
2020-12-09 22:37:20 -05:00
|
|
|
} while (!parser.parseOptionalComma());
|
|
|
|
|
2021-11-15 20:13:33 -05:00
|
|
|
ShapedType caseValueType =
|
|
|
|
VectorType::get(static_cast<int64_t>(values.size()), flagType);
|
|
|
|
caseValues = DenseIntElementsAttr::get(caseValueType, values);
|
[mlir][LLVMIR] Add 'llvm.switch' op
The LLVM IR 'switch' instruction allows control flow to be transferred
to one of any number of branches depending on an integer control value,
or a default value if the control does not match any branch values. This patch
adds `llvm.switch` to the MLIR LLVMIR dialect, as well as translation routines
for lowering it to LLVM IR.
To store a variable number of operands for a variable number of branch
destinations, the new op makes use of the `AttrSizedOperandSegments`
trait. It stores its default branch operands as one segment, and all
remaining case branches' operands as another. It also stores pairs of
begin and end offset values to delineate the sub-range of each case branch's
operands. There's probably a better way to implement this, since the
offset computation complicates several parts of the op definition. This is the
approach I settled on because in doing so I was able to delegate to the default
op builder member functions. However, it may be preferable to instead specify
`skipDefaultBuilders` in the op's ODS, or use a completely separate
approach; feedback is welcome!
Another contentious part of this patch may be the custom printer and
parser functions for the op. Ideally I would have liked the MLIR to be
printed in this way:
```
llvm.switch %0, ^bb1(%1 : !llvm.i32) [
1: ^bb2,
2: ^bb3(%2, %3 : !llvm.i32, !llvm.i32)
]
```
The above would resemble how LLVM IR is formatted for the 'switch'
instruction. But I found it difficult to print and parse something like
this, whether I used the declarative assembly format or custom functions.
I also was not sure a multi-line format would be welcome -- it seems
like most MLIR ops do not use newlines. Again, I'd be happy to hear any
feedback here as well, or on any other aspect of the patch.
Differential Revision: https://reviews.llvm.org/D93005
2020-12-09 22:37:20 -05:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2021-11-15 20:13:33 -05:00
|
|
|
static void printSwitchOpCases(OpAsmPrinter &p, SwitchOp op, Type flagType,
|
[mlir][LLVMIR] Add 'llvm.switch' op
The LLVM IR 'switch' instruction allows control flow to be transferred
to one of any number of branches depending on an integer control value,
or a default value if the control does not match any branch values. This patch
adds `llvm.switch` to the MLIR LLVMIR dialect, as well as translation routines
for lowering it to LLVM IR.
To store a variable number of operands for a variable number of branch
destinations, the new op makes use of the `AttrSizedOperandSegments`
trait. It stores its default branch operands as one segment, and all
remaining case branches' operands as another. It also stores pairs of
begin and end offset values to delineate the sub-range of each case branch's
operands. There's probably a better way to implement this, since the
offset computation complicates several parts of the op definition. This is the
approach I settled on because in doing so I was able to delegate to the default
op builder member functions. However, it may be preferable to instead specify
`skipDefaultBuilders` in the op's ODS, or use a completely separate
approach; feedback is welcome!
Another contentious part of this patch may be the custom printer and
parser functions for the op. Ideally I would have liked the MLIR to be
printed in this way:
```
llvm.switch %0, ^bb1(%1 : !llvm.i32) [
1: ^bb2,
2: ^bb3(%2, %3 : !llvm.i32, !llvm.i32)
]
```
The above would resemble how LLVM IR is formatted for the 'switch'
instruction. But I found it difficult to print and parse something like
this, whether I used the declarative assembly format or custom functions.
I also was not sure a multi-line format would be welcome -- it seems
like most MLIR ops do not use newlines. Again, I'd be happy to hear any
feedback here as well, or on any other aspect of the patch.
Differential Revision: https://reviews.llvm.org/D93005
2020-12-09 22:37:20 -05:00
|
|
|
ElementsAttr caseValues,
|
|
|
|
SuccessorRange caseDestinations,
|
[mlir] Add support for VariadicOfVariadic operands
This revision adds native ODS support for VariadicOfVariadic operand
groups. An example of this is the SwitchOp, which has a variadic number
of nested operand ranges for each of the case statements, where the
number of case statements is variadic. Builtin ODS support allows for
generating proper accessors for the nested operand ranges, builder
support, and declarative format support. VariadicOfVariadic operands
are supported by providing a segment attribute to use to store the
operand groups, mapping similarly to the AttrSizedOperand trait
(but with a user defined attribute name).
`build` methods for VariadicOfVariadic operand expect inputs of the
form `ArrayRef<ValueRange>`. Accessors for the variadic ranges
return a new `OperandRangeRange` type, which represents a
contiguous range of `OperandRange`. In the declarative assembly
format, VariadicOfVariadic operands and types are by default
formatted as a comma delimited list of value lists:
`(<value>, <value>), (), (<value>)`.
Differential Revision: https://reviews.llvm.org/D107774
2021-08-23 20:23:09 +00:00
|
|
|
OperandRangeRange caseOperands,
|
2022-01-02 01:26:44 +00:00
|
|
|
const TypeRangeRange &caseOperandTypes) {
|
[mlir][LLVMIR] Add 'llvm.switch' op
The LLVM IR 'switch' instruction allows control flow to be transferred
to one of any number of branches depending on an integer control value,
or a default value if the control does not match any branch values. This patch
adds `llvm.switch` to the MLIR LLVMIR dialect, as well as translation routines
for lowering it to LLVM IR.
To store a variable number of operands for a variable number of branch
destinations, the new op makes use of the `AttrSizedOperandSegments`
trait. It stores its default branch operands as one segment, and all
remaining case branches' operands as another. It also stores pairs of
begin and end offset values to delineate the sub-range of each case branch's
operands. There's probably a better way to implement this, since the
offset computation complicates several parts of the op definition. This is the
approach I settled on because in doing so I was able to delegate to the default
op builder member functions. However, it may be preferable to instead specify
`skipDefaultBuilders` in the op's ODS, or use a completely separate
approach; feedback is welcome!
Another contentious part of this patch may be the custom printer and
parser functions for the op. Ideally I would have liked the MLIR to be
printed in this way:
```
llvm.switch %0, ^bb1(%1 : !llvm.i32) [
1: ^bb2,
2: ^bb3(%2, %3 : !llvm.i32, !llvm.i32)
]
```
The above would resemble how LLVM IR is formatted for the 'switch'
instruction. But I found it difficult to print and parse something like
this, whether I used the declarative assembly format or custom functions.
I also was not sure a multi-line format would be welcome -- it seems
like most MLIR ops do not use newlines. Again, I'd be happy to hear any
feedback here as well, or on any other aspect of the patch.
Differential Revision: https://reviews.llvm.org/D93005
2020-12-09 22:37:20 -05:00
|
|
|
if (!caseValues)
|
|
|
|
return;
|
|
|
|
|
|
|
|
size_t index = 0;
|
|
|
|
llvm::interleave(
|
|
|
|
llvm::zip(caseValues.cast<DenseIntElementsAttr>(), caseDestinations),
|
|
|
|
[&](auto i) {
|
|
|
|
p << " ";
|
|
|
|
p << std::get<0>(i).getLimitedValue();
|
|
|
|
p << ": ";
|
[mlir] Add support for VariadicOfVariadic operands
This revision adds native ODS support for VariadicOfVariadic operand
groups. An example of this is the SwitchOp, which has a variadic number
of nested operand ranges for each of the case statements, where the
number of case statements is variadic. Builtin ODS support allows for
generating proper accessors for the nested operand ranges, builder
support, and declarative format support. VariadicOfVariadic operands
are supported by providing a segment attribute to use to store the
operand groups, mapping similarly to the AttrSizedOperand trait
(but with a user defined attribute name).
`build` methods for VariadicOfVariadic operand expect inputs of the
form `ArrayRef<ValueRange>`. Accessors for the variadic ranges
return a new `OperandRangeRange` type, which represents a
contiguous range of `OperandRange`. In the declarative assembly
format, VariadicOfVariadic operands and types are by default
formatted as a comma delimited list of value lists:
`(<value>, <value>), (), (<value>)`.
Differential Revision: https://reviews.llvm.org/D107774
2021-08-23 20:23:09 +00:00
|
|
|
p.printSuccessorAndUseList(std::get<1>(i), caseOperands[index++]);
|
[mlir][LLVMIR] Add 'llvm.switch' op
The LLVM IR 'switch' instruction allows control flow to be transferred
to one of any number of branches depending on an integer control value,
or a default value if the control does not match any branch values. This patch
adds `llvm.switch` to the MLIR LLVMIR dialect, as well as translation routines
for lowering it to LLVM IR.
To store a variable number of operands for a variable number of branch
destinations, the new op makes use of the `AttrSizedOperandSegments`
trait. It stores its default branch operands as one segment, and all
remaining case branches' operands as another. It also stores pairs of
begin and end offset values to delineate the sub-range of each case branch's
operands. There's probably a better way to implement this, since the
offset computation complicates several parts of the op definition. This is the
approach I settled on because in doing so I was able to delegate to the default
op builder member functions. However, it may be preferable to instead specify
`skipDefaultBuilders` in the op's ODS, or use a completely separate
approach; feedback is welcome!
Another contentious part of this patch may be the custom printer and
parser functions for the op. Ideally I would have liked the MLIR to be
printed in this way:
```
llvm.switch %0, ^bb1(%1 : !llvm.i32) [
1: ^bb2,
2: ^bb3(%2, %3 : !llvm.i32, !llvm.i32)
]
```
The above would resemble how LLVM IR is formatted for the 'switch'
instruction. But I found it difficult to print and parse something like
this, whether I used the declarative assembly format or custom functions.
I also was not sure a multi-line format would be welcome -- it seems
like most MLIR ops do not use newlines. Again, I'd be happy to hear any
feedback here as well, or on any other aspect of the patch.
Differential Revision: https://reviews.llvm.org/D93005
2020-12-09 22:37:20 -05:00
|
|
|
},
|
|
|
|
[&] {
|
|
|
|
p << ',';
|
|
|
|
p.printNewline();
|
|
|
|
});
|
|
|
|
p.printNewline();
|
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult SwitchOp::verify() {
|
|
|
|
if ((!getCaseValues() && !getCaseDestinations().empty()) ||
|
|
|
|
(getCaseValues() &&
|
|
|
|
getCaseValues()->size() !=
|
|
|
|
static_cast<int64_t>(getCaseDestinations().size())))
|
|
|
|
return emitOpError("expects number of case values to match number of "
|
|
|
|
"case destinations");
|
|
|
|
if (getBranchWeights() && getBranchWeights()->size() != getNumSuccessors())
|
|
|
|
return emitError("expects number of branch weights to match number of "
|
|
|
|
"successors: ")
|
|
|
|
<< getBranchWeights()->size() << " vs " << getNumSuccessors();
|
[mlir][LLVMIR] Add 'llvm.switch' op
The LLVM IR 'switch' instruction allows control flow to be transferred
to one of any number of branches depending on an integer control value,
or a default value if the control does not match any branch values. This patch
adds `llvm.switch` to the MLIR LLVMIR dialect, as well as translation routines
for lowering it to LLVM IR.
To store a variable number of operands for a variable number of branch
destinations, the new op makes use of the `AttrSizedOperandSegments`
trait. It stores its default branch operands as one segment, and all
remaining case branches' operands as another. It also stores pairs of
begin and end offset values to delineate the sub-range of each case branch's
operands. There's probably a better way to implement this, since the
offset computation complicates several parts of the op definition. This is the
approach I settled on because in doing so I was able to delegate to the default
op builder member functions. However, it may be preferable to instead specify
`skipDefaultBuilders` in the op's ODS, or use a completely separate
approach; feedback is welcome!
Another contentious part of this patch may be the custom printer and
parser functions for the op. Ideally I would have liked the MLIR to be
printed in this way:
```
llvm.switch %0, ^bb1(%1 : !llvm.i32) [
1: ^bb2,
2: ^bb3(%2, %3 : !llvm.i32, !llvm.i32)
]
```
The above would resemble how LLVM IR is formatted for the 'switch'
instruction. But I found it difficult to print and parse something like
this, whether I used the declarative assembly format or custom functions.
I also was not sure a multi-line format would be welcome -- it seems
like most MLIR ops do not use newlines. Again, I'd be happy to hear any
feedback here as well, or on any other aspect of the patch.
Differential Revision: https://reviews.llvm.org/D93005
2020-12-09 22:37:20 -05:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
Optional<MutableOperandRange>
|
|
|
|
SwitchOp::getMutableSuccessorOperands(unsigned index) {
|
|
|
|
assert(index < getNumSuccessors() && "invalid successor index");
|
2021-10-29 13:29:48 -07:00
|
|
|
return index == 0 ? getDefaultOperandsMutable()
|
[mlir][LLVMIR] Add 'llvm.switch' op
The LLVM IR 'switch' instruction allows control flow to be transferred
to one of any number of branches depending on an integer control value,
or a default value if the control does not match any branch values. This patch
adds `llvm.switch` to the MLIR LLVMIR dialect, as well as translation routines
for lowering it to LLVM IR.
To store a variable number of operands for a variable number of branch
destinations, the new op makes use of the `AttrSizedOperandSegments`
trait. It stores its default branch operands as one segment, and all
remaining case branches' operands as another. It also stores pairs of
begin and end offset values to delineate the sub-range of each case branch's
operands. There's probably a better way to implement this, since the
offset computation complicates several parts of the op definition. This is the
approach I settled on because in doing so I was able to delegate to the default
op builder member functions. However, it may be preferable to instead specify
`skipDefaultBuilders` in the op's ODS, or use a completely separate
approach; feedback is welcome!
Another contentious part of this patch may be the custom printer and
parser functions for the op. Ideally I would have liked the MLIR to be
printed in this way:
```
llvm.switch %0, ^bb1(%1 : !llvm.i32) [
1: ^bb2,
2: ^bb3(%2, %3 : !llvm.i32, !llvm.i32)
]
```
The above would resemble how LLVM IR is formatted for the 'switch'
instruction. But I found it difficult to print and parse something like
this, whether I used the declarative assembly format or custom functions.
I also was not sure a multi-line format would be welcome -- it seems
like most MLIR ops do not use newlines. Again, I'd be happy to hear any
feedback here as well, or on any other aspect of the patch.
Differential Revision: https://reviews.llvm.org/D93005
2020-12-09 22:37:20 -05:00
|
|
|
: getCaseOperandsMutable(index - 1);
|
|
|
|
}
|
|
|
|
|
2022-01-06 23:29:15 +01:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Code for LLVM::GEPOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-01-07 12:04:17 +01:00
|
|
|
constexpr int GEPOp::kDynamicIndex;
|
|
|
|
|
2022-01-06 23:30:15 +01:00
|
|
|
/// Populates `indices` with positions of GEP indices that would correspond to
|
|
|
|
/// LLVMStructTypes potentially nested in the given type. The type currently
|
|
|
|
/// visited gets `currentIndex` and LLVM container types are visited
|
|
|
|
/// recursively. The recursion is bounded and takes care of recursive types by
|
|
|
|
/// means of the `visited` set.
|
|
|
|
static void recordStructIndices(Type type, unsigned currentIndex,
|
|
|
|
SmallVectorImpl<unsigned> &indices,
|
|
|
|
SmallVectorImpl<unsigned> *structSizes,
|
|
|
|
SmallPtrSet<Type, 4> &visited) {
|
|
|
|
if (visited.contains(type))
|
|
|
|
return;
|
|
|
|
|
|
|
|
visited.insert(type);
|
|
|
|
|
|
|
|
llvm::TypeSwitch<Type>(type)
|
|
|
|
.Case<LLVMStructType>([&](LLVMStructType structType) {
|
|
|
|
indices.push_back(currentIndex);
|
|
|
|
if (structSizes)
|
|
|
|
structSizes->push_back(structType.getBody().size());
|
|
|
|
for (Type elementType : structType.getBody())
|
|
|
|
recordStructIndices(elementType, currentIndex + 1, indices,
|
|
|
|
structSizes, visited);
|
|
|
|
})
|
|
|
|
.Case<VectorType, LLVMScalableVectorType, LLVMFixedVectorType,
|
|
|
|
LLVMArrayType>([&](auto containerType) {
|
|
|
|
recordStructIndices(containerType.getElementType(), currentIndex + 1,
|
|
|
|
indices, structSizes, visited);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Populates `indices` with positions of GEP indices that correspond to
|
|
|
|
/// LLVMStructTypes potentially nested in the given `baseGEPType`, which must
|
|
|
|
/// be either an LLVMPointer type or a vector thereof. If `structSizes` is
|
|
|
|
/// provided, it is populated with sizes of the indexed structs for bounds
|
|
|
|
/// verification purposes.
|
|
|
|
static void
|
|
|
|
findKnownStructIndices(Type baseGEPType, SmallVectorImpl<unsigned> &indices,
|
|
|
|
SmallVectorImpl<unsigned> *structSizes = nullptr) {
|
|
|
|
Type type = baseGEPType;
|
|
|
|
if (auto vectorType = type.dyn_cast<VectorType>())
|
|
|
|
type = vectorType.getElementType();
|
|
|
|
if (auto scalableVectorType = type.dyn_cast<LLVMScalableVectorType>())
|
|
|
|
type = scalableVectorType.getElementType();
|
|
|
|
if (auto fixedVectorType = type.dyn_cast<LLVMFixedVectorType>())
|
|
|
|
type = fixedVectorType.getElementType();
|
|
|
|
|
|
|
|
Type pointeeType = type.cast<LLVMPointerType>().getElementType();
|
|
|
|
SmallPtrSet<Type, 4> visited;
|
|
|
|
recordStructIndices(pointeeType, /*currentIndex=*/1, indices, structSizes,
|
|
|
|
visited);
|
|
|
|
}
|
|
|
|
|
2022-01-06 23:29:15 +01:00
|
|
|
void GEPOp::build(OpBuilder &builder, OperationState &result, Type resultType,
|
|
|
|
Value basePtr, ValueRange operands,
|
|
|
|
ArrayRef<NamedAttribute> attributes) {
|
|
|
|
build(builder, result, resultType, basePtr, operands,
|
|
|
|
SmallVector<int32_t>(operands.size(), LLVM::GEPOp::kDynamicIndex),
|
|
|
|
attributes);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GEPOp::build(OpBuilder &builder, OperationState &result, Type resultType,
|
|
|
|
Value basePtr, ValueRange indices,
|
|
|
|
ArrayRef<int32_t> structIndices,
|
|
|
|
ArrayRef<NamedAttribute> attributes) {
|
2022-01-06 23:30:15 +01:00
|
|
|
SmallVector<Value> remainingIndices;
|
|
|
|
SmallVector<int32_t> updatedStructIndices(structIndices.begin(),
|
|
|
|
structIndices.end());
|
|
|
|
SmallVector<unsigned> structRelatedPositions;
|
|
|
|
findKnownStructIndices(basePtr.getType(), structRelatedPositions);
|
|
|
|
|
|
|
|
SmallVector<unsigned> operandsToErase;
|
|
|
|
for (unsigned pos : structRelatedPositions) {
|
|
|
|
// GEP may not be indexing as deep as some structs are located.
|
|
|
|
if (pos >= structIndices.size())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// If the index is already static, it's fine.
|
|
|
|
if (structIndices[pos] != kDynamicIndex)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Find the corresponding operand.
|
|
|
|
unsigned operandPos =
|
|
|
|
std::count(structIndices.begin(), std::next(structIndices.begin(), pos),
|
|
|
|
kDynamicIndex);
|
|
|
|
|
|
|
|
// Extract the constant value from the operand and put it into the attribute
|
|
|
|
// instead.
|
|
|
|
APInt staticIndexValue;
|
|
|
|
bool matched =
|
|
|
|
matchPattern(indices[operandPos], m_ConstantInt(&staticIndexValue));
|
|
|
|
(void)matched;
|
|
|
|
assert(matched && "index into a struct must be a constant");
|
|
|
|
assert(staticIndexValue.sge(APInt::getSignedMinValue(/*numBits=*/32)) &&
|
|
|
|
"struct index underflows 32-bit integer");
|
|
|
|
assert(staticIndexValue.sle(APInt::getSignedMaxValue(/*numBits=*/32)) &&
|
|
|
|
"struct index overflows 32-bit integer");
|
|
|
|
auto staticIndex = static_cast<int32_t>(staticIndexValue.getSExtValue());
|
|
|
|
updatedStructIndices[pos] = staticIndex;
|
|
|
|
operandsToErase.push_back(operandPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = indices.size(); i < e; ++i) {
|
2022-01-10 12:40:38 +01:00
|
|
|
if (!llvm::is_contained(operandsToErase, i))
|
2022-01-06 23:30:15 +01:00
|
|
|
remainingIndices.push_back(indices[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(remainingIndices.size() == static_cast<size_t>(llvm::count(
|
|
|
|
updatedStructIndices, kDynamicIndex)) &&
|
2022-01-10 12:40:38 +01:00
|
|
|
"expected as many index operands as dynamic index attr elements");
|
2022-01-06 23:30:15 +01:00
|
|
|
|
2022-01-06 23:29:15 +01:00
|
|
|
result.addTypes(resultType);
|
|
|
|
result.addAttributes(attributes);
|
2022-01-06 23:30:15 +01:00
|
|
|
result.addAttribute("structIndices",
|
|
|
|
builder.getI32TensorAttr(updatedStructIndices));
|
2022-01-06 23:29:15 +01:00
|
|
|
result.addOperands(basePtr);
|
2022-01-06 23:30:15 +01:00
|
|
|
result.addOperands(remainingIndices);
|
2022-01-06 23:29:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static ParseResult
|
|
|
|
parseGEPIndices(OpAsmParser &parser,
|
|
|
|
SmallVectorImpl<OpAsmParser::OperandType> &indices,
|
|
|
|
DenseIntElementsAttr &structIndices) {
|
|
|
|
SmallVector<int32_t> constantIndices;
|
|
|
|
do {
|
|
|
|
int32_t constantIndex;
|
|
|
|
OptionalParseResult parsedInteger =
|
|
|
|
parser.parseOptionalInteger(constantIndex);
|
|
|
|
if (parsedInteger.hasValue()) {
|
|
|
|
if (failed(parsedInteger.getValue()))
|
|
|
|
return failure();
|
|
|
|
constantIndices.push_back(constantIndex);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
constantIndices.push_back(LLVM::GEPOp::kDynamicIndex);
|
|
|
|
if (failed(parser.parseOperand(indices.emplace_back())))
|
|
|
|
return failure();
|
|
|
|
} while (succeeded(parser.parseOptionalComma()));
|
|
|
|
|
|
|
|
structIndices = parser.getBuilder().getI32TensorAttr(constantIndices);
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void printGEPIndices(OpAsmPrinter &printer, LLVM::GEPOp gepOp,
|
|
|
|
OperandRange indices,
|
|
|
|
DenseIntElementsAttr structIndices) {
|
|
|
|
unsigned operandIdx = 0;
|
|
|
|
llvm::interleaveComma(structIndices.getValues<int32_t>(), printer,
|
|
|
|
[&](int32_t cst) {
|
|
|
|
if (cst == LLVM::GEPOp::kDynamicIndex)
|
|
|
|
printer.printOperand(indices[operandIdx++]);
|
|
|
|
else
|
|
|
|
printer << cst;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult LLVM::GEPOp::verify() {
|
2022-01-06 23:30:15 +01:00
|
|
|
SmallVector<unsigned> indices;
|
|
|
|
SmallVector<unsigned> structSizes;
|
2022-02-02 10:16:28 -08:00
|
|
|
findKnownStructIndices(getBase().getType(), indices, &structSizes);
|
|
|
|
DenseIntElementsAttr structIndices = getStructIndices();
|
2022-01-10 12:40:38 +01:00
|
|
|
for (unsigned i : llvm::seq<unsigned>(0, indices.size())) {
|
2022-01-06 23:30:15 +01:00
|
|
|
unsigned index = indices[i];
|
|
|
|
// GEP may not be indexing as deep as some structs nested in the type.
|
2022-01-10 12:40:38 +01:00
|
|
|
if (index >= structIndices.getNumElements())
|
2022-01-06 23:30:15 +01:00
|
|
|
continue;
|
|
|
|
|
2022-01-10 12:40:38 +01:00
|
|
|
int32_t staticIndex = structIndices.getValues<int32_t>()[index];
|
2022-01-06 23:30:15 +01:00
|
|
|
if (staticIndex == LLVM::GEPOp::kDynamicIndex)
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError() << "expected index " << index
|
|
|
|
<< " indexing a struct to be constant";
|
2022-01-06 23:30:15 +01:00
|
|
|
if (staticIndex < 0 || static_cast<unsigned>(staticIndex) >= structSizes[i])
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError() << "index " << index
|
|
|
|
<< " indexing a struct is out of bounds";
|
2022-01-06 23:30:15 +01:00
|
|
|
}
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
2020-07-27 10:19:48 +03:00
|
|
|
// Builder, printer and parser for for LLVM::LoadOp.
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2021-08-24 20:38:32 +02:00
|
|
|
LogicalResult verifySymbolAttribute(
|
|
|
|
Operation *op, StringRef attributeName,
|
2022-01-02 01:26:44 +00:00
|
|
|
llvm::function_ref<LogicalResult(Operation *, SymbolRefAttr)>
|
|
|
|
verifySymbolType) {
|
2021-08-24 20:38:32 +02:00
|
|
|
if (Attribute attribute = op->getAttr(attributeName)) {
|
2021-03-04 18:12:56 +01:00
|
|
|
// The attribute is already verified to be a symbol ref array attribute via
|
|
|
|
// a constraint in the operation definition.
|
2021-08-24 20:38:32 +02:00
|
|
|
for (SymbolRefAttr symbolRef :
|
2021-03-04 18:12:56 +01:00
|
|
|
attribute.cast<ArrayAttr>().getAsRange<SymbolRefAttr>()) {
|
2021-08-29 14:22:24 -07:00
|
|
|
StringAttr metadataName = symbolRef.getRootReference();
|
|
|
|
StringAttr symbolName = symbolRef.getLeafReference();
|
2021-08-24 20:38:32 +02:00
|
|
|
// We want @metadata::@symbol, not just @symbol
|
|
|
|
if (metadataName == symbolName) {
|
|
|
|
return op->emitOpError() << "expected '" << symbolRef
|
|
|
|
<< "' to specify a fully qualified reference";
|
|
|
|
}
|
2021-03-04 18:12:56 +01:00
|
|
|
auto metadataOp = SymbolTable::lookupNearestSymbolFrom<LLVM::MetadataOp>(
|
|
|
|
op->getParentOp(), metadataName);
|
|
|
|
if (!metadataOp)
|
2021-08-24 20:38:32 +02:00
|
|
|
return op->emitOpError()
|
|
|
|
<< "expected '" << symbolRef << "' to reference a metadata op";
|
|
|
|
Operation *symbolOp =
|
|
|
|
SymbolTable::lookupNearestSymbolFrom(metadataOp, symbolName);
|
|
|
|
if (!symbolOp)
|
|
|
|
return op->emitOpError()
|
|
|
|
<< "expected '" << symbolRef << "' to be a valid reference";
|
|
|
|
if (failed(verifySymbolType(symbolOp, symbolRef))) {
|
|
|
|
return failure();
|
|
|
|
}
|
2021-03-04 18:12:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2021-08-24 20:38:32 +02:00
|
|
|
// Verifies that metadata ops are wired up properly.
|
|
|
|
template <typename OpTy>
|
|
|
|
static LogicalResult verifyOpMetadata(Operation *op, StringRef attributeName) {
|
|
|
|
auto verifySymbolType = [op](Operation *symbolOp,
|
|
|
|
SymbolRefAttr symbolRef) -> LogicalResult {
|
|
|
|
if (!isa<OpTy>(symbolOp)) {
|
|
|
|
return op->emitOpError()
|
|
|
|
<< "expected '" << symbolRef << "' to resolve to a "
|
|
|
|
<< OpTy::getOperationName();
|
|
|
|
}
|
|
|
|
return success();
|
|
|
|
};
|
|
|
|
|
|
|
|
return verifySymbolAttribute(op, attributeName, verifySymbolType);
|
|
|
|
}
|
|
|
|
|
|
|
|
static LogicalResult verifyMemoryOpMetadata(Operation *op) {
|
|
|
|
// access_groups
|
|
|
|
if (failed(verifyOpMetadata<LLVM::AccessGroupMetadataOp>(
|
|
|
|
op, LLVMDialect::getAccessGroupsAttrName())))
|
|
|
|
return failure();
|
|
|
|
|
|
|
|
// alias_scopes
|
|
|
|
if (failed(verifyOpMetadata<LLVM::AliasScopeMetadataOp>(
|
|
|
|
op, LLVMDialect::getAliasScopesAttrName())))
|
|
|
|
return failure();
|
|
|
|
|
|
|
|
// noalias_scopes
|
|
|
|
if (failed(verifyOpMetadata<LLVM::AliasScopeMetadataOp>(
|
|
|
|
op, LLVMDialect::getNoAliasScopesAttrName())))
|
|
|
|
return failure();
|
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult LoadOp::verify() { return verifyMemoryOpMetadata(*this); }
|
2021-03-04 18:12:56 +01:00
|
|
|
|
2020-07-27 10:19:48 +03:00
|
|
|
void LoadOp::build(OpBuilder &builder, OperationState &result, Type t,
|
|
|
|
Value addr, unsigned alignment, bool isVolatile,
|
|
|
|
bool isNonTemporal) {
|
|
|
|
result.addOperands(addr);
|
|
|
|
result.addTypes(t);
|
|
|
|
if (isVolatile)
|
|
|
|
result.addAttribute(kVolatileAttrName, builder.getUnitAttr());
|
|
|
|
if (isNonTemporal)
|
|
|
|
result.addAttribute(kNonTemporalAttrName, builder.getUnitAttr());
|
|
|
|
if (alignment != 0)
|
|
|
|
result.addAttribute("alignment", builder.getI64IntegerAttr(alignment));
|
|
|
|
}
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
void LoadOp::print(OpAsmPrinter &p) {
|
2021-08-28 03:03:15 +00:00
|
|
|
p << ' ';
|
2022-02-07 17:54:04 -08:00
|
|
|
if (getVolatile_())
|
2020-07-27 10:19:48 +03:00
|
|
|
p << "volatile ";
|
2022-02-07 17:54:04 -08:00
|
|
|
p << getAddr();
|
|
|
|
p.printOptionalAttrDict((*this)->getAttrs(), {kVolatileAttrName});
|
|
|
|
p << " : " << getAddr().getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Extract the pointee type from the LLVM pointer type wrapped in MLIR. Return
|
|
|
|
// the resulting type wrapped in MLIR, or nullptr on error.
|
2019-09-20 11:36:49 -07:00
|
|
|
static Type getLoadStoreElementType(OpAsmParser &parser, Type type,
|
2022-01-26 15:49:53 -08:00
|
|
|
SMLoc trailingTypeLoc) {
|
2020-12-22 11:22:21 +01:00
|
|
|
auto llvmTy = type.dyn_cast<LLVM::LLVMPointerType>();
|
2019-04-02 15:33:54 -07:00
|
|
|
if (!llvmTy)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(trailingTypeLoc, "expected LLVM pointer type"),
|
2019-04-02 15:33:54 -07:00
|
|
|
nullptr;
|
2020-12-22 11:22:21 +01:00
|
|
|
return llvmTy.getElementType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2020-07-27 10:19:48 +03:00
|
|
|
// <operation> ::= `llvm.load` `volatile` ssa-use attribute-dict? `:` type
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult LoadOp::parse(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
OpAsmParser::OperandType addr;
|
|
|
|
Type type;
|
2022-01-26 15:49:53 -08:00
|
|
|
SMLoc trailingTypeLoc;
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2020-07-27 10:19:48 +03:00
|
|
|
if (succeeded(parser.parseOptionalKeyword("volatile")))
|
|
|
|
result.addAttribute(kVolatileAttrName, parser.getBuilder().getUnitAttr());
|
|
|
|
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
if (parser.parseOperand(addr) ||
|
|
|
|
parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
|
|
|
|
parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type) ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.resolveOperand(addr, type, result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
Type elemTy = getLoadStoreElementType(parser, type, trailingTypeLoc);
|
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes(elemTy);
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
2020-07-27 10:19:48 +03:00
|
|
|
// Builder, printer and parser for LLVM::StoreOp.
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult StoreOp::verify() { return verifyMemoryOpMetadata(*this); }
|
2021-03-04 18:12:56 +01:00
|
|
|
|
2020-07-27 10:19:48 +03:00
|
|
|
void StoreOp::build(OpBuilder &builder, OperationState &result, Value value,
|
|
|
|
Value addr, unsigned alignment, bool isVolatile,
|
|
|
|
bool isNonTemporal) {
|
|
|
|
result.addOperands({value, addr});
|
2020-09-22 21:00:11 -07:00
|
|
|
result.addTypes({});
|
2020-07-27 10:19:48 +03:00
|
|
|
if (isVolatile)
|
|
|
|
result.addAttribute(kVolatileAttrName, builder.getUnitAttr());
|
|
|
|
if (isNonTemporal)
|
|
|
|
result.addAttribute(kNonTemporalAttrName, builder.getUnitAttr());
|
|
|
|
if (alignment != 0)
|
|
|
|
result.addAttribute("alignment", builder.getI64IntegerAttr(alignment));
|
|
|
|
}
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
void StoreOp::print(OpAsmPrinter &p) {
|
2021-08-28 03:03:15 +00:00
|
|
|
p << ' ';
|
2022-02-07 17:54:04 -08:00
|
|
|
if (getVolatile_())
|
2020-07-27 10:19:48 +03:00
|
|
|
p << "volatile ";
|
2022-02-07 17:54:04 -08:00
|
|
|
p << getValue() << ", " << getAddr();
|
|
|
|
p.printOptionalAttrDict((*this)->getAttrs(), {kVolatileAttrName});
|
|
|
|
p << " : " << getAddr().getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2020-07-27 10:19:48 +03:00
|
|
|
// <operation> ::= `llvm.store` `volatile` ssa-use `,` ssa-use
|
|
|
|
// attribute-dict? `:` type
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult StoreOp::parse(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
OpAsmParser::OperandType addr, value;
|
|
|
|
Type type;
|
2022-01-26 15:49:53 -08:00
|
|
|
SMLoc trailingTypeLoc;
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2020-07-27 10:19:48 +03:00
|
|
|
if (succeeded(parser.parseOptionalKeyword("volatile")))
|
|
|
|
result.addAttribute(kVolatileAttrName, parser.getBuilder().getUnitAttr());
|
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperand(value) || parser.parseComma() ||
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
parser.parseOperand(addr) ||
|
|
|
|
parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
|
|
|
|
parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
Type elemTy = getLoadStoreElementType(parser, type, trailingTypeLoc);
|
|
|
|
if (!elemTy)
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
if (parser.resolveOperand(value, elemTy, result.operands) ||
|
|
|
|
parser.resolveOperand(addr, type, result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2020-03-05 12:48:28 -08:00
|
|
|
///===---------------------------------------------------------------------===//
|
2020-03-05 12:40:23 -08:00
|
|
|
/// LLVM::InvokeOp
|
2020-03-05 12:48:28 -08:00
|
|
|
///===---------------------------------------------------------------------===//
|
2020-01-30 12:50:12 +01:00
|
|
|
|
2020-04-29 16:09:43 -07:00
|
|
|
Optional<MutableOperandRange>
|
|
|
|
InvokeOp::getMutableSuccessorOperands(unsigned index) {
|
2020-03-05 12:40:23 -08:00
|
|
|
assert(index < getNumSuccessors() && "invalid successor index");
|
2021-10-29 13:29:48 -07:00
|
|
|
return index == 0 ? getNormalDestOperandsMutable()
|
|
|
|
: getUnwindDestOperandsMutable();
|
2020-03-05 12:40:23 -08:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult InvokeOp::verify() {
|
|
|
|
if (getNumResults() > 1)
|
|
|
|
return emitOpError("must have 0 or 1 result");
|
2020-01-30 12:50:12 +01:00
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
Block *unwindDest = getUnwindDest();
|
2020-02-21 13:19:50 -08:00
|
|
|
if (unwindDest->empty())
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitError("must have at least one operation in unwind destination");
|
2020-01-30 12:50:12 +01:00
|
|
|
|
|
|
|
// In unwind destination, first operation must be LandingpadOp
|
2020-02-21 13:19:50 -08:00
|
|
|
if (!isa<LandingpadOp>(unwindDest->front()))
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitError("first operation in unwind destination should be a "
|
|
|
|
"llvm.landingpad operation");
|
2020-01-30 12:50:12 +01:00
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
void InvokeOp::print(OpAsmPrinter &p) {
|
|
|
|
auto callee = getCallee();
|
2020-01-30 12:50:12 +01:00
|
|
|
bool isDirect = callee.hasValue();
|
|
|
|
|
2021-08-28 03:03:15 +00:00
|
|
|
p << ' ';
|
2020-01-30 12:50:12 +01:00
|
|
|
|
|
|
|
// Either function name or pointer
|
|
|
|
if (isDirect)
|
|
|
|
p.printSymbolName(callee.getValue());
|
|
|
|
else
|
2022-02-07 17:54:04 -08:00
|
|
|
p << getOperand(0);
|
2020-01-30 12:50:12 +01:00
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
p << '(' << getOperands().drop_front(isDirect ? 0 : 1) << ')';
|
2020-01-30 12:50:12 +01:00
|
|
|
p << " to ";
|
2022-02-07 17:54:04 -08:00
|
|
|
p.printSuccessorAndUseList(getNormalDest(), getNormalDestOperands());
|
2020-01-30 12:50:12 +01:00
|
|
|
p << " unwind ";
|
2022-02-07 17:54:04 -08:00
|
|
|
p.printSuccessorAndUseList(getUnwindDest(), getUnwindDestOperands());
|
2020-03-05 12:48:28 -08:00
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
p.printOptionalAttrDict((*this)->getAttrs(),
|
2020-03-05 12:48:28 -08:00
|
|
|
{InvokeOp::getOperandSegmentSizeAttr(), "callee"});
|
|
|
|
p << " : ";
|
2022-02-07 17:54:04 -08:00
|
|
|
p.printFunctionalType(llvm::drop_begin(getOperandTypes(), isDirect ? 0 : 1),
|
|
|
|
getResultTypes());
|
2020-01-30 12:50:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <operation> ::= `llvm.invoke` (function-id | ssa-use) `(` ssa-use-list `)`
|
|
|
|
/// `to` bb-id (`[` ssa-use-and-type-list `]`)?
|
|
|
|
/// `unwind` bb-id (`[` ssa-use-and-type-list `]`)?
|
|
|
|
/// attribute-dict? `:` function-type
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult InvokeOp::parse(OpAsmParser &parser, OperationState &result) {
|
2020-01-30 12:50:12 +01:00
|
|
|
SmallVector<OpAsmParser::OperandType, 8> operands;
|
|
|
|
FunctionType funcType;
|
|
|
|
SymbolRefAttr funcAttr;
|
2022-01-26 15:49:53 -08:00
|
|
|
SMLoc trailingTypeLoc;
|
2020-01-30 12:50:12 +01:00
|
|
|
Block *normalDest, *unwindDest;
|
|
|
|
SmallVector<Value, 4> normalOperands, unwindOperands;
|
2020-03-05 12:48:28 -08:00
|
|
|
Builder &builder = parser.getBuilder();
|
2020-01-30 12:50:12 +01:00
|
|
|
|
|
|
|
// Parse an operand list that will, in practice, contain 0 or 1 operand. In
|
|
|
|
// case of an indirect call, there will be 1 operand before `(`. In case of a
|
|
|
|
// direct call, there will be no operands and the parser will stop at the
|
|
|
|
// function identifier without complaining.
|
|
|
|
if (parser.parseOperandList(operands))
|
|
|
|
return failure();
|
|
|
|
bool isDirect = operands.empty();
|
|
|
|
|
|
|
|
// Optionally parse a function identifier.
|
|
|
|
if (isDirect && parser.parseAttribute(funcAttr, "callee", result.attributes))
|
|
|
|
return failure();
|
|
|
|
|
|
|
|
if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren) ||
|
|
|
|
parser.parseKeyword("to") ||
|
|
|
|
parser.parseSuccessorAndUseList(normalDest, normalOperands) ||
|
|
|
|
parser.parseKeyword("unwind") ||
|
|
|
|
parser.parseSuccessorAndUseList(unwindDest, unwindOperands) ||
|
|
|
|
parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
|
|
|
|
parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(funcType))
|
|
|
|
return failure();
|
|
|
|
|
|
|
|
if (isDirect) {
|
|
|
|
// Make sure types match.
|
|
|
|
if (parser.resolveOperands(operands, funcType.getInputs(),
|
|
|
|
parser.getNameLoc(), result.operands))
|
|
|
|
return failure();
|
|
|
|
result.addTypes(funcType.getResults());
|
|
|
|
} else {
|
|
|
|
// Construct the LLVM IR Dialect function type that the first operand
|
|
|
|
// should match.
|
|
|
|
if (funcType.getNumResults() > 1)
|
|
|
|
return parser.emitError(trailingTypeLoc,
|
|
|
|
"expected function with 0 or 1 result");
|
|
|
|
|
2021-01-05 16:22:53 +01:00
|
|
|
Type llvmResultType;
|
2020-01-30 12:50:12 +01:00
|
|
|
if (funcType.getNumResults() == 0) {
|
2020-12-22 11:22:56 +01:00
|
|
|
llvmResultType = LLVM::LLVMVoidType::get(builder.getContext());
|
2020-01-30 12:50:12 +01:00
|
|
|
} else {
|
2021-01-05 16:22:53 +01:00
|
|
|
llvmResultType = funcType.getResult(0);
|
|
|
|
if (!isCompatibleType(llvmResultType))
|
2020-01-30 12:50:12 +01:00
|
|
|
return parser.emitError(trailingTypeLoc,
|
|
|
|
"expected result to have LLVM type");
|
|
|
|
}
|
|
|
|
|
2021-01-05 16:22:53 +01:00
|
|
|
SmallVector<Type, 8> argTypes;
|
2020-01-30 12:50:12 +01:00
|
|
|
argTypes.reserve(funcType.getNumInputs());
|
|
|
|
for (Type ty : funcType.getInputs()) {
|
2021-01-05 16:22:53 +01:00
|
|
|
if (isCompatibleType(ty))
|
|
|
|
argTypes.push_back(ty);
|
2020-01-30 12:50:12 +01:00
|
|
|
else
|
|
|
|
return parser.emitError(trailingTypeLoc,
|
|
|
|
"expected LLVM types as inputs");
|
|
|
|
}
|
|
|
|
|
2020-12-22 11:22:56 +01:00
|
|
|
auto llvmFuncType = LLVM::LLVMFunctionType::get(llvmResultType, argTypes);
|
2020-12-22 11:22:21 +01:00
|
|
|
auto wrappedFuncType = LLVM::LLVMPointerType::get(llvmFuncType);
|
2020-01-30 12:50:12 +01:00
|
|
|
|
|
|
|
auto funcArguments = llvm::makeArrayRef(operands).drop_front();
|
|
|
|
|
|
|
|
// Make sure that the first operand (indirect callee) matches the wrapped
|
|
|
|
// LLVM IR function type, and that the types of the other call operands
|
|
|
|
// match the types of the function arguments.
|
|
|
|
if (parser.resolveOperand(operands[0], wrappedFuncType, result.operands) ||
|
|
|
|
parser.resolveOperands(funcArguments, funcType.getInputs(),
|
|
|
|
parser.getNameLoc(), result.operands))
|
|
|
|
return failure();
|
|
|
|
|
|
|
|
result.addTypes(llvmResultType);
|
|
|
|
}
|
2020-03-05 12:48:28 -08:00
|
|
|
result.addSuccessors({normalDest, unwindDest});
|
|
|
|
result.addOperands(normalOperands);
|
|
|
|
result.addOperands(unwindOperands);
|
|
|
|
|
|
|
|
result.addAttribute(
|
|
|
|
InvokeOp::getOperandSegmentSizeAttr(),
|
|
|
|
builder.getI32VectorAttr({static_cast<int32_t>(operands.size()),
|
|
|
|
static_cast<int32_t>(normalOperands.size()),
|
|
|
|
static_cast<int32_t>(unwindOperands.size())}));
|
2020-01-30 12:50:12 +01:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
///===----------------------------------------------------------------------===//
|
|
|
|
/// Verifying/Printing/Parsing for LLVM::LandingpadOp.
|
|
|
|
///===----------------------------------------------------------------------===//
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult LandingpadOp::verify() {
|
2020-01-30 12:50:12 +01:00
|
|
|
Value value;
|
2022-02-02 10:16:28 -08:00
|
|
|
if (LLVMFuncOp func = (*this)->getParentOfType<LLVMFuncOp>()) {
|
2021-10-29 13:29:48 -07:00
|
|
|
if (!func.getPersonality().hasValue())
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitError(
|
2020-03-19 13:09:31 +01:00
|
|
|
"llvm.landingpad needs to be in a function with a personality");
|
|
|
|
}
|
2020-01-30 12:50:12 +01:00
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
if (!getCleanup() && getOperands().empty())
|
|
|
|
return emitError("landingpad instruction expects at least one clause or "
|
|
|
|
"cleanup attribute");
|
2020-01-30 12:50:12 +01:00
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
for (unsigned idx = 0, ie = getNumOperands(); idx < ie; idx++) {
|
|
|
|
value = getOperand(idx);
|
2020-12-22 11:22:21 +01:00
|
|
|
bool isFilter = value.getType().isa<LLVMArrayType>();
|
2020-01-30 12:50:12 +01:00
|
|
|
if (isFilter) {
|
|
|
|
// FIXME: Verify filter clauses when arrays are appropriately handled
|
|
|
|
} else {
|
|
|
|
// catch - global addresses only.
|
|
|
|
// Bitcast ops should have global addresses as their args.
|
2020-05-09 17:52:35 -07:00
|
|
|
if (auto bcOp = value.getDefiningOp<BitcastOp>()) {
|
2021-10-24 18:36:33 -07:00
|
|
|
if (auto addrOp = bcOp.getArg().getDefiningOp<AddressOfOp>())
|
2020-01-30 12:50:12 +01:00
|
|
|
continue;
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitError("constant clauses expected").attachNote(bcOp.getLoc())
|
2020-01-30 12:50:12 +01:00
|
|
|
<< "global addresses expected as operand to "
|
|
|
|
"bitcast used in clauses for landingpad";
|
|
|
|
}
|
|
|
|
// NullOp and AddressOfOp allowed
|
2020-05-09 17:52:35 -07:00
|
|
|
if (value.getDefiningOp<NullOp>())
|
2020-01-30 12:50:12 +01:00
|
|
|
continue;
|
2020-05-09 17:52:35 -07:00
|
|
|
if (value.getDefiningOp<AddressOfOp>())
|
2020-01-30 12:50:12 +01:00
|
|
|
continue;
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitError("clause #")
|
2020-01-30 12:50:12 +01:00
|
|
|
<< idx << " is not a known constant - null, addressof, bitcast";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
void LandingpadOp::print(OpAsmPrinter &p) {
|
|
|
|
p << (getCleanup() ? " cleanup " : " ");
|
2020-01-30 12:50:12 +01:00
|
|
|
|
|
|
|
// Clauses
|
2022-02-07 17:54:04 -08:00
|
|
|
for (auto value : getOperands()) {
|
2020-01-30 12:50:12 +01:00
|
|
|
// Similar to llvm - if clause is an array type then it is filter
|
|
|
|
// clause else catch clause
|
2020-12-22 11:22:21 +01:00
|
|
|
bool isArrayTy = value.getType().isa<LLVMArrayType>();
|
2020-01-30 12:50:12 +01:00
|
|
|
p << '(' << (isArrayTy ? "filter " : "catch ") << value << " : "
|
|
|
|
<< value.getType() << ") ";
|
|
|
|
}
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
p.printOptionalAttrDict((*this)->getAttrs(), {"cleanup"});
|
2020-01-30 12:50:12 +01:00
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
p << ": " << getType();
|
2020-01-30 12:50:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <operation> ::= `llvm.landingpad` `cleanup`?
|
|
|
|
/// ((`catch` | `filter`) operand-type ssa-use)* attribute-dict?
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult LandingpadOp::parse(OpAsmParser &parser, OperationState &result) {
|
2020-01-30 12:50:12 +01:00
|
|
|
// Check for cleanup
|
|
|
|
if (succeeded(parser.parseOptionalKeyword("cleanup")))
|
|
|
|
result.addAttribute("cleanup", parser.getBuilder().getUnitAttr());
|
|
|
|
|
|
|
|
// Parse clauses with types
|
|
|
|
while (succeeded(parser.parseOptionalLParen()) &&
|
|
|
|
(succeeded(parser.parseOptionalKeyword("filter")) ||
|
|
|
|
succeeded(parser.parseOptionalKeyword("catch")))) {
|
|
|
|
OpAsmParser::OperandType operand;
|
|
|
|
Type ty;
|
|
|
|
if (parser.parseOperand(operand) || parser.parseColon() ||
|
|
|
|
parser.parseType(ty) ||
|
|
|
|
parser.resolveOperand(operand, ty, result.operands) ||
|
|
|
|
parser.parseRParen())
|
|
|
|
return failure();
|
|
|
|
}
|
|
|
|
|
|
|
|
Type type;
|
|
|
|
if (parser.parseColon() || parser.parseType(type))
|
|
|
|
return failure();
|
|
|
|
|
|
|
|
result.addTypes(type);
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
2020-10-03 03:30:21 +00:00
|
|
|
// Verifying/Printing/parsing for LLVM::CallOp.
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult CallOp::verify() {
|
|
|
|
if (getNumResults() > 1)
|
|
|
|
return emitOpError("must have 0 or 1 result");
|
2020-10-03 03:30:21 +00:00
|
|
|
|
|
|
|
// Type for the callee, we'll get it differently depending if it is a direct
|
|
|
|
// or indirect call.
|
2021-01-05 16:22:53 +01:00
|
|
|
Type fnType;
|
2020-10-03 03:30:21 +00:00
|
|
|
|
|
|
|
bool isIndirect = false;
|
|
|
|
|
|
|
|
// If this is an indirect call, the callee attribute is missing.
|
2022-02-02 10:16:28 -08:00
|
|
|
FlatSymbolRefAttr calleeName = getCalleeAttr();
|
2020-10-03 03:30:21 +00:00
|
|
|
if (!calleeName) {
|
|
|
|
isIndirect = true;
|
2022-02-02 10:16:28 -08:00
|
|
|
if (!getNumOperands())
|
|
|
|
return emitOpError(
|
2020-10-03 03:30:21 +00:00
|
|
|
"must have either a `callee` attribute or at least an operand");
|
2022-02-02 10:16:28 -08:00
|
|
|
auto ptrType = getOperand(0).getType().dyn_cast<LLVMPointerType>();
|
2020-10-03 03:30:21 +00:00
|
|
|
if (!ptrType)
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError("indirect call expects a pointer as callee: ")
|
2021-01-05 16:22:53 +01:00
|
|
|
<< ptrType;
|
2020-10-03 03:30:21 +00:00
|
|
|
fnType = ptrType.getElementType();
|
|
|
|
} else {
|
2021-08-29 14:22:24 -07:00
|
|
|
Operation *callee =
|
2022-02-02 10:16:28 -08:00
|
|
|
SymbolTable::lookupNearestSymbolFrom(*this, calleeName.getAttr());
|
2020-10-03 03:30:21 +00:00
|
|
|
if (!callee)
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError()
|
2021-08-29 14:22:24 -07:00
|
|
|
<< "'" << calleeName.getValue()
|
2020-10-03 03:30:21 +00:00
|
|
|
<< "' does not reference a symbol in the current scope";
|
|
|
|
auto fn = dyn_cast<LLVMFuncOp>(callee);
|
|
|
|
if (!fn)
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError() << "'" << calleeName.getValue()
|
|
|
|
<< "' does not reference a valid LLVM function";
|
2020-10-03 03:30:21 +00:00
|
|
|
|
|
|
|
fnType = fn.getType();
|
|
|
|
}
|
2020-12-22 11:22:21 +01:00
|
|
|
|
|
|
|
LLVMFunctionType funcType = fnType.dyn_cast<LLVMFunctionType>();
|
|
|
|
if (!funcType)
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError("callee does not have a functional type: ") << fnType;
|
2020-10-03 03:30:21 +00:00
|
|
|
|
|
|
|
// Verify that the operand and result types match the callee.
|
|
|
|
|
2020-12-22 11:22:21 +01:00
|
|
|
if (!funcType.isVarArg() &&
|
2022-02-02 10:16:28 -08:00
|
|
|
funcType.getNumParams() != (getNumOperands() - isIndirect))
|
|
|
|
return emitOpError() << "incorrect number of operands ("
|
|
|
|
<< (getNumOperands() - isIndirect)
|
|
|
|
<< ") for callee (expecting: "
|
|
|
|
<< funcType.getNumParams() << ")";
|
|
|
|
|
|
|
|
if (funcType.getNumParams() > (getNumOperands() - isIndirect))
|
|
|
|
return emitOpError() << "incorrect number of operands ("
|
|
|
|
<< (getNumOperands() - isIndirect)
|
|
|
|
<< ") for varargs callee (expecting at least: "
|
|
|
|
<< funcType.getNumParams() << ")";
|
2020-10-03 03:30:21 +00:00
|
|
|
|
2020-12-22 11:22:21 +01:00
|
|
|
for (unsigned i = 0, e = funcType.getNumParams(); i != e; ++i)
|
2022-02-02 10:16:28 -08:00
|
|
|
if (getOperand(i + isIndirect).getType() != funcType.getParamType(i))
|
|
|
|
return emitOpError() << "operand type mismatch for operand " << i << ": "
|
|
|
|
<< getOperand(i + isIndirect).getType()
|
|
|
|
<< " != " << funcType.getParamType(i);
|
2020-10-03 03:30:21 +00:00
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
if (getNumResults() == 0 &&
|
2021-07-28 10:23:06 +02:00
|
|
|
!funcType.getReturnType().isa<LLVM::LLVMVoidType>())
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError() << "expected function call to produce a value";
|
2021-07-28 10:23:06 +02:00
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
if (getNumResults() != 0 &&
|
2021-07-28 10:23:06 +02:00
|
|
|
funcType.getReturnType().isa<LLVM::LLVMVoidType>())
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError()
|
2021-07-28 10:23:06 +02:00
|
|
|
<< "calling function with void result must not produce values";
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
if (getNumResults() > 1)
|
|
|
|
return emitOpError()
|
2021-07-28 10:23:06 +02:00
|
|
|
<< "expected LLVM function call to produce 0 or 1 result";
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
if (getNumResults() && getResult(0).getType() != funcType.getReturnType())
|
|
|
|
return emitOpError() << "result type mismatch: " << getResult(0).getType()
|
|
|
|
<< " != " << funcType.getReturnType();
|
2020-10-03 03:30:21 +00:00
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
void CallOp::print(OpAsmPrinter &p) {
|
|
|
|
auto callee = getCallee();
|
2019-04-02 15:33:54 -07:00
|
|
|
bool isDirect = callee.hasValue();
|
|
|
|
|
|
|
|
// Print the direct callee if present as a function attribute, or an indirect
|
|
|
|
// callee (first operand) otherwise.
|
2021-08-28 03:03:15 +00:00
|
|
|
p << ' ';
|
2019-04-02 15:33:54 -07:00
|
|
|
if (isDirect)
|
2019-10-08 17:44:39 -07:00
|
|
|
p.printSymbolName(callee.getValue());
|
2019-04-02 15:33:54 -07:00
|
|
|
else
|
2022-02-07 17:54:04 -08:00
|
|
|
p << getOperand(0);
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
auto args = getOperands().drop_front(isDirect ? 0 : 1);
|
2020-08-04 11:46:26 -07:00
|
|
|
p << '(' << args << ')';
|
2022-02-07 17:54:04 -08:00
|
|
|
p.printOptionalAttrDict(processFMFAttr((*this)->getAttrs()), {"callee"});
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-05-22 13:41:23 -07:00
|
|
|
// Reconstruct the function MLIR function type from operand and result types.
|
2022-02-07 17:54:04 -08:00
|
|
|
p << " : ";
|
|
|
|
p.printFunctionalType(args.getTypes(), getResultTypes());
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.call` (function-id | ssa-use) `(` ssa-use-list `)`
|
|
|
|
// attribute-dict? `:` function-type
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult CallOp::parse(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
SmallVector<OpAsmParser::OperandType, 8> operands;
|
|
|
|
Type type;
|
2019-07-11 11:41:04 -07:00
|
|
|
SymbolRefAttr funcAttr;
|
2022-01-26 15:49:53 -08:00
|
|
|
SMLoc trailingTypeLoc;
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
// Parse an operand list that will, in practice, contain 0 or 1 operand. In
|
|
|
|
// case of an indirect call, there will be 1 operand before `(`. In case of a
|
|
|
|
// direct call, there will be no operands and the parser will stop at the
|
|
|
|
// function identifier without complaining.
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperandList(operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
bool isDirect = operands.empty();
|
|
|
|
|
|
|
|
// Optionally parse a function identifier.
|
|
|
|
if (isDirect)
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
if (parser.parseAttribute(funcAttr, "callee", result.attributes))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren) ||
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
auto funcType = type.dyn_cast<FunctionType>();
|
|
|
|
if (!funcType)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(trailingTypeLoc, "expected function type");
|
2021-07-28 10:23:06 +02:00
|
|
|
if (funcType.getNumResults() > 1)
|
|
|
|
return parser.emitError(trailingTypeLoc,
|
|
|
|
"expected function with 0 or 1 result");
|
2019-04-02 15:33:54 -07:00
|
|
|
if (isDirect) {
|
|
|
|
// Make sure types match.
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.resolveOperands(operands, funcType.getInputs(),
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.getNameLoc(), result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2021-07-28 10:23:06 +02:00
|
|
|
if (funcType.getNumResults() != 0 &&
|
|
|
|
!funcType.getResult(0).isa<LLVM::LLVMVoidType>())
|
|
|
|
result.addTypes(funcType.getResults());
|
2019-04-02 15:33:54 -07:00
|
|
|
} else {
|
2019-09-20 11:36:49 -07:00
|
|
|
Builder &builder = parser.getBuilder();
|
2021-01-05 16:22:53 +01:00
|
|
|
Type llvmResultType;
|
2019-04-02 15:33:54 -07:00
|
|
|
if (funcType.getNumResults() == 0) {
|
2020-12-22 11:22:56 +01:00
|
|
|
llvmResultType = LLVM::LLVMVoidType::get(builder.getContext());
|
2019-04-02 15:33:54 -07:00
|
|
|
} else {
|
2021-01-05 16:22:53 +01:00
|
|
|
llvmResultType = funcType.getResult(0);
|
|
|
|
if (!isCompatibleType(llvmResultType))
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(trailingTypeLoc,
|
|
|
|
"expected result to have LLVM type");
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2021-01-05 16:22:53 +01:00
|
|
|
SmallVector<Type, 8> argTypes;
|
2019-04-02 15:33:54 -07:00
|
|
|
argTypes.reserve(funcType.getNumInputs());
|
|
|
|
for (int i = 0, e = funcType.getNumInputs(); i < e; ++i) {
|
2021-01-05 16:22:53 +01:00
|
|
|
auto argType = funcType.getInput(i);
|
|
|
|
if (!isCompatibleType(argType))
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(trailingTypeLoc,
|
|
|
|
"expected LLVM types as inputs");
|
2019-05-22 14:56:07 -07:00
|
|
|
argTypes.push_back(argType);
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
2020-12-22 11:22:56 +01:00
|
|
|
auto llvmFuncType = LLVM::LLVMFunctionType::get(llvmResultType, argTypes);
|
2020-12-22 11:22:21 +01:00
|
|
|
auto wrappedFuncType = LLVM::LLVMPointerType::get(llvmFuncType);
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
auto funcArguments =
|
|
|
|
ArrayRef<OpAsmParser::OperandType>(operands).drop_front();
|
|
|
|
|
|
|
|
// Make sure that the first operand (indirect callee) matches the wrapped
|
|
|
|
// LLVM IR function type, and that the types of the other call operands
|
|
|
|
// match the types of the function arguments.
|
2019-09-20 19:47:05 -07:00
|
|
|
if (parser.resolveOperand(operands[0], wrappedFuncType, result.operands) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.resolveOperands(funcArguments, funcType.getInputs(),
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.getNameLoc(), result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2021-07-28 10:23:06 +02:00
|
|
|
if (!llvmResultType.isa<LLVM::LLVMVoidType>())
|
|
|
|
result.addTypes(llvmResultType);
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2019-08-09 05:24:47 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::ExtractElementOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Expects vector to be of wrapped LLVM vector type and position to be of
|
|
|
|
// wrapped LLVM i32 type.
|
2020-04-23 16:02:46 +02:00
|
|
|
void LLVM::ExtractElementOp::build(OpBuilder &b, OperationState &result,
|
2019-12-23 14:45:01 -08:00
|
|
|
Value vector, Value position,
|
2019-08-09 05:24:47 -07:00
|
|
|
ArrayRef<NamedAttribute> attrs) {
|
[mlir] use built-in vector types instead of LLVM dialect types when possible
Continue the convergence between LLVM dialect and built-in types by using the
built-in vector type whenever possible, that is for fixed vectors of built-in
integers and built-in floats. LLVM dialect vector type is still in use for
pointers, less frequent floating point types that do not have a built-in
equivalent, and scalable vectors. However, the top-level `LLVMVectorType` class
has been removed in favor of free functions capable of inspecting both built-in
and LLVM dialect vector types: `LLVM::getVectorElementType`,
`LLVM::getNumVectorElements` and `LLVM::getFixedVectorType`. Additional work is
necessary to design an implemented the extensions to built-in types so as to
remove the `LLVMFixedVectorType` entirely.
Note that the default output format for the built-in vectors does not have
whitespace around the `x` separator, e.g., `vector<4xf32>` as opposed to the
LLVM dialect vector type format that does, e.g., `!llvm.vec<4 x fp128>`. This
required changing the FileCheck patterns in several tests.
Reviewed By: mehdi_amini, silvas
Differential Revision: https://reviews.llvm.org/D94405
2021-01-11 13:58:05 +01:00
|
|
|
auto vectorType = vector.getType();
|
|
|
|
auto llvmType = LLVM::getVectorElementType(vectorType);
|
2019-08-09 05:24:47 -07:00
|
|
|
build(b, result, llvmType, vector, position);
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addAttributes(attrs);
|
2019-08-09 05:24:47 -07:00
|
|
|
}
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
void ExtractElementOp::print(OpAsmPrinter &p) {
|
|
|
|
p << ' ' << getVector() << "[" << getPosition() << " : "
|
|
|
|
<< getPosition().getType() << "]";
|
|
|
|
p.printOptionalAttrDict((*this)->getAttrs());
|
|
|
|
p << " : " << getVector().getType();
|
2019-08-09 05:24:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.extractelement` ssa-use `, ` ssa-use
|
|
|
|
// attribute-dict? `:` type
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult ExtractElementOp::parse(OpAsmParser &parser,
|
|
|
|
OperationState &result) {
|
2022-01-26 15:49:53 -08:00
|
|
|
SMLoc loc;
|
2019-08-09 05:24:47 -07:00
|
|
|
OpAsmParser::OperandType vector, position;
|
2019-11-25 14:44:20 -08:00
|
|
|
Type type, positionType;
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.getCurrentLocation(&loc) || parser.parseOperand(vector) ||
|
2019-11-25 14:44:20 -08:00
|
|
|
parser.parseLSquare() || parser.parseOperand(position) ||
|
|
|
|
parser.parseColonType(positionType) || parser.parseRSquare() ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOptionalAttrDict(result.attributes) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.parseColonType(type) ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.resolveOperand(vector, type, result.operands) ||
|
2019-11-25 14:44:20 -08:00
|
|
|
parser.resolveOperand(position, positionType, result.operands))
|
2019-08-09 05:24:47 -07:00
|
|
|
return failure();
|
[mlir] use built-in vector types instead of LLVM dialect types when possible
Continue the convergence between LLVM dialect and built-in types by using the
built-in vector type whenever possible, that is for fixed vectors of built-in
integers and built-in floats. LLVM dialect vector type is still in use for
pointers, less frequent floating point types that do not have a built-in
equivalent, and scalable vectors. However, the top-level `LLVMVectorType` class
has been removed in favor of free functions capable of inspecting both built-in
and LLVM dialect vector types: `LLVM::getVectorElementType`,
`LLVM::getNumVectorElements` and `LLVM::getFixedVectorType`. Additional work is
necessary to design an implemented the extensions to built-in types so as to
remove the `LLVMFixedVectorType` entirely.
Note that the default output format for the built-in vectors does not have
whitespace around the `x` separator, e.g., `vector<4xf32>` as opposed to the
LLVM dialect vector type format that does, e.g., `!llvm.vec<4 x fp128>`. This
required changing the FileCheck patterns in several tests.
Reviewed By: mehdi_amini, silvas
Differential Revision: https://reviews.llvm.org/D94405
2021-01-11 13:58:05 +01:00
|
|
|
if (!LLVM::isCompatibleVectorType(type))
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(
|
[mlir] use built-in vector types instead of LLVM dialect types when possible
Continue the convergence between LLVM dialect and built-in types by using the
built-in vector type whenever possible, that is for fixed vectors of built-in
integers and built-in floats. LLVM dialect vector type is still in use for
pointers, less frequent floating point types that do not have a built-in
equivalent, and scalable vectors. However, the top-level `LLVMVectorType` class
has been removed in favor of free functions capable of inspecting both built-in
and LLVM dialect vector types: `LLVM::getVectorElementType`,
`LLVM::getNumVectorElements` and `LLVM::getFixedVectorType`. Additional work is
necessary to design an implemented the extensions to built-in types so as to
remove the `LLVMFixedVectorType` entirely.
Note that the default output format for the built-in vectors does not have
whitespace around the `x` separator, e.g., `vector<4xf32>` as opposed to the
LLVM dialect vector type format that does, e.g., `!llvm.vec<4 x fp128>`. This
required changing the FileCheck patterns in several tests.
Reviewed By: mehdi_amini, silvas
Differential Revision: https://reviews.llvm.org/D94405
2021-01-11 13:58:05 +01:00
|
|
|
loc, "expected LLVM dialect-compatible vector type for operand #1");
|
|
|
|
result.addTypes(LLVM::getVectorElementType(type));
|
2019-08-09 05:24:47 -07:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult ExtractElementOp::verify() {
|
|
|
|
Type vectorType = getVector().getType();
|
2021-07-21 22:28:45 +00:00
|
|
|
if (!LLVM::isCompatibleVectorType(vectorType))
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError("expected LLVM dialect-compatible vector type for "
|
|
|
|
"operand #1, got")
|
2021-07-21 22:28:45 +00:00
|
|
|
<< vectorType;
|
|
|
|
Type valueType = LLVM::getVectorElementType(vectorType);
|
2022-02-02 10:16:28 -08:00
|
|
|
if (valueType != getRes().getType())
|
|
|
|
return emitOpError() << "Type mismatch: extracting from " << vectorType
|
|
|
|
<< " should produce " << valueType
|
|
|
|
<< " but this op returns " << getRes().getType();
|
2021-07-21 22:28:45 +00:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::ExtractValueOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
void ExtractValueOp::print(OpAsmPrinter &p) {
|
|
|
|
p << ' ' << getContainer() << getPosition();
|
|
|
|
p.printOptionalAttrDict((*this)->getAttrs(), {"position"});
|
|
|
|
p << " : " << getContainer().getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Extract the type at `position` in the wrapped LLVM IR aggregate type
|
|
|
|
// `containerType`. Position is an integer array attribute where each value
|
|
|
|
// is a zero-based position of the element in the aggregate type. Return the
|
|
|
|
// resulting type wrapped in MLIR, or nullptr on error.
|
2021-01-05 16:22:53 +01:00
|
|
|
static Type getInsertExtractValueElementType(OpAsmParser &parser,
|
|
|
|
Type containerType,
|
|
|
|
ArrayAttr positionAttr,
|
2022-01-26 15:49:53 -08:00
|
|
|
SMLoc attributeLoc,
|
|
|
|
SMLoc typeLoc) {
|
2021-01-05 16:22:53 +01:00
|
|
|
Type llvmType = containerType;
|
|
|
|
if (!isCompatibleType(containerType))
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(typeLoc, "expected LLVM IR Dialect type"), nullptr;
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
// Infer the element type from the structure type: iteratively step inside the
|
|
|
|
// type by taking the element type, indexed by the position attribute for
|
2019-10-20 00:11:03 -07:00
|
|
|
// structures. Check the position index before accessing, it is supposed to
|
|
|
|
// be in bounds.
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
for (Attribute subAttr : positionAttr) {
|
2019-04-02 15:33:54 -07:00
|
|
|
auto positionElementAttr = subAttr.dyn_cast<IntegerAttr>();
|
|
|
|
if (!positionElementAttr)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(attributeLoc,
|
|
|
|
"expected an array of integer literals"),
|
2019-04-02 15:33:54 -07:00
|
|
|
nullptr;
|
|
|
|
int position = positionElementAttr.getInt();
|
2020-12-22 11:22:21 +01:00
|
|
|
if (auto arrayType = llvmType.dyn_cast<LLVMArrayType>()) {
|
|
|
|
if (position < 0 ||
|
|
|
|
static_cast<unsigned>(position) >= arrayType.getNumElements())
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(attributeLoc, "position out of bounds"),
|
2019-04-02 15:33:54 -07:00
|
|
|
nullptr;
|
2020-12-22 11:22:21 +01:00
|
|
|
llvmType = arrayType.getElementType();
|
|
|
|
} else if (auto structType = llvmType.dyn_cast<LLVMStructType>()) {
|
|
|
|
if (position < 0 ||
|
|
|
|
static_cast<unsigned>(position) >= structType.getBody().size())
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(attributeLoc, "position out of bounds"),
|
2019-04-02 15:33:54 -07:00
|
|
|
nullptr;
|
2020-12-22 11:22:21 +01:00
|
|
|
llvmType = structType.getBody()[position];
|
2019-04-02 15:33:54 -07:00
|
|
|
} else {
|
2020-12-22 11:22:21 +01:00
|
|
|
return parser.emitError(typeLoc, "expected LLVM IR structure/array type"),
|
2019-04-02 15:33:54 -07:00
|
|
|
nullptr;
|
|
|
|
}
|
|
|
|
}
|
2020-12-22 11:22:21 +01:00
|
|
|
return llvmType;
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2021-07-21 22:28:45 +00:00
|
|
|
// Extract the type at `position` in the wrapped LLVM IR aggregate type
|
|
|
|
// `containerType`. Returns null on failure.
|
|
|
|
static Type getInsertExtractValueElementType(Type containerType,
|
|
|
|
ArrayAttr positionAttr,
|
|
|
|
Operation *op) {
|
|
|
|
Type llvmType = containerType;
|
|
|
|
if (!isCompatibleType(containerType)) {
|
|
|
|
op->emitError("expected LLVM IR Dialect type, got ") << containerType;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Infer the element type from the structure type: iteratively step inside the
|
|
|
|
// type by taking the element type, indexed by the position attribute for
|
|
|
|
// structures. Check the position index before accessing, it is supposed to
|
|
|
|
// be in bounds.
|
|
|
|
for (Attribute subAttr : positionAttr) {
|
|
|
|
auto positionElementAttr = subAttr.dyn_cast<IntegerAttr>();
|
|
|
|
if (!positionElementAttr) {
|
|
|
|
op->emitOpError("expected an array of integer literals, got: ")
|
|
|
|
<< subAttr;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
int position = positionElementAttr.getInt();
|
|
|
|
if (auto arrayType = llvmType.dyn_cast<LLVMArrayType>()) {
|
|
|
|
if (position < 0 ||
|
|
|
|
static_cast<unsigned>(position) >= arrayType.getNumElements()) {
|
|
|
|
op->emitOpError("position out of bounds: ") << position;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
llvmType = arrayType.getElementType();
|
|
|
|
} else if (auto structType = llvmType.dyn_cast<LLVMStructType>()) {
|
|
|
|
if (position < 0 ||
|
|
|
|
static_cast<unsigned>(position) >= structType.getBody().size()) {
|
|
|
|
op->emitOpError("position out of bounds") << position;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
llvmType = structType.getBody()[position];
|
|
|
|
} else {
|
|
|
|
op->emitOpError("expected LLVM IR structure/array type, got: ")
|
|
|
|
<< llvmType;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return llvmType;
|
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
// <operation> ::= `llvm.extractvalue` ssa-use
|
|
|
|
// `[` integer-literal (`,` integer-literal)* `]`
|
|
|
|
// attribute-dict? `:` type
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult ExtractValueOp::parse(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
OpAsmParser::OperandType container;
|
|
|
|
Type containerType;
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
ArrayAttr positionAttr;
|
2022-01-26 15:49:53 -08:00
|
|
|
SMLoc attributeLoc, trailingTypeLoc;
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperand(container) ||
|
|
|
|
parser.getCurrentLocation(&attributeLoc) ||
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
parser.parseAttribute(positionAttr, "position", result.attributes) ||
|
|
|
|
parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.getCurrentLocation(&trailingTypeLoc) ||
|
|
|
|
parser.parseType(containerType) ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.resolveOperand(container, containerType, result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
auto elementType = getInsertExtractValueElementType(
|
|
|
|
parser, containerType, positionAttr, attributeLoc, trailingTypeLoc);
|
|
|
|
if (!elementType)
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes(elementType);
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2021-06-23 09:03:08 +00:00
|
|
|
OpFoldResult LLVM::ExtractValueOp::fold(ArrayRef<Attribute> operands) {
|
2021-10-24 18:36:33 -07:00
|
|
|
auto insertValueOp = getContainer().getDefiningOp<InsertValueOp>();
|
2022-03-03 12:31:48 -05:00
|
|
|
OpFoldResult result = {};
|
2021-06-23 09:03:08 +00:00
|
|
|
while (insertValueOp) {
|
2021-10-29 13:29:48 -07:00
|
|
|
if (getPosition() == insertValueOp.getPosition())
|
|
|
|
return insertValueOp.getValue();
|
2021-11-16 10:06:15 +00:00
|
|
|
unsigned min =
|
|
|
|
std::min(getPosition().size(), insertValueOp.getPosition().size());
|
|
|
|
// If one is fully prefix of the other, stop propagating back as it will
|
|
|
|
// miss dependencies. For instance, %3 should not fold to %f0 in the
|
|
|
|
// following example:
|
|
|
|
// ```
|
|
|
|
// %1 = llvm.insertvalue %f0, %0[0, 0] :
|
|
|
|
// !llvm.array<4 x !llvm.array<4xf32>>
|
|
|
|
// %2 = llvm.insertvalue %arr, %1[0] :
|
|
|
|
// !llvm.array<4 x !llvm.array<4xf32>>
|
|
|
|
// %3 = llvm.extractvalue %2[0, 0] : !llvm.array<4 x !llvm.array<4xf32>>
|
|
|
|
// ```
|
|
|
|
if (getPosition().getValue().take_front(min) ==
|
|
|
|
insertValueOp.getPosition().getValue().take_front(min))
|
2022-03-03 12:31:48 -05:00
|
|
|
return result;
|
|
|
|
|
|
|
|
// If neither a prefix, nor the exact position, we can extract out of the
|
|
|
|
// value being inserted into. Moreover, we can try again if that operand
|
|
|
|
// is itself an insertvalue expression.
|
|
|
|
getContainerMutable().assign(insertValueOp.getContainer());
|
|
|
|
result = getResult();
|
2021-10-29 13:29:48 -07:00
|
|
|
insertValueOp = insertValueOp.getContainer().getDefiningOp<InsertValueOp>();
|
2021-06-23 09:03:08 +00:00
|
|
|
}
|
2022-03-03 12:31:48 -05:00
|
|
|
return result;
|
2021-06-23 09:03:08 +00:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult ExtractValueOp::verify() {
|
|
|
|
Type valueType = getInsertExtractValueElementType(getContainer().getType(),
|
|
|
|
getPositionAttr(), *this);
|
2021-07-21 22:28:45 +00:00
|
|
|
if (!valueType)
|
|
|
|
return failure();
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
if (getRes().getType() != valueType)
|
|
|
|
return emitOpError() << "Type mismatch: extracting from "
|
|
|
|
<< getContainer().getType() << " should produce "
|
|
|
|
<< valueType << " but this op returns "
|
|
|
|
<< getRes().getType();
|
2021-07-21 22:28:45 +00:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-08-09 05:24:47 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::InsertElementOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
void InsertElementOp::print(OpAsmPrinter &p) {
|
|
|
|
p << ' ' << getValue() << ", " << getVector() << "[" << getPosition() << " : "
|
|
|
|
<< getPosition().getType() << "]";
|
|
|
|
p.printOptionalAttrDict((*this)->getAttrs());
|
|
|
|
p << " : " << getVector().getType();
|
2019-08-09 05:24:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.insertelement` ssa-use `,` ssa-use `,` ssa-use
|
|
|
|
// attribute-dict? `:` type
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult InsertElementOp::parse(OpAsmParser &parser,
|
|
|
|
OperationState &result) {
|
2022-01-26 15:49:53 -08:00
|
|
|
SMLoc loc;
|
2019-08-09 05:24:47 -07:00
|
|
|
OpAsmParser::OperandType vector, value, position;
|
2019-11-25 14:44:20 -08:00
|
|
|
Type vectorType, positionType;
|
|
|
|
if (parser.getCurrentLocation(&loc) || parser.parseOperand(value) ||
|
|
|
|
parser.parseComma() || parser.parseOperand(vector) ||
|
|
|
|
parser.parseLSquare() || parser.parseOperand(position) ||
|
|
|
|
parser.parseColonType(positionType) || parser.parseRSquare() ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOptionalAttrDict(result.attributes) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.parseColonType(vectorType))
|
2019-08-09 05:24:47 -07:00
|
|
|
return failure();
|
|
|
|
|
[mlir] use built-in vector types instead of LLVM dialect types when possible
Continue the convergence between LLVM dialect and built-in types by using the
built-in vector type whenever possible, that is for fixed vectors of built-in
integers and built-in floats. LLVM dialect vector type is still in use for
pointers, less frequent floating point types that do not have a built-in
equivalent, and scalable vectors. However, the top-level `LLVMVectorType` class
has been removed in favor of free functions capable of inspecting both built-in
and LLVM dialect vector types: `LLVM::getVectorElementType`,
`LLVM::getNumVectorElements` and `LLVM::getFixedVectorType`. Additional work is
necessary to design an implemented the extensions to built-in types so as to
remove the `LLVMFixedVectorType` entirely.
Note that the default output format for the built-in vectors does not have
whitespace around the `x` separator, e.g., `vector<4xf32>` as opposed to the
LLVM dialect vector type format that does, e.g., `!llvm.vec<4 x fp128>`. This
required changing the FileCheck patterns in several tests.
Reviewed By: mehdi_amini, silvas
Differential Revision: https://reviews.llvm.org/D94405
2021-01-11 13:58:05 +01:00
|
|
|
if (!LLVM::isCompatibleVectorType(vectorType))
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(
|
[mlir] use built-in vector types instead of LLVM dialect types when possible
Continue the convergence between LLVM dialect and built-in types by using the
built-in vector type whenever possible, that is for fixed vectors of built-in
integers and built-in floats. LLVM dialect vector type is still in use for
pointers, less frequent floating point types that do not have a built-in
equivalent, and scalable vectors. However, the top-level `LLVMVectorType` class
has been removed in favor of free functions capable of inspecting both built-in
and LLVM dialect vector types: `LLVM::getVectorElementType`,
`LLVM::getNumVectorElements` and `LLVM::getFixedVectorType`. Additional work is
necessary to design an implemented the extensions to built-in types so as to
remove the `LLVMFixedVectorType` entirely.
Note that the default output format for the built-in vectors does not have
whitespace around the `x` separator, e.g., `vector<4xf32>` as opposed to the
LLVM dialect vector type format that does, e.g., `!llvm.vec<4 x fp128>`. This
required changing the FileCheck patterns in several tests.
Reviewed By: mehdi_amini, silvas
Differential Revision: https://reviews.llvm.org/D94405
2021-01-11 13:58:05 +01:00
|
|
|
loc, "expected LLVM dialect-compatible vector type for operand #1");
|
|
|
|
Type valueType = LLVM::getVectorElementType(vectorType);
|
2019-08-09 05:24:47 -07:00
|
|
|
if (!valueType)
|
|
|
|
return failure();
|
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
if (parser.resolveOperand(vector, vectorType, result.operands) ||
|
|
|
|
parser.resolveOperand(value, valueType, result.operands) ||
|
2019-11-25 14:44:20 -08:00
|
|
|
parser.resolveOperand(position, positionType, result.operands))
|
2019-08-09 05:24:47 -07:00
|
|
|
return failure();
|
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes(vectorType);
|
2019-08-09 05:24:47 -07:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult InsertElementOp::verify() {
|
|
|
|
Type valueType = LLVM::getVectorElementType(getVector().getType());
|
|
|
|
if (valueType != getValue().getType())
|
|
|
|
return emitOpError() << "Type mismatch: cannot insert "
|
|
|
|
<< getValue().getType() << " into "
|
|
|
|
<< getVector().getType();
|
2021-07-21 22:28:45 +00:00
|
|
|
return success();
|
|
|
|
}
|
2022-02-02 10:16:28 -08:00
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::InsertValueOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
void InsertValueOp::print(OpAsmPrinter &p) {
|
|
|
|
p << ' ' << getValue() << ", " << getContainer() << getPosition();
|
|
|
|
p.printOptionalAttrDict((*this)->getAttrs(), {"position"});
|
|
|
|
p << " : " << getContainer().getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.insertvaluevalue` ssa-use `,` ssa-use
|
|
|
|
// `[` integer-literal (`,` integer-literal)* `]`
|
|
|
|
// attribute-dict? `:` type
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult InsertValueOp::parse(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
OpAsmParser::OperandType container, value;
|
|
|
|
Type containerType;
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
ArrayAttr positionAttr;
|
2022-01-26 15:49:53 -08:00
|
|
|
SMLoc attributeLoc, trailingTypeLoc;
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperand(value) || parser.parseComma() ||
|
|
|
|
parser.parseOperand(container) ||
|
|
|
|
parser.getCurrentLocation(&attributeLoc) ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.parseAttribute(positionAttr, "position", result.attributes) ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
|
|
|
|
parser.getCurrentLocation(&trailingTypeLoc) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.parseType(containerType))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
|
|
|
auto valueType = getInsertExtractValueElementType(
|
|
|
|
parser, containerType, positionAttr, attributeLoc, trailingTypeLoc);
|
|
|
|
if (!valueType)
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
if (parser.resolveOperand(container, containerType, result.operands) ||
|
|
|
|
parser.resolveOperand(value, valueType, result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes(containerType);
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult InsertValueOp::verify() {
|
|
|
|
Type valueType = getInsertExtractValueElementType(getContainer().getType(),
|
|
|
|
getPositionAttr(), *this);
|
2021-07-21 22:28:45 +00:00
|
|
|
if (!valueType)
|
|
|
|
return failure();
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
if (getValue().getType() != valueType)
|
|
|
|
return emitOpError() << "Type mismatch: cannot insert "
|
|
|
|
<< getValue().getType() << " into "
|
|
|
|
<< getContainer().getType();
|
2021-07-21 22:28:45 +00:00
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
2021-02-16 17:36:20 +01:00
|
|
|
// Printing, parsing and verification for LLVM::ReturnOp.
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult ReturnOp::verify() {
|
|
|
|
if (getNumOperands() > 1)
|
|
|
|
return emitOpError("expected at most 1 operand");
|
2021-02-16 17:36:20 +01:00
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
if (auto parent = (*this)->getParentOfType<LLVMFuncOp>()) {
|
2021-02-16 17:36:20 +01:00
|
|
|
Type expectedType = parent.getType().getReturnType();
|
|
|
|
if (expectedType.isa<LLVMVoidType>()) {
|
2022-02-02 10:16:28 -08:00
|
|
|
if (getNumOperands() == 0)
|
2021-02-16 17:36:20 +01:00
|
|
|
return success();
|
2022-02-02 10:16:28 -08:00
|
|
|
InFlightDiagnostic diag = emitOpError("expected no operands");
|
2021-02-16 17:36:20 +01:00
|
|
|
diag.attachNote(parent->getLoc()) << "when returning from function";
|
|
|
|
return diag;
|
|
|
|
}
|
2022-02-02 10:16:28 -08:00
|
|
|
if (getNumOperands() == 0) {
|
2021-02-16 17:36:20 +01:00
|
|
|
if (expectedType.isa<LLVMVoidType>())
|
|
|
|
return success();
|
2022-02-02 10:16:28 -08:00
|
|
|
InFlightDiagnostic diag = emitOpError("expected 1 operand");
|
2021-02-16 17:36:20 +01:00
|
|
|
diag.attachNote(parent->getLoc()) << "when returning from function";
|
|
|
|
return diag;
|
|
|
|
}
|
2022-02-02 10:16:28 -08:00
|
|
|
if (expectedType != getOperand(0).getType()) {
|
|
|
|
InFlightDiagnostic diag = emitOpError("mismatching result types");
|
2021-02-16 17:36:20 +01:00
|
|
|
diag.attachNote(parent->getLoc()) << "when returning from function";
|
|
|
|
return diag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ResumeOp
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
LogicalResult ResumeOp::verify() {
|
|
|
|
if (!getValue().getDefiningOp<LandingpadOp>())
|
|
|
|
return emitOpError("expects landingpad value as operand");
|
|
|
|
// No check for personality of function - landingpad op verifies it.
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
2020-01-30 11:32:04 -08:00
|
|
|
// Verifier for LLVM::AddressOfOp.
|
2019-08-12 06:10:29 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-06-29 12:16:23 +02:00
|
|
|
template <typename OpTy>
|
|
|
|
static OpTy lookupSymbolInModule(Operation *parent, StringRef name) {
|
|
|
|
Operation *module = parent;
|
2019-12-16 01:35:03 -08:00
|
|
|
while (module && !satisfiesLLVMModule(module))
|
|
|
|
module = module->getParentOp();
|
2019-08-12 06:10:29 -07:00
|
|
|
assert(module && "unexpected operation outside of a module");
|
2020-06-29 12:16:23 +02:00
|
|
|
return dyn_cast_or_null<OpTy>(
|
|
|
|
mlir::SymbolTable::lookupSymbolIn(module, name));
|
|
|
|
}
|
|
|
|
|
|
|
|
GlobalOp AddressOfOp::getGlobal() {
|
2020-12-09 11:50:18 +01:00
|
|
|
return lookupSymbolInModule<LLVM::GlobalOp>((*this)->getParentOp(),
|
2021-10-24 18:36:33 -07:00
|
|
|
getGlobalName());
|
2020-06-29 12:16:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
LLVMFuncOp AddressOfOp::getFunction() {
|
2020-12-09 11:50:18 +01:00
|
|
|
return lookupSymbolInModule<LLVM::LLVMFuncOp>((*this)->getParentOp(),
|
2021-10-24 18:36:33 -07:00
|
|
|
getGlobalName());
|
2019-08-12 06:10:29 -07:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult AddressOfOp::verify() {
|
|
|
|
auto global = getGlobal();
|
|
|
|
auto function = getFunction();
|
2020-06-29 12:16:23 +02:00
|
|
|
if (!global && !function)
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError(
|
2020-06-29 12:16:23 +02:00
|
|
|
"must reference a global defined by 'llvm.mlir.global' or 'llvm.func'");
|
|
|
|
|
2020-12-22 11:22:21 +01:00
|
|
|
if (global &&
|
2021-10-24 18:36:33 -07:00
|
|
|
LLVM::LLVMPointerType::get(global.getType(), global.getAddrSpace()) !=
|
2022-02-02 10:16:28 -08:00
|
|
|
getResult().getType())
|
|
|
|
return emitOpError(
|
2020-06-29 12:16:23 +02:00
|
|
|
"the type must be a pointer to the type of the referenced global");
|
2019-08-12 06:10:29 -07:00
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
if (function &&
|
|
|
|
LLVM::LLVMPointerType::get(function.getType()) != getResult().getType())
|
|
|
|
return emitOpError(
|
2020-06-29 12:16:23 +02:00
|
|
|
"the type must be a pointer to the type of the referenced function");
|
2019-08-12 06:10:29 -07:00
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-08-09 05:01:23 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Builder, printer and verifier for LLVM::GlobalOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-01-20 03:14:37 +00:00
|
|
|
/// Returns the name used for the linkage attribute. This *must* correspond to
|
2019-12-03 00:26:13 -08:00
|
|
|
/// the name of the attribute in ODS.
|
|
|
|
static StringRef getLinkageAttrName() { return "linkage"; }
|
|
|
|
|
2021-04-19 21:45:01 -04:00
|
|
|
/// Returns the name used for the unnamed_addr attribute. This *must* correspond
|
|
|
|
/// to the name of the attribute in ODS.
|
|
|
|
static StringRef getUnnamedAddrAttrName() { return "unnamed_addr"; }
|
|
|
|
|
2021-01-05 16:22:53 +01:00
|
|
|
void GlobalOp::build(OpBuilder &builder, OperationState &result, Type type,
|
2019-12-02 03:27:38 -08:00
|
|
|
bool isConstant, Linkage linkage, StringRef name,
|
2021-05-12 08:45:25 +02:00
|
|
|
Attribute value, uint64_t alignment, unsigned addrSpace,
|
2021-06-29 14:57:16 +02:00
|
|
|
bool dsoLocal, ArrayRef<NamedAttribute> attrs) {
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addAttribute(SymbolTable::getSymbolAttrName(),
|
2020-04-23 16:02:46 +02:00
|
|
|
builder.getStringAttr(name));
|
2021-10-24 18:17:09 -07:00
|
|
|
result.addAttribute("global_type", TypeAttr::get(type));
|
2019-08-09 05:01:23 -07:00
|
|
|
if (isConstant)
|
2020-04-23 16:02:46 +02:00
|
|
|
result.addAttribute("constant", builder.getUnitAttr());
|
2019-09-24 01:19:21 -07:00
|
|
|
if (value)
|
|
|
|
result.addAttribute("value", value);
|
2021-06-29 14:57:16 +02:00
|
|
|
if (dsoLocal)
|
|
|
|
result.addAttribute("dso_local", builder.getUnitAttr());
|
2021-05-12 08:45:25 +02:00
|
|
|
|
|
|
|
// Only add an alignment attribute if the "alignment" input
|
|
|
|
// is different from 0. The value must also be a power of two, but
|
|
|
|
// this is tested in GlobalOp::verify, not here.
|
|
|
|
if (alignment != 0)
|
|
|
|
result.addAttribute("alignment", builder.getI64IntegerAttr(alignment));
|
|
|
|
|
2021-10-24 18:36:33 -07:00
|
|
|
result.addAttribute(::getLinkageAttrName(),
|
2021-09-03 21:18:39 +00:00
|
|
|
LinkageAttr::get(builder.getContext(), linkage));
|
2019-12-06 12:00:01 -08:00
|
|
|
if (addrSpace != 0)
|
2020-04-23 16:02:46 +02:00
|
|
|
result.addAttribute("addr_space", builder.getI32IntegerAttr(addrSpace));
|
2019-09-20 19:47:05 -07:00
|
|
|
result.attributes.append(attrs.begin(), attrs.end());
|
2019-11-05 15:10:28 -08:00
|
|
|
result.addRegion();
|
2019-08-09 05:01:23 -07:00
|
|
|
}
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
void GlobalOp::print(OpAsmPrinter &p) {
|
|
|
|
p << ' ' << stringifyLinkage(getLinkage()) << ' ';
|
|
|
|
if (auto unnamedAddr = getUnnamedAddr()) {
|
2021-09-09 17:09:03 +05:30
|
|
|
StringRef str = stringifyUnnamedAddr(*unnamedAddr);
|
|
|
|
if (!str.empty())
|
|
|
|
p << str << ' ';
|
|
|
|
}
|
2022-02-07 17:54:04 -08:00
|
|
|
if (getConstant())
|
2019-09-20 20:43:02 -07:00
|
|
|
p << "constant ";
|
2022-02-07 17:54:04 -08:00
|
|
|
p.printSymbolName(getSymName());
|
2019-10-08 17:44:39 -07:00
|
|
|
p << '(';
|
2022-02-07 17:54:04 -08:00
|
|
|
if (auto value = getValueOrNull())
|
2019-09-21 01:19:43 -07:00
|
|
|
p.printAttribute(value);
|
2019-09-20 20:43:02 -07:00
|
|
|
p << ')';
|
2021-05-12 08:45:25 +02:00
|
|
|
// Note that the alignment attribute is printed using the
|
|
|
|
// default syntax here, even though it is an inherent attribute
|
|
|
|
// (as defined in https://mlir.llvm.org/docs/LangRef/#attributes)
|
2022-02-07 17:54:04 -08:00
|
|
|
p.printOptionalAttrDict((*this)->getAttrs(),
|
2021-10-24 18:17:09 -07:00
|
|
|
{SymbolTable::getSymbolAttrName(), "global_type",
|
|
|
|
"constant", "value", getLinkageAttrName(),
|
2021-04-19 21:45:01 -04:00
|
|
|
getUnnamedAddrAttrName()});
|
2019-08-09 08:59:45 -07:00
|
|
|
|
|
|
|
// Print the trailing type unless it's a string global.
|
2022-02-07 17:54:04 -08:00
|
|
|
if (getValueOrNull().dyn_cast_or_null<StringAttr>())
|
2019-08-09 08:59:45 -07:00
|
|
|
return;
|
2022-02-07 17:54:04 -08:00
|
|
|
p << " : " << getType();
|
2019-11-05 15:10:28 -08:00
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
Region &initializer = getInitializerRegion();
|
2022-01-18 07:47:25 +00:00
|
|
|
if (!initializer.empty()) {
|
|
|
|
p << ' ';
|
2019-11-05 15:10:28 -08:00
|
|
|
p.printRegion(initializer, /*printEntryBlockArgs=*/false);
|
2022-01-18 07:47:25 +00:00
|
|
|
}
|
2019-08-09 05:01:23 -07:00
|
|
|
}
|
|
|
|
|
2019-12-02 03:27:38 -08:00
|
|
|
// Parses one of the keywords provided in the list `keywords` and returns the
|
|
|
|
// position of the parsed keyword in the list. If none of the keywords from the
|
|
|
|
// list is parsed, returns -1.
|
|
|
|
static int parseOptionalKeywordAlternative(OpAsmParser &parser,
|
|
|
|
ArrayRef<StringRef> keywords) {
|
2022-01-02 22:02:14 +00:00
|
|
|
for (const auto &en : llvm::enumerate(keywords)) {
|
2019-12-02 03:27:38 -08:00
|
|
|
if (succeeded(parser.parseOptionalKeyword(en.value())))
|
|
|
|
return en.index();
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-01-24 17:51:10 +01:00
|
|
|
namespace {
|
2021-05-12 08:45:25 +02:00
|
|
|
template <typename Ty>
|
|
|
|
struct EnumTraits {};
|
2020-01-24 17:51:10 +01:00
|
|
|
|
|
|
|
#define REGISTER_ENUM_TYPE(Ty) \
|
2021-05-12 08:45:25 +02:00
|
|
|
template <> \
|
|
|
|
struct EnumTraits<Ty> { \
|
2020-01-24 17:51:10 +01:00
|
|
|
static StringRef stringify(Ty value) { return stringify##Ty(value); } \
|
|
|
|
static unsigned getMaxEnumVal() { return getMaxEnumValFor##Ty(); } \
|
|
|
|
}
|
|
|
|
|
|
|
|
REGISTER_ENUM_TYPE(Linkage);
|
2021-04-19 21:45:01 -04:00
|
|
|
REGISTER_ENUM_TYPE(UnnamedAddr);
|
2021-12-07 18:27:58 +00:00
|
|
|
} // namespace
|
2020-01-24 17:51:10 +01:00
|
|
|
|
2021-09-03 21:18:39 +00:00
|
|
|
/// Parse an enum from the keyword, or default to the provided default value.
|
|
|
|
/// The return type is the enum type by default, unless overriden with the
|
|
|
|
/// second template argument.
|
|
|
|
template <typename EnumTy, typename RetTy = EnumTy>
|
|
|
|
static RetTy parseOptionalLLVMKeyword(OpAsmParser &parser,
|
|
|
|
OperationState &result,
|
|
|
|
EnumTy defaultValue) {
|
2020-01-24 17:51:10 +01:00
|
|
|
SmallVector<StringRef, 10> names;
|
2021-09-03 21:18:39 +00:00
|
|
|
for (unsigned i = 0, e = EnumTraits<EnumTy>::getMaxEnumVal(); i <= e; ++i)
|
2020-01-24 17:51:10 +01:00
|
|
|
names.push_back(EnumTraits<EnumTy>::stringify(static_cast<EnumTy>(i)));
|
|
|
|
|
|
|
|
int index = parseOptionalKeywordAlternative(parser, names);
|
2019-12-02 03:27:38 -08:00
|
|
|
if (index == -1)
|
2021-09-03 21:18:39 +00:00
|
|
|
return static_cast<RetTy>(defaultValue);
|
|
|
|
return static_cast<RetTy>(index);
|
2019-12-02 03:27:38 -08:00
|
|
|
}
|
|
|
|
|
2020-04-14 13:01:53 +02:00
|
|
|
// operation ::= `llvm.mlir.global` linkage? `constant`? `@` identifier
|
2021-05-12 08:45:25 +02:00
|
|
|
// `(` attribute? `)` align? attribute-list? (`:` type)? region?
|
|
|
|
// align ::= `align` `=` UINT64
|
2019-08-09 08:59:45 -07:00
|
|
|
//
|
|
|
|
// The type can be omitted for string attributes, in which case it will be
|
|
|
|
// inferred from the value of the string as [strlen(value) x i8].
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult GlobalOp::parse(OpAsmParser &parser, OperationState &result) {
|
2021-09-29 17:47:08 -07:00
|
|
|
MLIRContext *ctx = parser.getContext();
|
2021-09-03 21:18:39 +00:00
|
|
|
// Parse optional linkage, default to External.
|
2022-02-07 17:54:04 -08:00
|
|
|
result.addAttribute(::getLinkageAttrName(),
|
2021-09-03 21:18:39 +00:00
|
|
|
LLVM::LinkageAttr::get(
|
|
|
|
ctx, parseOptionalLLVMKeyword<Linkage>(
|
|
|
|
parser, result, LLVM::Linkage::External)));
|
|
|
|
// Parse optional UnnamedAddr, default to None.
|
2022-02-07 17:54:04 -08:00
|
|
|
result.addAttribute(::getUnnamedAddrAttrName(),
|
2021-09-03 21:18:39 +00:00
|
|
|
parser.getBuilder().getI64IntegerAttr(
|
|
|
|
parseOptionalLLVMKeyword<UnnamedAddr, int64_t>(
|
|
|
|
parser, result, LLVM::UnnamedAddr::None)));
|
2021-04-19 21:45:01 -04:00
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (succeeded(parser.parseOptionalKeyword("constant")))
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addAttribute("constant", parser.getBuilder().getUnitAttr());
|
2019-08-09 05:01:23 -07:00
|
|
|
|
|
|
|
StringAttr name;
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseSymbolName(name, SymbolTable::getSymbolAttrName(),
|
2019-09-20 19:47:05 -07:00
|
|
|
result.attributes) ||
|
2019-09-21 01:19:43 -07:00
|
|
|
parser.parseLParen())
|
|
|
|
return failure();
|
|
|
|
|
|
|
|
Attribute value;
|
|
|
|
if (parser.parseOptionalRParen()) {
|
|
|
|
if (parser.parseAttribute(value, "value", result.attributes) ||
|
|
|
|
parser.parseRParen())
|
|
|
|
return failure();
|
|
|
|
}
|
|
|
|
|
|
|
|
SmallVector<Type, 1> types;
|
2019-11-05 13:32:07 -08:00
|
|
|
if (parser.parseOptionalAttrDict(result.attributes) ||
|
2019-09-20 11:36:49 -07:00
|
|
|
parser.parseOptionalColonTypeList(types))
|
2019-08-09 05:01:23 -07:00
|
|
|
return failure();
|
|
|
|
|
2019-08-09 08:59:45 -07:00
|
|
|
if (types.size() > 1)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(parser.getNameLoc(), "expected zero or one type");
|
2019-08-09 08:59:45 -07:00
|
|
|
|
2019-11-05 15:10:28 -08:00
|
|
|
Region &initRegion = *result.addRegion();
|
2019-08-09 08:59:45 -07:00
|
|
|
if (types.empty()) {
|
2019-09-21 01:19:43 -07:00
|
|
|
if (auto strAttr = value.dyn_cast_or_null<StringAttr>()) {
|
2021-09-29 17:47:08 -07:00
|
|
|
MLIRContext *context = parser.getContext();
|
[mlir] replace LLVMIntegerType with built-in integer type
The LLVM dialect type system has been closed until now, i.e. did not support
types from other dialects inside containers. While this has had obvious
benefits of deriving from a common base class, it has led to some simple types
being almost identical with the built-in types, namely integer and floating
point types. This in turn has led to a lot of larger-scale complexity: simple
types must still be converted, numerous operations that correspond to LLVM IR
intrinsics are replicated to produce versions operating on either LLVM dialect
or built-in types leading to quasi-duplicate dialects, lowering to the LLVM
dialect is essentially required to be one-shot because of type conversion, etc.
In this light, it is reasonable to trade off some local complexity in the
internal implementation of LLVM dialect types for removing larger-scale system
complexity. Previous commits to the LLVM dialect type system have adapted the
API to support types from other dialects.
Replace LLVMIntegerType with the built-in IntegerType plus additional checks
that such types are signless (these are isolated in a utility function that
replaced `isa<LLVMType>` and in the parser). Temporarily keep the possibility
to parse `!llvm.i32` as a synonym for `i32`, but add a deprecation notice.
Reviewed By: mehdi_amini, silvas, antiagainst
Differential Revision: https://reviews.llvm.org/D94178
2021-01-06 16:19:04 +01:00
|
|
|
auto arrayType = LLVM::LLVMArrayType::get(IntegerType::get(context, 8),
|
|
|
|
strAttr.getValue().size());
|
2019-08-09 08:59:45 -07:00
|
|
|
types.push_back(arrayType);
|
|
|
|
} else {
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(parser.getNameLoc(),
|
|
|
|
"type can only be omitted for string globals");
|
2019-08-09 08:59:45 -07:00
|
|
|
}
|
2020-12-02 16:49:47 -08:00
|
|
|
} else {
|
|
|
|
OptionalParseResult parseResult =
|
|
|
|
parser.parseOptionalRegion(initRegion, /*arguments=*/{},
|
|
|
|
/*argTypes=*/{});
|
|
|
|
if (parseResult.hasValue() && failed(*parseResult))
|
|
|
|
return failure();
|
2019-08-09 08:59:45 -07:00
|
|
|
}
|
|
|
|
|
2021-10-24 18:17:09 -07:00
|
|
|
result.addAttribute("global_type", TypeAttr::get(types[0]));
|
2019-08-09 05:01:23 -07:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2021-02-16 17:36:20 +01:00
|
|
|
static bool isZeroAttribute(Attribute value) {
|
|
|
|
if (auto intValue = value.dyn_cast<IntegerAttr>())
|
|
|
|
return intValue.getValue().isNullValue();
|
|
|
|
if (auto fpValue = value.dyn_cast<FloatAttr>())
|
|
|
|
return fpValue.getValue().isZero();
|
|
|
|
if (auto splatValue = value.dyn_cast<SplatElementsAttr>())
|
2021-11-09 01:40:17 +00:00
|
|
|
return isZeroAttribute(splatValue.getSplatValue<Attribute>());
|
2021-02-16 17:36:20 +01:00
|
|
|
if (auto elementsValue = value.dyn_cast<ElementsAttr>())
|
|
|
|
return llvm::all_of(elementsValue.getValues<Attribute>(), isZeroAttribute);
|
|
|
|
if (auto arrayValue = value.dyn_cast<ArrayAttr>())
|
|
|
|
return llvm::all_of(arrayValue.getValue(), isZeroAttribute);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult GlobalOp::verify() {
|
|
|
|
if (!LLVMPointerType::isValidElementType(getType()))
|
|
|
|
return emitOpError(
|
2019-08-09 05:01:23 -07:00
|
|
|
"expects type to be a valid element type for an LLVM pointer");
|
2022-02-02 10:16:28 -08:00
|
|
|
if ((*this)->getParentOp() && !satisfiesLLVMModule((*this)->getParentOp()))
|
|
|
|
return emitOpError("must appear at the module level");
|
2019-09-21 01:19:43 -07:00
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
if (auto strAttr = getValueOrNull().dyn_cast_or_null<StringAttr>()) {
|
|
|
|
auto type = getType().dyn_cast<LLVMArrayType>();
|
[mlir] replace LLVMIntegerType with built-in integer type
The LLVM dialect type system has been closed until now, i.e. did not support
types from other dialects inside containers. While this has had obvious
benefits of deriving from a common base class, it has led to some simple types
being almost identical with the built-in types, namely integer and floating
point types. This in turn has led to a lot of larger-scale complexity: simple
types must still be converted, numerous operations that correspond to LLVM IR
intrinsics are replicated to produce versions operating on either LLVM dialect
or built-in types leading to quasi-duplicate dialects, lowering to the LLVM
dialect is essentially required to be one-shot because of type conversion, etc.
In this light, it is reasonable to trade off some local complexity in the
internal implementation of LLVM dialect types for removing larger-scale system
complexity. Previous commits to the LLVM dialect type system have adapted the
API to support types from other dialects.
Replace LLVMIntegerType with the built-in IntegerType plus additional checks
that such types are signless (these are isolated in a utility function that
replaced `isa<LLVMType>` and in the parser). Temporarily keep the possibility
to parse `!llvm.i32` as a synonym for `i32`, but add a deprecation notice.
Reviewed By: mehdi_amini, silvas, antiagainst
Differential Revision: https://reviews.llvm.org/D94178
2021-01-06 16:19:04 +01:00
|
|
|
IntegerType elementType =
|
|
|
|
type ? type.getElementType().dyn_cast<IntegerType>() : nullptr;
|
|
|
|
if (!elementType || elementType.getWidth() != 8 ||
|
2020-12-22 11:22:21 +01:00
|
|
|
type.getNumElements() != strAttr.getValue().size())
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError(
|
2019-08-09 08:59:45 -07:00
|
|
|
"requires an i8 array type of the length equal to that of the string "
|
|
|
|
"attribute");
|
|
|
|
}
|
2019-11-05 15:10:28 -08:00
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
if (getLinkage() == Linkage::Common) {
|
|
|
|
if (Attribute value = getValueOrNull()) {
|
2021-02-16 17:36:20 +01:00
|
|
|
if (!isZeroAttribute(value)) {
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError()
|
2021-02-16 17:36:20 +01:00
|
|
|
<< "expected zero value for '"
|
|
|
|
<< stringifyLinkage(Linkage::Common) << "' linkage";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
if (getLinkage() == Linkage::Appending) {
|
|
|
|
if (!getType().isa<LLVMArrayType>()) {
|
|
|
|
return emitOpError() << "expected array type for '"
|
|
|
|
<< stringifyLinkage(Linkage::Appending)
|
|
|
|
<< "' linkage";
|
2021-02-16 17:36:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
Optional<uint64_t> alignAttr = getAlignment();
|
2021-05-12 08:45:25 +02:00
|
|
|
if (alignAttr.hasValue()) {
|
|
|
|
uint64_t value = alignAttr.getValue();
|
|
|
|
if (!llvm::isPowerOf2_64(value))
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitError() << "alignment attribute is not a power of 2";
|
2021-05-12 08:45:25 +02:00
|
|
|
}
|
|
|
|
|
2019-08-09 05:01:23 -07:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2022-03-10 22:10:45 +00:00
|
|
|
LogicalResult GlobalOp::verifyRegions() {
|
|
|
|
if (Block *b = getInitializerBlock()) {
|
|
|
|
ReturnOp ret = cast<ReturnOp>(b->getTerminator());
|
|
|
|
if (ret.operand_type_begin() == ret.operand_type_end())
|
|
|
|
return emitOpError("initializer region cannot return void");
|
|
|
|
if (*ret.operand_type_begin() != getType())
|
|
|
|
return emitOpError("initializer region type ")
|
|
|
|
<< *ret.operand_type_begin() << " does not match global type "
|
|
|
|
<< getType();
|
|
|
|
|
|
|
|
for (Operation &op : *b) {
|
|
|
|
auto iface = dyn_cast<MemoryEffectOpInterface>(op);
|
|
|
|
if (!iface || !iface.hasNoEffect())
|
|
|
|
return op.emitError()
|
|
|
|
<< "ops with side effects not allowed in global initializers";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (getValueOrNull())
|
|
|
|
return emitOpError("cannot have both initializer value and region");
|
|
|
|
}
|
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2021-10-20 15:14:54 +05:30
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// LLVM::GlobalCtorsOp
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
LogicalResult
|
|
|
|
GlobalCtorsOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
|
2021-11-30 19:42:37 -08:00
|
|
|
for (Attribute ctor : getCtors()) {
|
2021-10-20 15:14:54 +05:30
|
|
|
if (failed(verifySymbolAttrUse(ctor.cast<FlatSymbolRefAttr>(), *this,
|
|
|
|
symbolTable)))
|
|
|
|
return failure();
|
|
|
|
}
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult GlobalCtorsOp::verify() {
|
|
|
|
if (getCtors().size() != getPriorities().size())
|
|
|
|
return emitError(
|
2021-10-20 15:14:54 +05:30
|
|
|
"mismatch between the number of ctors and the number of priorities");
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// LLVM::GlobalDtorsOp
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
LogicalResult
|
|
|
|
GlobalDtorsOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
|
2021-11-30 19:42:37 -08:00
|
|
|
for (Attribute dtor : getDtors()) {
|
2021-10-20 15:14:54 +05:30
|
|
|
if (failed(verifySymbolAttrUse(dtor.cast<FlatSymbolRefAttr>(), *this,
|
|
|
|
symbolTable)))
|
|
|
|
return failure();
|
|
|
|
}
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult GlobalDtorsOp::verify() {
|
|
|
|
if (getDtors().size() != getPriorities().size())
|
|
|
|
return emitError(
|
2021-10-20 15:14:54 +05:30
|
|
|
"mismatch between the number of dtors and the number of priorities");
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-08-09 05:24:47 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::ShuffleVectorOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Expects vector to be of wrapped LLVM vector type and position to be of
|
|
|
|
// wrapped LLVM i32 type.
|
2020-04-23 16:02:46 +02:00
|
|
|
void LLVM::ShuffleVectorOp::build(OpBuilder &b, OperationState &result,
|
|
|
|
Value v1, Value v2, ArrayAttr mask,
|
2019-08-09 05:24:47 -07:00
|
|
|
ArrayRef<NamedAttribute> attrs) {
|
[mlir] use built-in vector types instead of LLVM dialect types when possible
Continue the convergence between LLVM dialect and built-in types by using the
built-in vector type whenever possible, that is for fixed vectors of built-in
integers and built-in floats. LLVM dialect vector type is still in use for
pointers, less frequent floating point types that do not have a built-in
equivalent, and scalable vectors. However, the top-level `LLVMVectorType` class
has been removed in favor of free functions capable of inspecting both built-in
and LLVM dialect vector types: `LLVM::getVectorElementType`,
`LLVM::getNumVectorElements` and `LLVM::getFixedVectorType`. Additional work is
necessary to design an implemented the extensions to built-in types so as to
remove the `LLVMFixedVectorType` entirely.
Note that the default output format for the built-in vectors does not have
whitespace around the `x` separator, e.g., `vector<4xf32>` as opposed to the
LLVM dialect vector type format that does, e.g., `!llvm.vec<4 x fp128>`. This
required changing the FileCheck patterns in several tests.
Reviewed By: mehdi_amini, silvas
Differential Revision: https://reviews.llvm.org/D94405
2021-01-11 13:58:05 +01:00
|
|
|
auto containerType = v1.getType();
|
2022-01-27 13:36:16 +00:00
|
|
|
auto vType = LLVM::getVectorType(
|
|
|
|
LLVM::getVectorElementType(containerType), mask.size(),
|
|
|
|
containerType.cast<VectorType>().isScalable());
|
2019-08-09 05:24:47 -07:00
|
|
|
build(b, result, vType, v1, v2, mask);
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addAttributes(attrs);
|
2019-08-09 05:24:47 -07:00
|
|
|
}
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
void ShuffleVectorOp::print(OpAsmPrinter &p) {
|
|
|
|
p << ' ' << getV1() << ", " << getV2() << " " << getMask();
|
|
|
|
p.printOptionalAttrDict((*this)->getAttrs(), {"mask"});
|
|
|
|
p << " : " << getV1().getType() << ", " << getV2().getType();
|
2019-08-09 05:24:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.shufflevector` ssa-use `, ` ssa-use
|
|
|
|
// `[` integer-literal (`,` integer-literal)* `]`
|
|
|
|
// attribute-dict? `:` type
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult ShuffleVectorOp::parse(OpAsmParser &parser,
|
|
|
|
OperationState &result) {
|
2022-01-26 15:49:53 -08:00
|
|
|
SMLoc loc;
|
2019-08-09 05:24:47 -07:00
|
|
|
OpAsmParser::OperandType v1, v2;
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
ArrayAttr maskAttr;
|
2019-08-09 05:24:47 -07:00
|
|
|
Type typeV1, typeV2;
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.getCurrentLocation(&loc) || parser.parseOperand(v1) ||
|
|
|
|
parser.parseComma() || parser.parseOperand(v2) ||
|
[MLIR] LLVM dialect: modernize and cleanups
Summary:
Modernize some of the existing custom parsing code in the LLVM dialect.
While this reduces some boilerplate code, it also reduces the precision
of the diagnostic error messges.
Reviewers: ftynse, nicolasvasilache, rriddle
Reviewed By: rriddle
Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72967
2020-01-17 17:11:04 -08:00
|
|
|
parser.parseAttribute(maskAttr, "mask", result.attributes) ||
|
|
|
|
parser.parseOptionalAttrDict(result.attributes) ||
|
|
|
|
parser.parseColonType(typeV1) || parser.parseComma() ||
|
|
|
|
parser.parseType(typeV2) ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.resolveOperand(v1, typeV1, result.operands) ||
|
|
|
|
parser.resolveOperand(v2, typeV2, result.operands))
|
2019-08-09 05:24:47 -07:00
|
|
|
return failure();
|
[mlir] use built-in vector types instead of LLVM dialect types when possible
Continue the convergence between LLVM dialect and built-in types by using the
built-in vector type whenever possible, that is for fixed vectors of built-in
integers and built-in floats. LLVM dialect vector type is still in use for
pointers, less frequent floating point types that do not have a built-in
equivalent, and scalable vectors. However, the top-level `LLVMVectorType` class
has been removed in favor of free functions capable of inspecting both built-in
and LLVM dialect vector types: `LLVM::getVectorElementType`,
`LLVM::getNumVectorElements` and `LLVM::getFixedVectorType`. Additional work is
necessary to design an implemented the extensions to built-in types so as to
remove the `LLVMFixedVectorType` entirely.
Note that the default output format for the built-in vectors does not have
whitespace around the `x` separator, e.g., `vector<4xf32>` as opposed to the
LLVM dialect vector type format that does, e.g., `!llvm.vec<4 x fp128>`. This
required changing the FileCheck patterns in several tests.
Reviewed By: mehdi_amini, silvas
Differential Revision: https://reviews.llvm.org/D94405
2021-01-11 13:58:05 +01:00
|
|
|
if (!LLVM::isCompatibleVectorType(typeV1))
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(
|
2019-08-09 05:24:47 -07:00
|
|
|
loc, "expected LLVM IR dialect vector type for operand #1");
|
2022-01-27 13:36:16 +00:00
|
|
|
auto vType =
|
|
|
|
LLVM::getVectorType(LLVM::getVectorElementType(typeV1), maskAttr.size(),
|
|
|
|
typeV1.cast<VectorType>().isScalable());
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes(vType);
|
2019-08-09 05:24:47 -07:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult ShuffleVectorOp::verify() {
|
|
|
|
Type type1 = getV1().getType();
|
|
|
|
Type type2 = getV2().getType();
|
|
|
|
if (LLVM::getVectorElementType(type1) != LLVM::getVectorElementType(type2))
|
|
|
|
return emitOpError("expected matching LLVM IR Dialect element types");
|
2022-01-27 13:36:16 +00:00
|
|
|
if (LLVM::isScalableVectorType(type1))
|
|
|
|
if (llvm::any_of(getMask(), [](Attribute attr) {
|
|
|
|
return attr.cast<IntegerAttr>().getInt() != 0;
|
|
|
|
}))
|
|
|
|
return emitOpError("expected a splat operation for scalable vectors");
|
2022-02-02 10:16:28 -08:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-12-19 12:16:19 -08:00
|
|
|
// Implementations for LLVM::LLVMFuncOp.
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-12-19 12:16:19 -08:00
|
|
|
// Add the entry block to the function.
|
|
|
|
Block *LLVMFuncOp::addEntryBlock() {
|
|
|
|
assert(empty() && "function already has an entry block");
|
|
|
|
assert(!isVarArg() && "unimplemented: non-external variadic functions");
|
|
|
|
|
|
|
|
auto *entry = new Block;
|
|
|
|
push_back(entry);
|
|
|
|
|
2022-01-18 18:28:51 -08:00
|
|
|
// FIXME: Allow passing in proper locations for the entry arguments.
|
2020-12-22 11:22:21 +01:00
|
|
|
LLVMFunctionType type = getType();
|
|
|
|
for (unsigned i = 0, e = type.getNumParams(); i < e; ++i)
|
2022-01-18 18:28:51 -08:00
|
|
|
entry->addArgument(type.getParamType(i), getLoc());
|
2019-12-19 12:16:19 -08:00
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
2020-04-23 16:02:46 +02:00
|
|
|
void LLVMFuncOp::build(OpBuilder &builder, OperationState &result,
|
2021-01-05 16:22:53 +01:00
|
|
|
StringRef name, Type type, LLVM::Linkage linkage,
|
2021-06-29 14:57:16 +02:00
|
|
|
bool dsoLocal, ArrayRef<NamedAttribute> attrs,
|
2020-12-17 17:10:12 -08:00
|
|
|
ArrayRef<DictionaryAttr> argAttrs) {
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addRegion();
|
|
|
|
result.addAttribute(SymbolTable::getSymbolAttrName(),
|
2020-04-23 16:02:46 +02:00
|
|
|
builder.getStringAttr(name));
|
2019-10-17 20:08:01 -07:00
|
|
|
result.addAttribute("type", TypeAttr::get(type));
|
2021-10-24 18:36:33 -07:00
|
|
|
result.addAttribute(::getLinkageAttrName(),
|
2021-09-03 21:18:39 +00:00
|
|
|
LinkageAttr::get(builder.getContext(), linkage));
|
2019-09-20 19:47:05 -07:00
|
|
|
result.attributes.append(attrs.begin(), attrs.end());
|
2021-06-29 14:57:16 +02:00
|
|
|
if (dsoLocal)
|
|
|
|
result.addAttribute("dso_local", builder.getUnitAttr());
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
if (argAttrs.empty())
|
|
|
|
return;
|
|
|
|
|
2021-05-07 19:30:25 -07:00
|
|
|
assert(type.cast<LLVMFunctionType>().getNumParams() == argAttrs.size() &&
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
"expected as many argument attribute lists as arguments");
|
2022-01-13 20:51:38 -08:00
|
|
|
function_interface_impl::addArgAndResultAttrs(builder, result, argAttrs,
|
|
|
|
/*resultAttrs=*/llvm::None);
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
}
|
|
|
|
|
2019-12-03 00:26:13 -08:00
|
|
|
// Builds an LLVM function type from the given lists of input and output types.
|
2019-08-05 01:57:27 -07:00
|
|
|
// Returns a null type if any of the types provided are non-LLVM types, or if
|
|
|
|
// there is more than one output type.
|
2021-05-07 19:30:25 -07:00
|
|
|
static Type
|
2022-01-26 15:49:53 -08:00
|
|
|
buildLLVMFunctionType(OpAsmParser &parser, SMLoc loc,
|
2021-05-07 19:30:25 -07:00
|
|
|
ArrayRef<Type> inputs, ArrayRef<Type> outputs,
|
2022-01-13 20:51:38 -08:00
|
|
|
function_interface_impl::VariadicFlag variadicFlag) {
|
2019-12-03 00:26:13 -08:00
|
|
|
Builder &b = parser.getBuilder();
|
2019-08-05 01:57:27 -07:00
|
|
|
if (outputs.size() > 1) {
|
2019-12-03 00:26:13 -08:00
|
|
|
parser.emitError(loc, "failed to construct function type: expected zero or "
|
|
|
|
"one function result");
|
2019-08-05 01:57:27 -07:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert inputs to LLVM types, exit early on error.
|
2021-01-05 16:22:53 +01:00
|
|
|
SmallVector<Type, 4> llvmInputs;
|
2019-08-05 01:57:27 -07:00
|
|
|
for (auto t : inputs) {
|
2021-01-05 16:22:53 +01:00
|
|
|
if (!isCompatibleType(t)) {
|
2019-12-03 00:26:13 -08:00
|
|
|
parser.emitError(loc, "failed to construct function type: expected LLVM "
|
|
|
|
"type for function arguments");
|
2019-08-05 01:57:27 -07:00
|
|
|
return {};
|
|
|
|
}
|
2021-01-05 16:22:53 +01:00
|
|
|
llvmInputs.push_back(t);
|
2019-08-05 01:57:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// No output is denoted as "void" in LLVM type system.
|
2021-01-05 16:22:53 +01:00
|
|
|
Type llvmOutput =
|
|
|
|
outputs.empty() ? LLVMVoidType::get(b.getContext()) : outputs.front();
|
|
|
|
if (!isCompatibleType(llvmOutput)) {
|
2019-12-03 00:26:13 -08:00
|
|
|
parser.emitError(loc, "failed to construct function type: expected LLVM "
|
2021-01-05 16:22:53 +01:00
|
|
|
"type for function results")
|
|
|
|
<< llvmOutput;
|
2019-08-05 01:57:27 -07:00
|
|
|
return {};
|
|
|
|
}
|
2020-12-22 11:22:56 +01:00
|
|
|
return LLVMFunctionType::get(llvmOutput, llvmInputs,
|
|
|
|
variadicFlag.isVariadic());
|
2019-08-05 01:57:27 -07:00
|
|
|
}
|
|
|
|
|
2019-12-03 00:26:13 -08:00
|
|
|
// Parses an LLVM function.
|
|
|
|
//
|
|
|
|
// operation ::= `llvm.func` linkage? function-signature function-attributes?
|
|
|
|
// function-body
|
|
|
|
//
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult LLVMFuncOp::parse(OpAsmParser &parser, OperationState &result) {
|
2019-12-03 00:26:13 -08:00
|
|
|
// Default to external linkage if no keyword is provided.
|
2021-09-03 21:18:39 +00:00
|
|
|
result.addAttribute(
|
2022-02-07 17:54:04 -08:00
|
|
|
::getLinkageAttrName(),
|
2021-09-29 17:47:08 -07:00
|
|
|
LinkageAttr::get(parser.getContext(),
|
2021-09-03 21:18:39 +00:00
|
|
|
parseOptionalLLVMKeyword<Linkage>(
|
|
|
|
parser, result, LLVM::Linkage::External)));
|
2019-12-03 00:26:13 -08:00
|
|
|
|
|
|
|
StringAttr nameAttr;
|
2022-01-19 23:44:43 +00:00
|
|
|
SmallVector<OpAsmParser::OperandType> entryArgs;
|
|
|
|
SmallVector<NamedAttrList> argAttrs;
|
|
|
|
SmallVector<NamedAttrList> resultAttrs;
|
|
|
|
SmallVector<Type> argTypes;
|
|
|
|
SmallVector<Type> resultTypes;
|
2022-01-18 18:28:51 -08:00
|
|
|
SmallVector<Location> argLocations;
|
2019-12-03 00:26:13 -08:00
|
|
|
bool isVariadic;
|
|
|
|
|
|
|
|
auto signatureLocation = parser.getCurrentLocation();
|
|
|
|
if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
|
|
|
|
result.attributes) ||
|
2022-01-13 20:51:38 -08:00
|
|
|
function_interface_impl::parseFunctionSignature(
|
2021-05-07 19:30:25 -07:00
|
|
|
parser, /*allowVariadic=*/true, entryArgs, argTypes, argAttrs,
|
2022-01-19 23:44:43 +00:00
|
|
|
argLocations, isVariadic, resultTypes, resultAttrs))
|
2019-12-03 00:26:13 -08:00
|
|
|
return failure();
|
|
|
|
|
|
|
|
auto type =
|
|
|
|
buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes,
|
2022-01-13 20:51:38 -08:00
|
|
|
function_interface_impl::VariadicFlag(isVariadic));
|
2019-12-03 00:26:13 -08:00
|
|
|
if (!type)
|
|
|
|
return failure();
|
2022-01-13 20:51:38 -08:00
|
|
|
result.addAttribute(FunctionOpInterface::getTypeAttrName(),
|
2021-05-07 19:30:25 -07:00
|
|
|
TypeAttr::get(type));
|
2019-12-03 00:26:13 -08:00
|
|
|
|
|
|
|
if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
|
|
|
|
return failure();
|
2022-01-13 20:51:38 -08:00
|
|
|
function_interface_impl::addArgAndResultAttrs(parser.getBuilder(), result,
|
|
|
|
argAttrs, resultAttrs);
|
2019-12-03 00:26:13 -08:00
|
|
|
|
|
|
|
auto *body = result.addRegion();
|
2020-12-02 16:49:47 -08:00
|
|
|
OptionalParseResult parseResult = parser.parseOptionalRegion(
|
2019-12-18 09:28:48 -08:00
|
|
|
*body, entryArgs, entryArgs.empty() ? ArrayRef<Type>() : argTypes);
|
2020-12-02 16:49:47 -08:00
|
|
|
return failure(parseResult.hasValue() && failed(*parseResult));
|
2019-12-03 00:26:13 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Print the LLVMFuncOp. Collects argument and result types and passes them to
|
|
|
|
// helper functions. Drops "void" result since it cannot be parsed back. Skips
|
|
|
|
// the external linkage since it is the default value.
|
2022-02-07 17:54:04 -08:00
|
|
|
void LLVMFuncOp::print(OpAsmPrinter &p) {
|
2021-08-28 03:03:15 +00:00
|
|
|
p << ' ';
|
2022-02-07 17:54:04 -08:00
|
|
|
if (getLinkage() != LLVM::Linkage::External)
|
|
|
|
p << stringifyLinkage(getLinkage()) << ' ';
|
|
|
|
p.printSymbolName(getName());
|
2019-12-03 00:26:13 -08:00
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
LLVMFunctionType fnType = getType();
|
2019-08-05 01:57:27 -07:00
|
|
|
SmallVector<Type, 8> argTypes;
|
|
|
|
SmallVector<Type, 1> resTypes;
|
2020-12-22 11:22:21 +01:00
|
|
|
argTypes.reserve(fnType.getNumParams());
|
|
|
|
for (unsigned i = 0, e = fnType.getNumParams(); i < e; ++i)
|
|
|
|
argTypes.push_back(fnType.getParamType(i));
|
2019-08-05 01:57:27 -07:00
|
|
|
|
2021-01-05 16:22:53 +01:00
|
|
|
Type returnType = fnType.getReturnType();
|
2020-12-22 11:22:21 +01:00
|
|
|
if (!returnType.isa<LLVMVoidType>())
|
2019-08-05 01:57:27 -07:00
|
|
|
resTypes.push_back(returnType);
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
function_interface_impl::printFunctionSignature(p, *this, argTypes,
|
|
|
|
isVarArg(), resTypes);
|
2022-01-13 20:51:38 -08:00
|
|
|
function_interface_impl::printFunctionAttributes(
|
2022-02-07 17:54:04 -08:00
|
|
|
p, *this, argTypes.size(), resTypes.size(), {getLinkageAttrName()});
|
2019-12-03 00:26:13 -08:00
|
|
|
|
|
|
|
// Print the body if this is not an external function.
|
2022-02-07 17:54:04 -08:00
|
|
|
Region &body = getBody();
|
2022-01-18 07:47:25 +00:00
|
|
|
if (!body.empty()) {
|
|
|
|
p << ' ';
|
2019-12-03 00:26:13 -08:00
|
|
|
p.printRegion(body, /*printEntryBlockArgs=*/false,
|
|
|
|
/*printBlockTerminators=*/true);
|
2022-01-18 07:47:25 +00:00
|
|
|
}
|
2019-08-05 01:57:27 -07:00
|
|
|
}
|
|
|
|
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
LogicalResult LLVMFuncOp::verifyType() {
|
2020-12-22 11:22:21 +01:00
|
|
|
auto llvmType = getTypeAttr().getValue().dyn_cast_or_null<LLVMFunctionType>();
|
|
|
|
if (!llvmType)
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
return emitOpError("requires '" + getTypeAttrName() +
|
|
|
|
"' attribute of wrapped LLVM function type");
|
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-12-03 00:26:13 -08:00
|
|
|
// Verifies LLVM- and implementation-specific properties of the LLVM func Op:
|
|
|
|
// - functions don't have 'common' linkage
|
|
|
|
// - external functions have 'external' or 'extern_weak' linkage;
|
|
|
|
// - vararg is (currently) only supported for external functions;
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult LLVMFuncOp::verify() {
|
|
|
|
if (getLinkage() == LLVM::Linkage::Common)
|
|
|
|
return emitOpError() << "functions cannot have '"
|
|
|
|
<< stringifyLinkage(LLVM::Linkage::Common)
|
|
|
|
<< "' linkage";
|
2019-12-03 00:26:13 -08:00
|
|
|
|
2022-01-13 20:51:38 -08:00
|
|
|
// Check to see if this function has a void return with a result attribute to
|
|
|
|
// it. It isn't clear what semantics we would assign to that.
|
2022-02-02 10:16:28 -08:00
|
|
|
if (getType().getReturnType().isa<LLVMVoidType>() &&
|
|
|
|
!getResultAttrs(0).empty()) {
|
|
|
|
return emitOpError()
|
2022-01-13 20:51:38 -08:00
|
|
|
<< "cannot attach result attributes to functions with a void return";
|
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
if (isExternal()) {
|
|
|
|
if (getLinkage() != LLVM::Linkage::External &&
|
|
|
|
getLinkage() != LLVM::Linkage::ExternWeak)
|
|
|
|
return emitOpError() << "external functions must have '"
|
|
|
|
<< stringifyLinkage(LLVM::Linkage::External)
|
|
|
|
<< "' or '"
|
|
|
|
<< stringifyLinkage(LLVM::Linkage::ExternWeak)
|
|
|
|
<< "' linkage";
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
return success();
|
2019-12-03 00:26:13 -08:00
|
|
|
}
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
if (isVarArg())
|
|
|
|
return emitOpError("only external functions can be variadic");
|
2019-08-08 09:41:48 -07:00
|
|
|
|
2022-03-10 22:10:45 +00:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Verifies LLVM- and implementation-specific properties of the LLVM func Op:
|
|
|
|
/// - entry block arguments are of LLVM types and match the function signature.
|
|
|
|
LogicalResult LLVMFuncOp::verifyRegions() {
|
|
|
|
if (isExternal())
|
|
|
|
return success();
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
unsigned numArguments = getType().getNumParams();
|
|
|
|
Block &entryBlock = front();
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
for (unsigned i = 0; i < numArguments; ++i) {
|
2020-01-11 08:54:04 -08:00
|
|
|
Type argType = entryBlock.getArgument(i).getType();
|
2021-01-05 16:22:53 +01:00
|
|
|
if (!isCompatibleType(argType))
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError("entry block argument #")
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
<< i << " is not of LLVM type";
|
2022-02-02 10:16:28 -08:00
|
|
|
if (getType().getParamType(i) != argType)
|
|
|
|
return emitOpError("the type of entry block argument #")
|
Introduce LLVMFuncOp
Originally, MLIR only supported functions of the built-in FunctionType. On the
conversion path to LLVM IR, we were creating MLIR functions that contained LLVM
dialect operations and used LLVM IR types for everything expect top-level
functions (e.g., a second-order function would have a FunctionType that consume
or produces a wrapped LLVM function pointer type). With MLIR functions
becoming operations, it is now possible to introduce non-built-in function
operations. This will let us use conversion patterns for function conversion,
simplify the MLIR-to-LLVM translation by removing the knowledge of the MLIR
built-in function types, and provide stronger correctness verifications (e.g.
LLVM functions only accept LLVM types).
Furthermore, we can currently construct a situation where the same function is
used with two different types: () -> () when its specified and called directly,
and !llvm<"void ()"> when it's passed somewhere on called indirectly. Having a
special function-op that is always of !llvm<"void ()"> type makes the function
model and the llvm dialect type system more consistent.
Introduce LLVMFuncOp to represent a function in the LLVM dialect. Unlike
standard FuncOp, this function has an LLVMType wrapping an LLVM IR function
type. Generalize the common behavior of function-defining operations
(functions live in a symbol table of a module, contain a single region, are
iterable as a list of blocks, and support argument attributes).
This only defines the operation. Custom syntax, conversion and translation
rules will be added in follow-ups.
The operation name mentions LLVM explicitly to avoid confusion with standard
FuncOp, especially in multiple files that use both `mlir` and `mlir::LLVM`
namespaces.
PiperOrigin-RevId: 259550940
2019-07-23 09:26:15 -07:00
|
|
|
<< i << " does not match the function signature";
|
|
|
|
}
|
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
2020-06-29 12:16:23 +02:00
|
|
|
// Verification for LLVM::ConstantOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult LLVM::ConstantOp::verify() {
|
|
|
|
if (StringAttr sAttr = getValue().dyn_cast<StringAttr>()) {
|
|
|
|
auto arrayType = getType().dyn_cast<LLVMArrayType>();
|
2021-02-16 17:36:20 +01:00
|
|
|
if (!arrayType || arrayType.getNumElements() != sAttr.getValue().size() ||
|
|
|
|
!arrayType.getElementType().isInteger(8)) {
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError() << "expected array type of "
|
|
|
|
<< sAttr.getValue().size()
|
|
|
|
<< " i8 elements for the string constant";
|
2021-02-16 17:36:20 +01:00
|
|
|
}
|
|
|
|
return success();
|
|
|
|
}
|
2022-02-02 10:16:28 -08:00
|
|
|
if (auto structType = getType().dyn_cast<LLVMStructType>()) {
|
2021-05-14 13:00:38 +02:00
|
|
|
if (structType.getBody().size() != 2 ||
|
|
|
|
structType.getBody()[0] != structType.getBody()[1]) {
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitError() << "expected struct type with two elements of the "
|
|
|
|
"same type, the type of a complex constant";
|
2021-05-14 13:00:38 +02:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
auto arrayAttr = getValue().dyn_cast<ArrayAttr>();
|
2021-05-14 13:00:38 +02:00
|
|
|
if (!arrayAttr || arrayAttr.size() != 2 ||
|
|
|
|
arrayAttr[0].getType() != arrayAttr[1].getType()) {
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError() << "expected array attribute with two elements, "
|
|
|
|
"representing a complex constant";
|
2021-05-14 13:00:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Type elementType = structType.getBody()[0];
|
|
|
|
if (!elementType
|
|
|
|
.isa<IntegerType, Float16Type, Float32Type, Float64Type>()) {
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitError()
|
2021-05-14 13:00:38 +02:00
|
|
|
<< "expected struct element types to be floating point type or "
|
|
|
|
"integer type";
|
|
|
|
}
|
|
|
|
return success();
|
|
|
|
}
|
2022-02-02 10:16:28 -08:00
|
|
|
if (!getValue().isa<IntegerAttr, ArrayAttr, FloatAttr, ElementsAttr>())
|
|
|
|
return emitOpError()
|
2020-06-29 12:16:23 +02:00
|
|
|
<< "only supports integer, float, string or elements attributes";
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2022-01-06 23:29:52 +01:00
|
|
|
// Constant op constant-folds to its value.
|
|
|
|
OpFoldResult LLVM::ConstantOp::fold(ArrayRef<Attribute>) { return getValue(); }
|
|
|
|
|
2019-10-11 06:13:25 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
// Utility functions for parsing atomic ops
|
2020-01-17 21:09:53 +01:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
// Helper function to parse a keyword into the specified attribute named by
|
|
|
|
// `attrName`. The keyword must match one of the string values defined by the
|
|
|
|
// AtomicBinOp enum. The resulting I64 attribute is added to the `result`
|
|
|
|
// state.
|
|
|
|
static ParseResult parseAtomicBinOp(OpAsmParser &parser, OperationState &result,
|
|
|
|
StringRef attrName) {
|
2022-01-26 15:49:53 -08:00
|
|
|
SMLoc loc;
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
StringRef keyword;
|
|
|
|
if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&keyword))
|
2020-01-17 21:09:53 +01:00
|
|
|
return failure();
|
|
|
|
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
// Replace the keyword `keyword` with an integer attribute.
|
|
|
|
auto kind = symbolizeAtomicBinOp(keyword);
|
|
|
|
if (!kind) {
|
|
|
|
return parser.emitError(loc)
|
|
|
|
<< "'" << keyword << "' is an incorrect value of the '" << attrName
|
|
|
|
<< "' attribute";
|
|
|
|
}
|
|
|
|
|
|
|
|
auto value = static_cast<int64_t>(kind.getValue());
|
|
|
|
auto attr = parser.getBuilder().getI64IntegerAttr(value);
|
|
|
|
result.addAttribute(attrName, attr);
|
2020-01-17 21:09:53 +01:00
|
|
|
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helper function to parse a keyword into the specified attribute named by
|
|
|
|
// `attrName`. The keyword must match one of the string values defined by the
|
|
|
|
// AtomicOrdering enum. The resulting I64 attribute is added to the `result`
|
|
|
|
// state.
|
|
|
|
static ParseResult parseAtomicOrdering(OpAsmParser &parser,
|
|
|
|
OperationState &result,
|
|
|
|
StringRef attrName) {
|
2022-01-26 15:49:53 -08:00
|
|
|
SMLoc loc;
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
StringRef ordering;
|
|
|
|
if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&ordering))
|
2020-01-17 21:09:53 +01:00
|
|
|
return failure();
|
|
|
|
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
// Replace the keyword `ordering` with an integer attribute.
|
|
|
|
auto kind = symbolizeAtomicOrdering(ordering);
|
|
|
|
if (!kind) {
|
|
|
|
return parser.emitError(loc)
|
|
|
|
<< "'" << ordering << "' is an incorrect value of the '" << attrName
|
|
|
|
<< "' attribute";
|
2020-01-17 21:09:53 +01:00
|
|
|
}
|
|
|
|
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
auto value = static_cast<int64_t>(kind.getValue());
|
|
|
|
auto attr = parser.getBuilder().getI64IntegerAttr(value);
|
|
|
|
result.addAttribute(attrName, attr);
|
2020-01-17 21:09:53 +01:00
|
|
|
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
return success();
|
|
|
|
}
|
2020-01-17 21:09:53 +01:00
|
|
|
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printer, parser and verifier for LLVM::AtomicRMWOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
2020-01-17 21:09:53 +01:00
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
void AtomicRMWOp::print(OpAsmPrinter &p) {
|
|
|
|
p << ' ' << stringifyAtomicBinOp(getBinOp()) << ' ' << getPtr() << ", "
|
|
|
|
<< getVal() << ' ' << stringifyAtomicOrdering(getOrdering()) << ' ';
|
|
|
|
p.printOptionalAttrDict((*this)->getAttrs(), {"bin_op", "ordering"});
|
|
|
|
p << " : " << getRes().getType();
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.atomicrmw` keyword ssa-use `,` ssa-use keyword
|
|
|
|
// attribute-dict? `:` type
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult AtomicRMWOp::parse(OpAsmParser &parser, OperationState &result) {
|
2021-01-05 16:22:53 +01:00
|
|
|
Type type;
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
OpAsmParser::OperandType ptr, val;
|
|
|
|
if (parseAtomicBinOp(parser, result, "bin_op") || parser.parseOperand(ptr) ||
|
|
|
|
parser.parseComma() || parser.parseOperand(val) ||
|
|
|
|
parseAtomicOrdering(parser, result, "ordering") ||
|
|
|
|
parser.parseOptionalAttrDict(result.attributes) ||
|
|
|
|
parser.parseColonType(type) ||
|
2020-12-22 11:22:21 +01:00
|
|
|
parser.resolveOperand(ptr, LLVM::LLVMPointerType::get(type),
|
|
|
|
result.operands) ||
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
parser.resolveOperand(val, type, result.operands))
|
|
|
|
return failure();
|
|
|
|
|
|
|
|
result.addTypes(type);
|
2020-01-17 21:09:53 +01:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult AtomicRMWOp::verify() {
|
|
|
|
auto ptrType = getPtr().getType().cast<LLVM::LLVMPointerType>();
|
|
|
|
auto valType = getVal().getType();
|
2020-12-22 11:22:21 +01:00
|
|
|
if (valType != ptrType.getElementType())
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError("expected LLVM IR element type for operand #0 to "
|
|
|
|
"match type for operand #1");
|
|
|
|
auto resType = getRes().getType();
|
2020-01-17 21:09:53 +01:00
|
|
|
if (resType != valType)
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError(
|
2020-01-17 21:09:53 +01:00
|
|
|
"expected LLVM IR result type to match type for operand #1");
|
2022-02-02 10:16:28 -08:00
|
|
|
if (getBinOp() == AtomicBinOp::fadd || getBinOp() == AtomicBinOp::fsub) {
|
2020-12-22 11:22:21 +01:00
|
|
|
if (!mlir::LLVM::isCompatibleFloatingPointType(valType))
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError("expected LLVM IR floating point type");
|
|
|
|
} else if (getBinOp() == AtomicBinOp::xchg) {
|
[mlir] replace LLVMIntegerType with built-in integer type
The LLVM dialect type system has been closed until now, i.e. did not support
types from other dialects inside containers. While this has had obvious
benefits of deriving from a common base class, it has led to some simple types
being almost identical with the built-in types, namely integer and floating
point types. This in turn has led to a lot of larger-scale complexity: simple
types must still be converted, numerous operations that correspond to LLVM IR
intrinsics are replicated to produce versions operating on either LLVM dialect
or built-in types leading to quasi-duplicate dialects, lowering to the LLVM
dialect is essentially required to be one-shot because of type conversion, etc.
In this light, it is reasonable to trade off some local complexity in the
internal implementation of LLVM dialect types for removing larger-scale system
complexity. Previous commits to the LLVM dialect type system have adapted the
API to support types from other dialects.
Replace LLVMIntegerType with the built-in IntegerType plus additional checks
that such types are signless (these are isolated in a utility function that
replaced `isa<LLVMType>` and in the parser). Temporarily keep the possibility
to parse `!llvm.i32` as a synonym for `i32`, but add a deprecation notice.
Reviewed By: mehdi_amini, silvas, antiagainst
Differential Revision: https://reviews.llvm.org/D94178
2021-01-06 16:19:04 +01:00
|
|
|
auto intType = valType.dyn_cast<IntegerType>();
|
|
|
|
unsigned intBitWidth = intType ? intType.getWidth() : 0;
|
2020-12-22 11:22:21 +01:00
|
|
|
if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 &&
|
[mlir] replace LLVM dialect float types with built-ins
Continue the convergence between LLVM dialect and built-in types by replacing
the bfloat, half, float and double LLVM dialect types with their built-in
counterparts. At the API level, this is a direct replacement. At the syntax
level, we change the keywords to `bf16`, `f16`, `f32` and `f64`, respectively,
to be compatible with the built-in type syntax. The old keywords can still be
parsed but produce a deprecation warning and will be eventually removed.
Depends On D94178
Reviewed By: mehdi_amini, silvas, antiagainst
Differential Revision: https://reviews.llvm.org/D94179
2021-01-06 16:21:08 +01:00
|
|
|
intBitWidth != 64 && !valType.isa<BFloat16Type>() &&
|
|
|
|
!valType.isa<Float16Type>() && !valType.isa<Float32Type>() &&
|
|
|
|
!valType.isa<Float64Type>())
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError("unexpected LLVM IR type for 'xchg' bin_op");
|
2020-01-17 21:09:53 +01:00
|
|
|
} else {
|
[mlir] replace LLVMIntegerType with built-in integer type
The LLVM dialect type system has been closed until now, i.e. did not support
types from other dialects inside containers. While this has had obvious
benefits of deriving from a common base class, it has led to some simple types
being almost identical with the built-in types, namely integer and floating
point types. This in turn has led to a lot of larger-scale complexity: simple
types must still be converted, numerous operations that correspond to LLVM IR
intrinsics are replicated to produce versions operating on either LLVM dialect
or built-in types leading to quasi-duplicate dialects, lowering to the LLVM
dialect is essentially required to be one-shot because of type conversion, etc.
In this light, it is reasonable to trade off some local complexity in the
internal implementation of LLVM dialect types for removing larger-scale system
complexity. Previous commits to the LLVM dialect type system have adapted the
API to support types from other dialects.
Replace LLVMIntegerType with the built-in IntegerType plus additional checks
that such types are signless (these are isolated in a utility function that
replaced `isa<LLVMType>` and in the parser). Temporarily keep the possibility
to parse `!llvm.i32` as a synonym for `i32`, but add a deprecation notice.
Reviewed By: mehdi_amini, silvas, antiagainst
Differential Revision: https://reviews.llvm.org/D94178
2021-01-06 16:19:04 +01:00
|
|
|
auto intType = valType.dyn_cast<IntegerType>();
|
|
|
|
unsigned intBitWidth = intType ? intType.getWidth() : 0;
|
2020-12-22 11:22:21 +01:00
|
|
|
if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 &&
|
|
|
|
intBitWidth != 64)
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError("expected LLVM IR integer type");
|
2020-01-17 21:09:53 +01:00
|
|
|
}
|
2021-02-16 17:36:20 +01:00
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
if (static_cast<unsigned>(getOrdering()) <
|
2021-02-16 17:36:20 +01:00
|
|
|
static_cast<unsigned>(AtomicOrdering::monotonic))
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError() << "expected at least '"
|
|
|
|
<< stringifyAtomicOrdering(AtomicOrdering::monotonic)
|
|
|
|
<< "' ordering";
|
2021-02-16 17:36:20 +01:00
|
|
|
|
2020-01-17 21:09:53 +01:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
// Printer, parser and verifier for LLVM::AtomicCmpXchgOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
void AtomicCmpXchgOp::print(OpAsmPrinter &p) {
|
|
|
|
p << ' ' << getPtr() << ", " << getCmp() << ", " << getVal() << ' '
|
|
|
|
<< stringifyAtomicOrdering(getSuccessOrdering()) << ' '
|
|
|
|
<< stringifyAtomicOrdering(getFailureOrdering());
|
|
|
|
p.printOptionalAttrDict((*this)->getAttrs(),
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
{"success_ordering", "failure_ordering"});
|
2022-02-07 17:54:04 -08:00
|
|
|
p << " : " << getVal().getType();
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.cmpxchg` ssa-use `,` ssa-use `,` ssa-use
|
|
|
|
// keyword keyword attribute-dict? `:` type
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult AtomicCmpXchgOp::parse(OpAsmParser &parser,
|
|
|
|
OperationState &result) {
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
auto &builder = parser.getBuilder();
|
2021-01-05 16:22:53 +01:00
|
|
|
Type type;
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
OpAsmParser::OperandType ptr, cmp, val;
|
|
|
|
if (parser.parseOperand(ptr) || parser.parseComma() ||
|
|
|
|
parser.parseOperand(cmp) || parser.parseComma() ||
|
|
|
|
parser.parseOperand(val) ||
|
|
|
|
parseAtomicOrdering(parser, result, "success_ordering") ||
|
|
|
|
parseAtomicOrdering(parser, result, "failure_ordering") ||
|
|
|
|
parser.parseOptionalAttrDict(result.attributes) ||
|
|
|
|
parser.parseColonType(type) ||
|
2020-12-22 11:22:21 +01:00
|
|
|
parser.resolveOperand(ptr, LLVM::LLVMPointerType::get(type),
|
|
|
|
result.operands) ||
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
parser.resolveOperand(cmp, type, result.operands) ||
|
|
|
|
parser.resolveOperand(val, type, result.operands))
|
|
|
|
return failure();
|
|
|
|
|
[mlir] replace LLVMIntegerType with built-in integer type
The LLVM dialect type system has been closed until now, i.e. did not support
types from other dialects inside containers. While this has had obvious
benefits of deriving from a common base class, it has led to some simple types
being almost identical with the built-in types, namely integer and floating
point types. This in turn has led to a lot of larger-scale complexity: simple
types must still be converted, numerous operations that correspond to LLVM IR
intrinsics are replicated to produce versions operating on either LLVM dialect
or built-in types leading to quasi-duplicate dialects, lowering to the LLVM
dialect is essentially required to be one-shot because of type conversion, etc.
In this light, it is reasonable to trade off some local complexity in the
internal implementation of LLVM dialect types for removing larger-scale system
complexity. Previous commits to the LLVM dialect type system have adapted the
API to support types from other dialects.
Replace LLVMIntegerType with the built-in IntegerType plus additional checks
that such types are signless (these are isolated in a utility function that
replaced `isa<LLVMType>` and in the parser). Temporarily keep the possibility
to parse `!llvm.i32` as a synonym for `i32`, but add a deprecation notice.
Reviewed By: mehdi_amini, silvas, antiagainst
Differential Revision: https://reviews.llvm.org/D94178
2021-01-06 16:19:04 +01:00
|
|
|
auto boolType = IntegerType::get(builder.getContext(), 1);
|
2020-12-22 11:22:56 +01:00
|
|
|
auto resultType =
|
|
|
|
LLVMStructType::getLiteral(builder.getContext(), {type, boolType});
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
result.addTypes(resultType);
|
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult AtomicCmpXchgOp::verify() {
|
|
|
|
auto ptrType = getPtr().getType().cast<LLVM::LLVMPointerType>();
|
2020-12-22 11:22:21 +01:00
|
|
|
if (!ptrType)
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError("expected LLVM IR pointer type for operand #0");
|
|
|
|
auto cmpType = getCmp().getType();
|
|
|
|
auto valType = getVal().getType();
|
2020-12-22 11:22:21 +01:00
|
|
|
if (cmpType != ptrType.getElementType() || cmpType != valType)
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError("expected LLVM IR element type for operand #0 to "
|
|
|
|
"match type for all other operands");
|
[mlir] replace LLVMIntegerType with built-in integer type
The LLVM dialect type system has been closed until now, i.e. did not support
types from other dialects inside containers. While this has had obvious
benefits of deriving from a common base class, it has led to some simple types
being almost identical with the built-in types, namely integer and floating
point types. This in turn has led to a lot of larger-scale complexity: simple
types must still be converted, numerous operations that correspond to LLVM IR
intrinsics are replicated to produce versions operating on either LLVM dialect
or built-in types leading to quasi-duplicate dialects, lowering to the LLVM
dialect is essentially required to be one-shot because of type conversion, etc.
In this light, it is reasonable to trade off some local complexity in the
internal implementation of LLVM dialect types for removing larger-scale system
complexity. Previous commits to the LLVM dialect type system have adapted the
API to support types from other dialects.
Replace LLVMIntegerType with the built-in IntegerType plus additional checks
that such types are signless (these are isolated in a utility function that
replaced `isa<LLVMType>` and in the parser). Temporarily keep the possibility
to parse `!llvm.i32` as a synonym for `i32`, but add a deprecation notice.
Reviewed By: mehdi_amini, silvas, antiagainst
Differential Revision: https://reviews.llvm.org/D94178
2021-01-06 16:19:04 +01:00
|
|
|
auto intType = valType.dyn_cast<IntegerType>();
|
|
|
|
unsigned intBitWidth = intType ? intType.getWidth() : 0;
|
2020-12-22 11:22:21 +01:00
|
|
|
if (!valType.isa<LLVMPointerType>() && intBitWidth != 8 &&
|
|
|
|
intBitWidth != 16 && intBitWidth != 32 && intBitWidth != 64 &&
|
[mlir] replace LLVM dialect float types with built-ins
Continue the convergence between LLVM dialect and built-in types by replacing
the bfloat, half, float and double LLVM dialect types with their built-in
counterparts. At the API level, this is a direct replacement. At the syntax
level, we change the keywords to `bf16`, `f16`, `f32` and `f64`, respectively,
to be compatible with the built-in type syntax. The old keywords can still be
parsed but produce a deprecation warning and will be eventually removed.
Depends On D94178
Reviewed By: mehdi_amini, silvas, antiagainst
Differential Revision: https://reviews.llvm.org/D94179
2021-01-06 16:21:08 +01:00
|
|
|
!valType.isa<BFloat16Type>() && !valType.isa<Float16Type>() &&
|
|
|
|
!valType.isa<Float32Type>() && !valType.isa<Float64Type>())
|
2022-02-02 10:16:28 -08:00
|
|
|
return emitOpError("unexpected LLVM IR type");
|
|
|
|
if (getSuccessOrdering() < AtomicOrdering::monotonic ||
|
|
|
|
getFailureOrdering() < AtomicOrdering::monotonic)
|
|
|
|
return emitOpError("ordering must be at least 'monotonic'");
|
|
|
|
if (getFailureOrdering() == AtomicOrdering::release ||
|
|
|
|
getFailureOrdering() == AtomicOrdering::acq_rel)
|
|
|
|
return emitOpError("failure ordering cannot be 'release' or 'acq_rel'");
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2020-03-17 17:43:21 +01:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printer, parser and verifier for LLVM::FenceOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.fence` (`syncscope(`strAttr`)`)? keyword
|
|
|
|
// attribute-dict?
|
2022-02-07 17:54:04 -08:00
|
|
|
ParseResult FenceOp::parse(OpAsmParser &parser, OperationState &result) {
|
2020-03-17 17:43:21 +01:00
|
|
|
StringAttr sScope;
|
|
|
|
StringRef syncscopeKeyword = "syncscope";
|
|
|
|
if (!failed(parser.parseOptionalKeyword(syncscopeKeyword))) {
|
|
|
|
if (parser.parseLParen() ||
|
|
|
|
parser.parseAttribute(sScope, syncscopeKeyword, result.attributes) ||
|
|
|
|
parser.parseRParen())
|
|
|
|
return failure();
|
|
|
|
} else {
|
|
|
|
result.addAttribute(syncscopeKeyword,
|
|
|
|
parser.getBuilder().getStringAttr(""));
|
|
|
|
}
|
|
|
|
if (parseAtomicOrdering(parser, result, "ordering") ||
|
|
|
|
parser.parseOptionalAttrDict(result.attributes))
|
|
|
|
return failure();
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2022-02-07 17:54:04 -08:00
|
|
|
void FenceOp::print(OpAsmPrinter &p) {
|
2020-03-17 17:43:21 +01:00
|
|
|
StringRef syncscopeKeyword = "syncscope";
|
2021-08-28 03:03:15 +00:00
|
|
|
p << ' ';
|
2022-02-07 17:54:04 -08:00
|
|
|
if (!(*this)->getAttr(syncscopeKeyword).cast<StringAttr>().getValue().empty())
|
|
|
|
p << "syncscope(" << (*this)->getAttr(syncscopeKeyword) << ") ";
|
|
|
|
p << stringifyAtomicOrdering(getOrdering());
|
2020-03-17 17:43:21 +01:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:16:28 -08:00
|
|
|
LogicalResult FenceOp::verify() {
|
|
|
|
if (getOrdering() == AtomicOrdering::not_atomic ||
|
|
|
|
getOrdering() == AtomicOrdering::unordered ||
|
|
|
|
getOrdering() == AtomicOrdering::monotonic)
|
|
|
|
return emitOpError("can be given only acquire, release, acq_rel, "
|
|
|
|
"and seq_cst orderings");
|
2020-03-17 17:43:21 +01:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2022-01-05 20:34:01 -05:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Folder for LLVM::BitcastOp
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
OpFoldResult LLVM::BitcastOp::fold(ArrayRef<Attribute> operands) {
|
|
|
|
// bitcast(x : T0, T0) -> x
|
|
|
|
if (getArg().getType() == getType())
|
|
|
|
return getArg();
|
|
|
|
// bitcast(bitcast(x : T0, T1), T0) -> x
|
|
|
|
if (auto prev = getArg().getDefiningOp<BitcastOp>())
|
|
|
|
if (prev.getArg().getType() == getType())
|
|
|
|
return prev.getArg();
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Folder for LLVM::AddrSpaceCastOp
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
OpFoldResult LLVM::AddrSpaceCastOp::fold(ArrayRef<Attribute> operands) {
|
|
|
|
// addrcast(x : T0, T0) -> x
|
|
|
|
if (getArg().getType() == getType())
|
|
|
|
return getArg();
|
|
|
|
// addrcast(addrcast(x : T0, T1), T0) -> x
|
|
|
|
if (auto prev = getArg().getDefiningOp<AddrSpaceCastOp>())
|
|
|
|
if (prev.getArg().getType() == getType())
|
|
|
|
return prev.getArg();
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Folder for LLVM::GEPOp
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
OpFoldResult LLVM::GEPOp::fold(ArrayRef<Attribute> operands) {
|
|
|
|
// gep %x:T, 0 -> %x
|
|
|
|
if (getBase().getType() == getType() && getIndices().size() == 1 &&
|
|
|
|
matchPattern(getIndices()[0], m_Zero()))
|
|
|
|
return getBase();
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
[MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.
This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).
Reviewers: ftynse, nicolasvasilache
Reviewed By: ftynse
Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 00:22:01 -08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-04-02 15:33:54 -07:00
|
|
|
// LLVMDialect initialization, type parsing, and registration.
|
|
|
|
//===----------------------------------------------------------------------===//
|
2019-01-15 10:53:22 -08:00
|
|
|
|
2020-08-07 02:41:44 +00:00
|
|
|
void LLVMDialect::initialize() {
|
2021-09-03 21:18:39 +00:00
|
|
|
addAttributes<FMFAttr, LinkageAttr, LoopOptionsAttr>();
|
2021-01-07 13:56:37 +01:00
|
|
|
|
2020-08-04 11:37:50 +02:00
|
|
|
// clang-format off
|
|
|
|
addTypes<LLVMVoidType,
|
|
|
|
LLVMPPCFP128Type,
|
|
|
|
LLVMX86MMXType,
|
|
|
|
LLVMTokenType,
|
|
|
|
LLVMLabelType,
|
|
|
|
LLVMMetadataType,
|
|
|
|
LLVMFunctionType,
|
|
|
|
LLVMPointerType,
|
|
|
|
LLVMFixedVectorType,
|
|
|
|
LLVMScalableVectorType,
|
|
|
|
LLVMArrayType,
|
|
|
|
LLVMStructType>();
|
|
|
|
// clang-format on
|
2019-01-15 10:53:22 -08:00
|
|
|
addOperations<
|
2019-03-20 17:25:34 -07:00
|
|
|
#define GET_OP_LIST
|
2019-08-19 11:00:47 -07:00
|
|
|
#include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc"
|
2019-01-15 10:53:22 -08:00
|
|
|
>();
|
2019-03-31 23:30:22 -07:00
|
|
|
|
|
|
|
// Support unknown operations because not all LLVM operations are registered.
|
|
|
|
allowUnknownOperations();
|
2019-02-25 13:16:24 -08:00
|
|
|
}
|
|
|
|
|
2019-03-20 17:25:34 -07:00
|
|
|
#define GET_OP_CLASSES
|
2019-08-19 11:00:47 -07:00
|
|
|
#include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc"
|
2019-03-20 17:25:34 -07:00
|
|
|
|
2019-02-25 13:16:24 -08:00
|
|
|
/// Parse a type registered to this dialect.
|
2019-11-01 15:39:30 -07:00
|
|
|
Type LLVMDialect::parseType(DialectAsmParser &parser) const {
|
2020-08-04 11:37:50 +02:00
|
|
|
return detail::parseType(parser);
|
2019-02-25 13:16:24 -08:00
|
|
|
}
|
2019-01-15 10:53:22 -08:00
|
|
|
|
2019-02-25 13:16:24 -08:00
|
|
|
/// Print a type registered to this dialect.
|
2019-11-01 14:47:42 -07:00
|
|
|
void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const {
|
2021-01-05 16:22:53 +01:00
|
|
|
return detail::printType(type, os);
|
2019-01-15 10:53:22 -08:00
|
|
|
}
|
|
|
|
|
2020-08-17 13:35:27 +02:00
|
|
|
LogicalResult LLVMDialect::verifyDataLayoutString(
|
|
|
|
StringRef descr, llvm::function_ref<void(const Twine &)> reportError) {
|
|
|
|
llvm::Expected<llvm::DataLayout> maybeDataLayout =
|
|
|
|
llvm::DataLayout::parse(descr);
|
|
|
|
if (maybeDataLayout)
|
|
|
|
return success();
|
|
|
|
|
|
|
|
std::string message;
|
|
|
|
llvm::raw_string_ostream messageStream(message);
|
|
|
|
llvm::logAllUnhandledErrors(maybeDataLayout.takeError(), messageStream);
|
|
|
|
reportError("invalid data layout descriptor: " + messageStream.str());
|
|
|
|
return failure();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Verify LLVM dialect attributes.
|
|
|
|
LogicalResult LLVMDialect::verifyOperationAttribute(Operation *op,
|
|
|
|
NamedAttribute attr) {
|
2021-03-04 09:00:18 +01:00
|
|
|
// If the `llvm.loop` attribute is present, enforce the following structure,
|
|
|
|
// which the module translation can assume.
|
2021-11-18 05:23:32 +00:00
|
|
|
if (attr.getName() == LLVMDialect::getLoopAttrName()) {
|
|
|
|
auto loopAttr = attr.getValue().dyn_cast<DictionaryAttr>();
|
2021-03-04 09:00:18 +01:00
|
|
|
if (!loopAttr)
|
|
|
|
return op->emitOpError() << "expected '" << LLVMDialect::getLoopAttrName()
|
|
|
|
<< "' to be a dictionary attribute";
|
|
|
|
Optional<NamedAttribute> parallelAccessGroup =
|
|
|
|
loopAttr.getNamed(LLVMDialect::getParallelAccessAttrName());
|
|
|
|
if (parallelAccessGroup.hasValue()) {
|
2021-11-18 05:23:32 +00:00
|
|
|
auto accessGroups = parallelAccessGroup->getValue().dyn_cast<ArrayAttr>();
|
2021-03-04 09:00:18 +01:00
|
|
|
if (!accessGroups)
|
|
|
|
return op->emitOpError()
|
|
|
|
<< "expected '" << LLVMDialect::getParallelAccessAttrName()
|
|
|
|
<< "' to be an array attribute";
|
|
|
|
for (Attribute attr : accessGroups) {
|
|
|
|
auto accessGroupRef = attr.dyn_cast<SymbolRefAttr>();
|
|
|
|
if (!accessGroupRef)
|
|
|
|
return op->emitOpError()
|
|
|
|
<< "expected '" << attr << "' to be a symbol reference";
|
2021-08-29 14:22:24 -07:00
|
|
|
StringAttr metadataName = accessGroupRef.getRootReference();
|
2021-03-04 09:00:18 +01:00
|
|
|
auto metadataOp =
|
|
|
|
SymbolTable::lookupNearestSymbolFrom<LLVM::MetadataOp>(
|
|
|
|
op->getParentOp(), metadataName);
|
|
|
|
if (!metadataOp)
|
|
|
|
return op->emitOpError()
|
|
|
|
<< "expected '" << attr << "' to reference a metadata op";
|
2021-08-29 14:22:24 -07:00
|
|
|
StringAttr accessGroupName = accessGroupRef.getLeafReference();
|
2021-03-04 09:00:18 +01:00
|
|
|
Operation *accessGroupOp =
|
|
|
|
SymbolTable::lookupNearestSymbolFrom(metadataOp, accessGroupName);
|
|
|
|
if (!accessGroupOp)
|
|
|
|
return op->emitOpError()
|
|
|
|
<< "expected '" << attr << "' to reference an access_group op";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Optional<NamedAttribute> loopOptions =
|
|
|
|
loopAttr.getNamed(LLVMDialect::getLoopOptionsAttrName());
|
2021-11-18 05:23:32 +00:00
|
|
|
if (loopOptions.hasValue() &&
|
|
|
|
!loopOptions->getValue().isa<LoopOptionsAttr>())
|
2021-03-06 05:24:55 +00:00
|
|
|
return op->emitOpError()
|
|
|
|
<< "expected '" << LLVMDialect::getLoopOptionsAttrName()
|
|
|
|
<< "' to be a `loopopts` attribute";
|
2021-03-04 09:00:18 +01:00
|
|
|
}
|
|
|
|
|
2022-03-15 15:22:31 +01:00
|
|
|
if (attr.getName() == LLVMDialect::getStructAttrsAttrName()) {
|
|
|
|
return op->emitOpError()
|
|
|
|
<< "'" << LLVM::LLVMDialect::getStructAttrsAttrName()
|
|
|
|
<< "' is permitted only in argument or result attributes";
|
|
|
|
}
|
|
|
|
|
2020-08-17 13:35:27 +02:00
|
|
|
// If the data layout attribute is present, it must use the LLVM data layout
|
|
|
|
// syntax. Try parsing it and report errors in case of failure. Users of this
|
|
|
|
// attribute may assume it is well-formed and can pass it to the (asserting)
|
|
|
|
// llvm::DataLayout constructor.
|
2021-11-18 05:23:32 +00:00
|
|
|
if (attr.getName() != LLVM::LLVMDialect::getDataLayoutAttrName())
|
2020-08-17 13:35:27 +02:00
|
|
|
return success();
|
2021-11-18 05:23:32 +00:00
|
|
|
if (auto stringAttr = attr.getValue().dyn_cast<StringAttr>())
|
2020-08-17 13:35:27 +02:00
|
|
|
return verifyDataLayoutString(
|
|
|
|
stringAttr.getValue(),
|
|
|
|
[op](const Twine &message) { op->emitOpError() << message.str(); });
|
|
|
|
|
|
|
|
return op->emitOpError() << "expected '"
|
|
|
|
<< LLVM::LLVMDialect::getDataLayoutAttrName()
|
|
|
|
<< "' to be a string attribute";
|
|
|
|
}
|
|
|
|
|
2022-03-15 15:22:31 +01:00
|
|
|
LogicalResult LLVMDialect::verifyStructAttr(Operation *op, Attribute attr,
|
|
|
|
Type annotatedType) {
|
|
|
|
auto structType = annotatedType.dyn_cast<LLVMStructType>();
|
|
|
|
if (!structType) {
|
|
|
|
const auto emitIncorrectAnnotatedType = [&op]() {
|
|
|
|
return op->emitError()
|
|
|
|
<< "expected '" << LLVMDialect::getStructAttrsAttrName()
|
|
|
|
<< "' to annotate '!llvm.struct' or '!llvm.ptr<struct<...>>'";
|
|
|
|
};
|
|
|
|
const auto ptrType = annotatedType.dyn_cast<LLVMPointerType>();
|
|
|
|
if (!ptrType)
|
|
|
|
return emitIncorrectAnnotatedType();
|
|
|
|
structType = ptrType.getElementType().dyn_cast<LLVMStructType>();
|
|
|
|
if (!structType)
|
|
|
|
return emitIncorrectAnnotatedType();
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto arrAttrs = attr.dyn_cast<ArrayAttr>();
|
|
|
|
if (!arrAttrs)
|
|
|
|
return op->emitError() << "expected '"
|
|
|
|
<< LLVMDialect::getStructAttrsAttrName()
|
|
|
|
<< "' to be an array attribute";
|
|
|
|
|
|
|
|
if (structType.getBody().size() != arrAttrs.size())
|
|
|
|
return op->emitError()
|
|
|
|
<< "size of '" << LLVMDialect::getStructAttrsAttrName()
|
|
|
|
<< "' must match the size of the annotated '!llvm.struct'";
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
static LogicalResult verifyFuncOpInterfaceStructAttr(
|
|
|
|
Operation *op, Attribute attr,
|
|
|
|
std::function<Type(FunctionOpInterface)> getAnnotatedType) {
|
|
|
|
if (auto funcOp = dyn_cast<FunctionOpInterface>(op))
|
|
|
|
return LLVMDialect::verifyStructAttr(op, attr, getAnnotatedType(funcOp));
|
|
|
|
return op->emitError() << "expected '"
|
|
|
|
<< LLVMDialect::getStructAttrsAttrName()
|
|
|
|
<< "' to be used on function-like operations";
|
|
|
|
}
|
|
|
|
|
2019-03-06 09:34:53 -08:00
|
|
|
/// Verify LLVMIR function argument attributes.
|
2019-07-11 15:05:19 -07:00
|
|
|
LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op,
|
|
|
|
unsigned regionIdx,
|
|
|
|
unsigned argIdx,
|
|
|
|
NamedAttribute argAttr) {
|
2021-05-11 15:18:42 +05:30
|
|
|
// Check that llvm.noalias is a unit attribute.
|
2021-11-18 05:23:32 +00:00
|
|
|
if (argAttr.getName() == LLVMDialect::getNoAliasAttrName() &&
|
|
|
|
!argAttr.getValue().isa<UnitAttr>())
|
2019-07-11 15:05:19 -07:00
|
|
|
return op->emitError()
|
2021-05-11 15:18:42 +05:30
|
|
|
<< "expected llvm.noalias argument attribute to be a unit attribute";
|
2020-06-19 10:59:07 +02:00
|
|
|
// Check that llvm.align is an integer attribute.
|
2021-11-18 05:23:32 +00:00
|
|
|
if (argAttr.getName() == LLVMDialect::getAlignAttrName() &&
|
|
|
|
!argAttr.getValue().isa<IntegerAttr>())
|
2020-06-19 10:59:07 +02:00
|
|
|
return op->emitError()
|
|
|
|
<< "llvm.align argument attribute of non integer type";
|
2022-03-15 15:22:31 +01:00
|
|
|
if (argAttr.getName() == LLVMDialect::getStructAttrsAttrName()) {
|
|
|
|
return verifyFuncOpInterfaceStructAttr(
|
|
|
|
op, argAttr.getValue(), [argIdx](FunctionOpInterface funcOp) {
|
|
|
|
return funcOp.getArgumentTypes()[argIdx];
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
LogicalResult LLVMDialect::verifyRegionResultAttribute(Operation *op,
|
|
|
|
unsigned regionIdx,
|
|
|
|
unsigned resIdx,
|
|
|
|
NamedAttribute resAttr) {
|
|
|
|
if (resAttr.getName() == LLVMDialect::getStructAttrsAttrName()) {
|
|
|
|
return verifyFuncOpInterfaceStructAttr(
|
|
|
|
op, resAttr.getValue(), [resIdx](FunctionOpInterface funcOp) {
|
|
|
|
return funcOp.getResultTypes()[resIdx];
|
|
|
|
});
|
|
|
|
}
|
2019-04-02 14:02:32 -07:00
|
|
|
return success();
|
2019-03-06 09:34:53 -08:00
|
|
|
}
|
|
|
|
|
2019-08-20 07:51:32 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Utility functions.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-12-23 14:45:01 -08:00
|
|
|
Value mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder,
|
|
|
|
StringRef name, StringRef value,
|
2020-08-06 00:52:20 +02:00
|
|
|
LLVM::Linkage linkage) {
|
2019-08-20 07:51:32 -07:00
|
|
|
assert(builder.getInsertionBlock() &&
|
|
|
|
builder.getInsertionBlock()->getParentOp() &&
|
2019-10-20 00:11:03 -07:00
|
|
|
"expected builder to point to a block constrained in an op");
|
2019-08-20 07:51:32 -07:00
|
|
|
auto module =
|
|
|
|
builder.getInsertionBlock()->getParentOp()->getParentOfType<ModuleOp>();
|
|
|
|
assert(module && "builder points to an op outside of a module");
|
|
|
|
|
|
|
|
// Create the global at the entry of the module.
|
2021-01-13 20:17:52 +01:00
|
|
|
OpBuilder moduleBuilder(module.getBodyRegion(), builder.getListener());
|
2020-08-06 00:52:20 +02:00
|
|
|
MLIRContext *ctx = builder.getContext();
|
[mlir] replace LLVMIntegerType with built-in integer type
The LLVM dialect type system has been closed until now, i.e. did not support
types from other dialects inside containers. While this has had obvious
benefits of deriving from a common base class, it has led to some simple types
being almost identical with the built-in types, namely integer and floating
point types. This in turn has led to a lot of larger-scale complexity: simple
types must still be converted, numerous operations that correspond to LLVM IR
intrinsics are replicated to produce versions operating on either LLVM dialect
or built-in types leading to quasi-duplicate dialects, lowering to the LLVM
dialect is essentially required to be one-shot because of type conversion, etc.
In this light, it is reasonable to trade off some local complexity in the
internal implementation of LLVM dialect types for removing larger-scale system
complexity. Previous commits to the LLVM dialect type system have adapted the
API to support types from other dialects.
Replace LLVMIntegerType with the built-in IntegerType plus additional checks
that such types are signless (these are isolated in a utility function that
replaced `isa<LLVMType>` and in the parser). Temporarily keep the possibility
to parse `!llvm.i32` as a synonym for `i32`, but add a deprecation notice.
Reviewed By: mehdi_amini, silvas, antiagainst
Differential Revision: https://reviews.llvm.org/D94178
2021-01-06 16:19:04 +01:00
|
|
|
auto type = LLVM::LLVMArrayType::get(IntegerType::get(ctx, 8), value.size());
|
2019-08-20 07:51:32 -07:00
|
|
|
auto global = moduleBuilder.create<LLVM::GlobalOp>(
|
2019-12-02 03:27:38 -08:00
|
|
|
loc, type, /*isConstant=*/true, linkage, name,
|
2021-05-12 08:45:25 +02:00
|
|
|
builder.getStringAttr(value), /*alignment=*/0);
|
2019-08-20 07:51:32 -07:00
|
|
|
|
|
|
|
// Get the pointer to the first character in the global string.
|
2019-12-23 14:45:01 -08:00
|
|
|
Value globalPtr = builder.create<LLVM::AddressOfOp>(loc, global);
|
|
|
|
Value cst0 = builder.create<LLVM::ConstantOp>(
|
[mlir] replace LLVMIntegerType with built-in integer type
The LLVM dialect type system has been closed until now, i.e. did not support
types from other dialects inside containers. While this has had obvious
benefits of deriving from a common base class, it has led to some simple types
being almost identical with the built-in types, namely integer and floating
point types. This in turn has led to a lot of larger-scale complexity: simple
types must still be converted, numerous operations that correspond to LLVM IR
intrinsics are replicated to produce versions operating on either LLVM dialect
or built-in types leading to quasi-duplicate dialects, lowering to the LLVM
dialect is essentially required to be one-shot because of type conversion, etc.
In this light, it is reasonable to trade off some local complexity in the
internal implementation of LLVM dialect types for removing larger-scale system
complexity. Previous commits to the LLVM dialect type system have adapted the
API to support types from other dialects.
Replace LLVMIntegerType with the built-in IntegerType plus additional checks
that such types are signless (these are isolated in a utility function that
replaced `isa<LLVMType>` and in the parser). Temporarily keep the possibility
to parse `!llvm.i32` as a synonym for `i32`, but add a deprecation notice.
Reviewed By: mehdi_amini, silvas, antiagainst
Differential Revision: https://reviews.llvm.org/D94178
2021-01-06 16:19:04 +01:00
|
|
|
loc, IntegerType::get(ctx, 64),
|
2019-08-20 07:51:32 -07:00
|
|
|
builder.getIntegerAttr(builder.getIndexType(), 0));
|
2020-12-22 11:22:56 +01:00
|
|
|
return builder.create<LLVM::GEPOp>(
|
[mlir] replace LLVMIntegerType with built-in integer type
The LLVM dialect type system has been closed until now, i.e. did not support
types from other dialects inside containers. While this has had obvious
benefits of deriving from a common base class, it has led to some simple types
being almost identical with the built-in types, namely integer and floating
point types. This in turn has led to a lot of larger-scale complexity: simple
types must still be converted, numerous operations that correspond to LLVM IR
intrinsics are replicated to produce versions operating on either LLVM dialect
or built-in types leading to quasi-duplicate dialects, lowering to the LLVM
dialect is essentially required to be one-shot because of type conversion, etc.
In this light, it is reasonable to trade off some local complexity in the
internal implementation of LLVM dialect types for removing larger-scale system
complexity. Previous commits to the LLVM dialect type system have adapted the
API to support types from other dialects.
Replace LLVMIntegerType with the built-in IntegerType plus additional checks
that such types are signless (these are isolated in a utility function that
replaced `isa<LLVMType>` and in the parser). Temporarily keep the possibility
to parse `!llvm.i32` as a synonym for `i32`, but add a deprecation notice.
Reviewed By: mehdi_amini, silvas, antiagainst
Differential Revision: https://reviews.llvm.org/D94178
2021-01-06 16:19:04 +01:00
|
|
|
loc, LLVM::LLVMPointerType::get(IntegerType::get(ctx, 8)), globalPtr,
|
2020-12-22 11:22:56 +01:00
|
|
|
ValueRange{cst0, cst0});
|
2019-08-20 07:51:32 -07:00
|
|
|
}
|
2019-12-16 01:35:03 -08:00
|
|
|
|
|
|
|
bool mlir::LLVM::satisfiesLLVMModule(Operation *op) {
|
|
|
|
return op->hasTrait<OpTrait::SymbolTable>() &&
|
|
|
|
op->hasTrait<OpTrait::IsIsolatedFromAbove>();
|
|
|
|
}
|
2021-01-07 13:56:37 +01:00
|
|
|
|
2021-10-20 15:14:54 +05:30
|
|
|
static constexpr const FastmathFlags fastmathFlagsList[] = {
|
2021-01-07 13:56:37 +01:00
|
|
|
// clang-format off
|
|
|
|
FastmathFlags::nnan,
|
|
|
|
FastmathFlags::ninf,
|
|
|
|
FastmathFlags::nsz,
|
|
|
|
FastmathFlags::arcp,
|
|
|
|
FastmathFlags::contract,
|
|
|
|
FastmathFlags::afn,
|
|
|
|
FastmathFlags::reassoc,
|
|
|
|
FastmathFlags::fast,
|
|
|
|
// clang-format on
|
|
|
|
};
|
|
|
|
|
2021-11-11 06:12:06 +00:00
|
|
|
void FMFAttr::print(AsmPrinter &printer) const {
|
2021-11-10 00:38:01 +00:00
|
|
|
printer << "<";
|
2021-10-20 15:14:54 +05:30
|
|
|
auto flags = llvm::make_filter_range(fastmathFlagsList, [&](auto flag) {
|
2021-01-07 17:42:55 +00:00
|
|
|
return bitEnumContains(this->getFlags(), flag);
|
2021-01-07 13:56:37 +01:00
|
|
|
});
|
|
|
|
llvm::interleaveComma(flags, printer,
|
|
|
|
[&](auto flag) { printer << stringifyEnum(flag); });
|
|
|
|
printer << ">";
|
|
|
|
}
|
|
|
|
|
2021-11-11 06:12:06 +00:00
|
|
|
Attribute FMFAttr::parse(AsmParser &parser, Type type) {
|
2021-01-07 13:56:37 +01:00
|
|
|
if (failed(parser.parseLess()))
|
|
|
|
return {};
|
|
|
|
|
|
|
|
FastmathFlags flags = {};
|
|
|
|
if (failed(parser.parseOptionalGreater())) {
|
|
|
|
do {
|
|
|
|
StringRef elemName;
|
|
|
|
if (failed(parser.parseKeyword(&elemName)))
|
|
|
|
return {};
|
|
|
|
|
|
|
|
auto elem = symbolizeFastmathFlags(elemName);
|
|
|
|
if (!elem) {
|
|
|
|
parser.emitError(parser.getNameLoc(), "Unknown fastmath flag: ")
|
|
|
|
<< elemName;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
flags = flags | *elem;
|
|
|
|
} while (succeeded(parser.parseOptionalComma()));
|
|
|
|
|
|
|
|
if (failed(parser.parseGreater()))
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2021-09-29 17:47:08 -07:00
|
|
|
return FMFAttr::get(parser.getContext(), flags);
|
2021-01-07 13:56:37 +01:00
|
|
|
}
|
|
|
|
|
2021-11-11 06:12:06 +00:00
|
|
|
void LinkageAttr::print(AsmPrinter &printer) const {
|
2021-11-10 00:38:01 +00:00
|
|
|
printer << "<";
|
2021-09-03 21:18:39 +00:00
|
|
|
if (static_cast<uint64_t>(getLinkage()) <= getMaxEnumValForLinkage())
|
|
|
|
printer << stringifyEnum(getLinkage());
|
|
|
|
else
|
|
|
|
printer << static_cast<uint64_t>(getLinkage());
|
|
|
|
printer << ">";
|
|
|
|
}
|
|
|
|
|
2021-11-11 06:12:06 +00:00
|
|
|
Attribute LinkageAttr::parse(AsmParser &parser, Type type) {
|
2021-09-03 21:18:39 +00:00
|
|
|
StringRef elemName;
|
|
|
|
if (parser.parseLess() || parser.parseKeyword(&elemName) ||
|
|
|
|
parser.parseGreater())
|
|
|
|
return {};
|
|
|
|
auto elem = linkage::symbolizeLinkage(elemName);
|
|
|
|
if (!elem) {
|
|
|
|
parser.emitError(parser.getNameLoc(), "Unknown linkage: ") << elemName;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
Linkage linkage = *elem;
|
2021-09-29 17:47:08 -07:00
|
|
|
return LinkageAttr::get(parser.getContext(), linkage);
|
2021-09-03 21:18:39 +00:00
|
|
|
}
|
|
|
|
|
2021-03-06 05:24:55 +00:00
|
|
|
LoopOptionsAttrBuilder::LoopOptionsAttrBuilder(LoopOptionsAttr attr)
|
|
|
|
: options(attr.getOptions().begin(), attr.getOptions().end()) {}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
LoopOptionsAttrBuilder &LoopOptionsAttrBuilder::setOption(LoopOptionCase tag,
|
|
|
|
Optional<T> value) {
|
|
|
|
auto option = llvm::find_if(
|
|
|
|
options, [tag](auto option) { return option.first == tag; });
|
|
|
|
if (option != options.end()) {
|
|
|
|
if (value.hasValue())
|
|
|
|
option->second = *value;
|
|
|
|
else
|
|
|
|
options.erase(option);
|
|
|
|
} else {
|
|
|
|
options.push_back(LoopOptionsAttr::OptionValuePair(tag, *value));
|
|
|
|
}
|
|
|
|
return *this;
|
2021-03-04 09:00:18 +01:00
|
|
|
}
|
|
|
|
|
2021-03-09 21:03:20 +00:00
|
|
|
LoopOptionsAttrBuilder &
|
|
|
|
LoopOptionsAttrBuilder::setDisableLICM(Optional<bool> value) {
|
|
|
|
return setOption(LoopOptionCase::disable_licm, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the `interleave_count` option to the provided value. If no value
|
|
|
|
/// is provided the option is deleted.
|
|
|
|
LoopOptionsAttrBuilder &
|
|
|
|
LoopOptionsAttrBuilder::setInterleaveCount(Optional<uint64_t> count) {
|
|
|
|
return setOption(LoopOptionCase::interleave_count, count);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the `disable_unroll` option to the provided value. If no value
|
|
|
|
/// is provided the option is deleted.
|
|
|
|
LoopOptionsAttrBuilder &
|
|
|
|
LoopOptionsAttrBuilder::setDisableUnroll(Optional<bool> value) {
|
|
|
|
return setOption(LoopOptionCase::disable_unroll, value);
|
|
|
|
}
|
|
|
|
|
2021-03-11 16:42:56 +01:00
|
|
|
/// Set the `disable_pipeline` option to the provided value. If no value
|
|
|
|
/// is provided the option is deleted.
|
|
|
|
LoopOptionsAttrBuilder &
|
|
|
|
LoopOptionsAttrBuilder::setDisablePipeline(Optional<bool> value) {
|
|
|
|
return setOption(LoopOptionCase::disable_pipeline, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the `pipeline_initiation_interval` option to the provided value.
|
|
|
|
/// If no value is provided the option is deleted.
|
|
|
|
LoopOptionsAttrBuilder &LoopOptionsAttrBuilder::setPipelineInitiationInterval(
|
|
|
|
Optional<uint64_t> count) {
|
|
|
|
return setOption(LoopOptionCase::pipeline_initiation_interval, count);
|
|
|
|
}
|
|
|
|
|
2021-03-06 05:24:55 +00:00
|
|
|
template <typename T>
|
|
|
|
static Optional<T>
|
|
|
|
getOption(ArrayRef<std::pair<LoopOptionCase, int64_t>> options,
|
|
|
|
LoopOptionCase option) {
|
|
|
|
auto it =
|
|
|
|
lower_bound(options, option, [](auto optionPair, LoopOptionCase option) {
|
|
|
|
return optionPair.first < option;
|
|
|
|
});
|
|
|
|
if (it == options.end())
|
|
|
|
return {};
|
|
|
|
return static_cast<T>(it->second);
|
2021-03-04 09:00:18 +01:00
|
|
|
}
|
|
|
|
|
2021-03-06 05:24:55 +00:00
|
|
|
Optional<bool> LoopOptionsAttr::disableUnroll() {
|
|
|
|
return getOption<bool>(getOptions(), LoopOptionCase::disable_unroll);
|
2021-03-04 09:00:18 +01:00
|
|
|
}
|
|
|
|
|
2021-03-06 05:24:55 +00:00
|
|
|
Optional<bool> LoopOptionsAttr::disableLICM() {
|
|
|
|
return getOption<bool>(getOptions(), LoopOptionCase::disable_licm);
|
2021-03-04 09:00:18 +01:00
|
|
|
}
|
|
|
|
|
2021-03-06 05:24:55 +00:00
|
|
|
Optional<int64_t> LoopOptionsAttr::interleaveCount() {
|
|
|
|
return getOption<int64_t>(getOptions(), LoopOptionCase::interleave_count);
|
2021-03-04 09:00:18 +01:00
|
|
|
}
|
|
|
|
|
2021-03-06 05:24:55 +00:00
|
|
|
/// Build the LoopOptions Attribute from a sorted array of individual options.
|
|
|
|
LoopOptionsAttr LoopOptionsAttr::get(
|
|
|
|
MLIRContext *context,
|
|
|
|
ArrayRef<std::pair<LoopOptionCase, int64_t>> sortedOptions) {
|
|
|
|
assert(llvm::is_sorted(sortedOptions, llvm::less_first()) &&
|
|
|
|
"LoopOptionsAttr ctor expects a sorted options array");
|
|
|
|
return Base::get(context, sortedOptions);
|
2021-03-04 09:00:18 +01:00
|
|
|
}
|
|
|
|
|
2021-03-06 05:24:55 +00:00
|
|
|
/// Build the LoopOptions Attribute from a sorted array of individual options.
|
|
|
|
LoopOptionsAttr LoopOptionsAttr::get(MLIRContext *context,
|
|
|
|
LoopOptionsAttrBuilder &optionBuilders) {
|
|
|
|
llvm::sort(optionBuilders.options, llvm::less_first());
|
|
|
|
return Base::get(context, optionBuilders.options);
|
|
|
|
}
|
|
|
|
|
2021-11-11 06:12:06 +00:00
|
|
|
void LoopOptionsAttr::print(AsmPrinter &printer) const {
|
2021-11-10 00:38:01 +00:00
|
|
|
printer << "<";
|
2021-03-06 05:24:55 +00:00
|
|
|
llvm::interleaveComma(getOptions(), printer, [&](auto option) {
|
2021-03-09 21:59:35 +00:00
|
|
|
printer << stringifyEnum(option.first) << " = ";
|
2021-03-06 05:24:55 +00:00
|
|
|
switch (option.first) {
|
|
|
|
case LoopOptionCase::disable_licm:
|
|
|
|
case LoopOptionCase::disable_unroll:
|
2021-03-11 16:42:56 +01:00
|
|
|
case LoopOptionCase::disable_pipeline:
|
2021-03-06 05:24:55 +00:00
|
|
|
printer << (option.second ? "true" : "false");
|
|
|
|
break;
|
|
|
|
case LoopOptionCase::interleave_count:
|
2021-03-11 16:42:56 +01:00
|
|
|
case LoopOptionCase::pipeline_initiation_interval:
|
2021-03-06 05:24:55 +00:00
|
|
|
printer << option.second;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
2021-03-04 09:00:18 +01:00
|
|
|
printer << ">";
|
|
|
|
}
|
|
|
|
|
2021-11-11 06:12:06 +00:00
|
|
|
Attribute LoopOptionsAttr::parse(AsmParser &parser, Type type) {
|
2021-03-04 09:00:18 +01:00
|
|
|
if (failed(parser.parseLess()))
|
|
|
|
return {};
|
|
|
|
|
2021-03-06 05:24:55 +00:00
|
|
|
SmallVector<std::pair<LoopOptionCase, int64_t>> options;
|
|
|
|
llvm::SmallDenseSet<LoopOptionCase> seenOptions;
|
|
|
|
do {
|
|
|
|
StringRef optionName;
|
|
|
|
if (parser.parseKeyword(&optionName))
|
|
|
|
return {};
|
2021-03-04 09:00:18 +01:00
|
|
|
|
2021-03-06 05:24:55 +00:00
|
|
|
auto option = symbolizeLoopOptionCase(optionName);
|
|
|
|
if (!option) {
|
|
|
|
parser.emitError(parser.getNameLoc(), "unknown loop option: ")
|
|
|
|
<< optionName;
|
2021-03-04 09:00:18 +01:00
|
|
|
return {};
|
|
|
|
}
|
2021-03-06 05:24:55 +00:00
|
|
|
if (!seenOptions.insert(*option).second) {
|
|
|
|
parser.emitError(parser.getNameLoc(), "loop option present twice");
|
2021-03-04 09:00:18 +01:00
|
|
|
return {};
|
|
|
|
}
|
2021-03-06 05:24:55 +00:00
|
|
|
if (failed(parser.parseEqual()))
|
|
|
|
return {};
|
2021-03-04 09:00:18 +01:00
|
|
|
|
2021-03-06 05:24:55 +00:00
|
|
|
int64_t value;
|
|
|
|
switch (*option) {
|
|
|
|
case LoopOptionCase::disable_licm:
|
|
|
|
case LoopOptionCase::disable_unroll:
|
2021-03-11 16:42:56 +01:00
|
|
|
case LoopOptionCase::disable_pipeline:
|
2021-03-06 05:24:55 +00:00
|
|
|
if (succeeded(parser.parseOptionalKeyword("true")))
|
|
|
|
value = 1;
|
|
|
|
else if (succeeded(parser.parseOptionalKeyword("false")))
|
|
|
|
value = 0;
|
|
|
|
else {
|
|
|
|
parser.emitError(parser.getNameLoc(),
|
|
|
|
"expected boolean value 'true' or 'false'");
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LoopOptionCase::interleave_count:
|
2021-03-11 16:42:56 +01:00
|
|
|
case LoopOptionCase::pipeline_initiation_interval:
|
2021-03-06 05:24:55 +00:00
|
|
|
if (failed(parser.parseInteger(value))) {
|
|
|
|
parser.emitError(parser.getNameLoc(), "expected integer value");
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
options.push_back(std::make_pair(*option, value));
|
|
|
|
} while (succeeded(parser.parseOptionalComma()));
|
2021-03-04 09:00:18 +01:00
|
|
|
if (failed(parser.parseGreater()))
|
|
|
|
return {};
|
|
|
|
|
2021-03-06 05:24:55 +00:00
|
|
|
llvm::sort(options, llvm::less_first());
|
2021-09-29 17:47:08 -07:00
|
|
|
return get(parser.getContext(), options);
|
2021-03-04 09:00:18 +01:00
|
|
|
}
|