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"
|
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"
|
|
|
|
|
2020-03-01 01:11:12 +00:00
|
|
|
#include "llvm/ADT/StringSwitch.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"
|
|
|
|
|
|
|
|
using namespace mlir;
|
|
|
|
using namespace mlir::LLVM;
|
|
|
|
|
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"
|
2019-07-15 05:45:08 -07:00
|
|
|
|
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
|
|
|
//===----------------------------------------------------------------------===//
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printICmpOp(OpAsmPrinter &p, ICmpOp &op) {
|
|
|
|
p << op.getOperationName() << " \"" << stringifyICmpPredicate(op.predicate())
|
2020-01-11 08:54:04 -08:00
|
|
|
<< "\" " << op.getOperand(0) << ", " << op.getOperand(1);
|
2019-09-20 20:43:02 -07:00
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"predicate"});
|
2020-01-11 08:54:04 -08:00
|
|
|
p << " : " << op.lhs().getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printFCmpOp(OpAsmPrinter &p, FCmpOp &op) {
|
|
|
|
p << op.getOperationName() << " \"" << stringifyFCmpPredicate(op.predicate())
|
2020-01-11 08:54:04 -08:00
|
|
|
<< "\" " << op.getOperand(0) << ", " << op.getOperand(1);
|
2019-09-20 20:43:02 -07:00
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"predicate"});
|
2020-01-11 08:54:04 -08:00
|
|
|
p << " : " << op.lhs().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;
|
|
|
|
llvm::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.
|
2020-12-22 11:22:56 +01:00
|
|
|
LLVMType resultType = LLVMIntegerType::get(builder.getContext(), 1);
|
2019-04-02 15:33:54 -07:00
|
|
|
auto argType = type.dyn_cast<LLVM::LLVMType>();
|
|
|
|
if (!argType)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(trailingTypeLoc, "expected LLVM IR dialect type");
|
2020-12-22 11:22:21 +01:00
|
|
|
if (auto vecArgType = argType.dyn_cast<LLVM::LLVMFixedVectorType>())
|
2020-12-22 11:22:56 +01:00
|
|
|
resultType =
|
|
|
|
LLVMFixedVectorType::get(resultType, vecArgType.getNumElements());
|
2020-12-22 11:22:21 +01:00
|
|
|
assert(!argType.isa<LLVM::LLVMScalableVectorType>() &&
|
|
|
|
"unhandled scalable vector");
|
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
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::AllocaOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printAllocaOp(OpAsmPrinter &p, AllocaOp &op) {
|
2020-12-22 11:22:21 +01:00
|
|
|
auto elemTy = op.getType().cast<LLVM::LLVMPointerType>().getElementType();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2020-12-17 12:24:45 -08:00
|
|
|
auto funcTy = FunctionType::get(op.getContext(), {op.arraySize().getType()},
|
|
|
|
{op.getType()});
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2020-01-11 08:54:04 -08:00
|
|
|
p << op.getOperationName() << ' ' << op.arraySize() << " x " << elemTy;
|
2020-09-01 13:32:14 -07:00
|
|
|
if (op.alignment().hasValue() && *op.alignment() != 0)
|
2019-09-20 20:43:02 -07:00
|
|
|
p.printOptionalAttrDict(op.getAttrs());
|
2019-08-18 18:54:50 -07:00
|
|
|
else
|
2019-09-20 20:43:02 -07:00
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"alignment"});
|
|
|
|
p << " : " << funcTy;
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.alloca` ssa-use `x` type attribute-dict?
|
|
|
|
// `:` type `,` type
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseAllocaOp(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
OpAsmParser::OperandType arraySize;
|
|
|
|
Type type, elemType;
|
|
|
|
llvm::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()) {
|
|
|
|
auto alignmentInt = alignmentAttr.getValue().second.dyn_cast<IntegerAttr>();
|
|
|
|
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");
|
2020-04-29 16:09:43 -07:00
|
|
|
return destOperandsMutable();
|
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");
|
2020-04-29 16:09:43 -07:00
|
|
|
return index == 0 ? trueDestOperandsMutable() : falseDestOperandsMutable();
|
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) {
|
2020-12-22 02:19:31 +01:00
|
|
|
SmallVector<Value> flattenedCaseOperands;
|
|
|
|
SmallVector<int32_t> caseOperandOffsets;
|
[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
|
|
|
int32_t offset = 0;
|
|
|
|
for (ValueRange operands : caseOperands) {
|
|
|
|
flattenedCaseOperands.append(operands.begin(), operands.end());
|
|
|
|
caseOperandOffsets.push_back(offset);
|
|
|
|
offset += operands.size();
|
|
|
|
}
|
|
|
|
ElementsAttr caseValuesAttr;
|
|
|
|
if (!caseValues.empty())
|
|
|
|
caseValuesAttr = builder.getI32VectorAttr(caseValues);
|
|
|
|
ElementsAttr caseOperandOffsetsAttr;
|
|
|
|
if (!caseOperandOffsets.empty())
|
|
|
|
caseOperandOffsetsAttr = builder.getI32VectorAttr(caseOperandOffsets);
|
|
|
|
|
|
|
|
ElementsAttr weightsAttr;
|
|
|
|
if (!branchWeights.empty())
|
|
|
|
weightsAttr = builder.getI32VectorAttr(llvm::to_vector<4>(branchWeights));
|
|
|
|
|
|
|
|
build(builder, result, value, defaultOperands, flattenedCaseOperands,
|
|
|
|
caseValuesAttr, caseOperandOffsetsAttr, weightsAttr, defaultDestination,
|
|
|
|
caseDestinations);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <cases> ::= integer `:` bb-id (`(` ssa-use-and-type-list `)`)?
|
|
|
|
/// ( `,` integer `:` bb-id (`(` ssa-use-and-type-list `)`)? )?
|
|
|
|
static ParseResult
|
|
|
|
parseSwitchOpCases(OpAsmParser &parser, ElementsAttr &caseValues,
|
|
|
|
SmallVectorImpl<Block *> &caseDestinations,
|
|
|
|
SmallVectorImpl<OpAsmParser::OperandType> &caseOperands,
|
|
|
|
SmallVectorImpl<Type> &caseOperandTypes,
|
|
|
|
ElementsAttr &caseOperandOffsets) {
|
2020-12-22 02:19:31 +01:00
|
|
|
SmallVector<int32_t> values;
|
|
|
|
SmallVector<int32_t> offsets;
|
[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
|
|
|
int32_t value, offset = 0;
|
|
|
|
do {
|
|
|
|
OptionalParseResult integerParseResult = parser.parseOptionalInteger(value);
|
|
|
|
if (values.empty() && !integerParseResult.hasValue())
|
|
|
|
return success();
|
|
|
|
|
|
|
|
if (!integerParseResult.hasValue() || integerParseResult.getValue())
|
|
|
|
return failure();
|
|
|
|
values.push_back(value);
|
|
|
|
|
|
|
|
Block *destination;
|
2020-12-22 02:19:31 +01:00
|
|
|
SmallVector<OpAsmParser::OperandType> operands;
|
[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) ||
|
|
|
|
parser.parseColonTypeList(caseOperandTypes) || parser.parseRParen())
|
|
|
|
return failure();
|
|
|
|
}
|
|
|
|
caseDestinations.push_back(destination);
|
|
|
|
caseOperands.append(operands.begin(), operands.end());
|
|
|
|
offsets.push_back(offset);
|
|
|
|
offset += operands.size();
|
|
|
|
} while (!parser.parseOptionalComma());
|
|
|
|
|
|
|
|
Builder &builder = parser.getBuilder();
|
|
|
|
caseValues = builder.getI32VectorAttr(values);
|
|
|
|
caseOperandOffsets = builder.getI32VectorAttr(offsets);
|
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void printSwitchOpCases(OpAsmPrinter &p, SwitchOp op,
|
|
|
|
ElementsAttr caseValues,
|
|
|
|
SuccessorRange caseDestinations,
|
|
|
|
OperandRange caseOperands,
|
|
|
|
TypeRange caseOperandTypes,
|
|
|
|
ElementsAttr caseOperandOffsets) {
|
|
|
|
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 << ": ";
|
|
|
|
p.printSuccessorAndUseList(std::get<1>(i), op.getCaseOperands(index++));
|
|
|
|
},
|
|
|
|
[&] {
|
|
|
|
p << ',';
|
|
|
|
p.printNewline();
|
|
|
|
});
|
|
|
|
p.printNewline();
|
|
|
|
}
|
|
|
|
|
|
|
|
static LogicalResult verify(SwitchOp op) {
|
|
|
|
if ((!op.case_values() && !op.caseDestinations().empty()) ||
|
|
|
|
(op.case_values() &&
|
|
|
|
op.case_values()->size() !=
|
|
|
|
static_cast<int64_t>(op.caseDestinations().size())))
|
|
|
|
return op.emitOpError("expects number of case values to match number of "
|
|
|
|
"case destinations");
|
|
|
|
if (op.branch_weights() &&
|
|
|
|
op.branch_weights()->size() != op.getNumSuccessors())
|
|
|
|
return op.emitError("expects number of branch weights to match number of "
|
|
|
|
"successors: ")
|
|
|
|
<< op.branch_weights()->size() << " vs " << op.getNumSuccessors();
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
OperandRange SwitchOp::getCaseOperands(unsigned index) {
|
|
|
|
return getCaseOperandsMutable(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
MutableOperandRange SwitchOp::getCaseOperandsMutable(unsigned index) {
|
|
|
|
MutableOperandRange caseOperands = caseOperandsMutable();
|
|
|
|
if (!case_operand_offsets()) {
|
|
|
|
assert(caseOperands.size() == 0 &&
|
|
|
|
"non-empty case operands must have offsets");
|
|
|
|
return caseOperands;
|
|
|
|
}
|
|
|
|
|
|
|
|
ElementsAttr offsets = case_operand_offsets().getValue();
|
|
|
|
assert(index < offsets.size() && "invalid case operand offset index");
|
|
|
|
|
|
|
|
int64_t begin = offsets.getValue(index).cast<IntegerAttr>().getInt();
|
|
|
|
int64_t end = index + 1 == offsets.size()
|
|
|
|
? caseOperands.size()
|
|
|
|
: offsets.getValue(index + 1).cast<IntegerAttr>().getInt();
|
|
|
|
return caseOperandsMutable().slice(begin, end - begin);
|
|
|
|
}
|
|
|
|
|
|
|
|
Optional<MutableOperandRange>
|
|
|
|
SwitchOp::getMutableSuccessorOperands(unsigned index) {
|
|
|
|
assert(index < getNumSuccessors() && "invalid successor index");
|
|
|
|
return index == 0 ? defaultOperandsMutable()
|
|
|
|
: getCaseOperandsMutable(index - 1);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printLoadOp(OpAsmPrinter &p, LoadOp &op) {
|
2020-07-27 10:19:48 +03:00
|
|
|
p << op.getOperationName() << ' ';
|
|
|
|
if (op.volatile_())
|
|
|
|
p << "volatile ";
|
|
|
|
p << op.addr();
|
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {kVolatileAttrName});
|
2020-01-11 08:54:04 -08:00
|
|
|
p << " : " << op.addr().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,
|
2019-04-02 15:33:54 -07:00
|
|
|
llvm::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
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseLoadOp(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
OpAsmParser::OperandType addr;
|
|
|
|
Type type;
|
|
|
|
llvm::SMLoc trailingTypeLoc;
|
|
|
|
|
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
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printStoreOp(OpAsmPrinter &p, StoreOp &op) {
|
2020-07-27 10:19:48 +03:00
|
|
|
p << op.getOperationName() << ' ';
|
|
|
|
if (op.volatile_())
|
|
|
|
p << "volatile ";
|
|
|
|
p << op.value() << ", " << op.addr();
|
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {kVolatileAttrName});
|
2020-01-11 08:54:04 -08:00
|
|
|
p << " : " << op.addr().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
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseStoreOp(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
OpAsmParser::OperandType addr, value;
|
|
|
|
Type type;
|
|
|
|
llvm::SMLoc trailingTypeLoc;
|
|
|
|
|
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");
|
2020-04-29 16:09:43 -07:00
|
|
|
return index == 0 ? normalDestOperandsMutable() : unwindDestOperandsMutable();
|
2020-03-05 12:40:23 -08:00
|
|
|
}
|
|
|
|
|
2020-01-30 12:50:12 +01:00
|
|
|
static LogicalResult verify(InvokeOp op) {
|
|
|
|
if (op.getNumResults() > 1)
|
|
|
|
return op.emitOpError("must have 0 or 1 result");
|
|
|
|
|
2020-02-21 13:19:50 -08:00
|
|
|
Block *unwindDest = op.unwindDest();
|
|
|
|
if (unwindDest->empty())
|
2020-01-30 12:50:12 +01:00
|
|
|
return op.emitError(
|
|
|
|
"must have at least one operation in unwind destination");
|
|
|
|
|
|
|
|
// In unwind destination, first operation must be LandingpadOp
|
2020-02-21 13:19:50 -08:00
|
|
|
if (!isa<LandingpadOp>(unwindDest->front()))
|
2020-01-30 12:50:12 +01:00
|
|
|
return op.emitError("first operation in unwind destination should be a "
|
|
|
|
"llvm.landingpad operation");
|
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2020-03-05 12:48:28 -08:00
|
|
|
static void printInvokeOp(OpAsmPrinter &p, InvokeOp op) {
|
2020-01-30 12:50:12 +01:00
|
|
|
auto callee = op.callee();
|
|
|
|
bool isDirect = callee.hasValue();
|
|
|
|
|
|
|
|
p << op.getOperationName() << ' ';
|
|
|
|
|
|
|
|
// Either function name or pointer
|
|
|
|
if (isDirect)
|
|
|
|
p.printSymbolName(callee.getValue());
|
|
|
|
else
|
|
|
|
p << op.getOperand(0);
|
|
|
|
|
|
|
|
p << '(' << op.getOperands().drop_front(isDirect ? 0 : 1) << ')';
|
|
|
|
p << " to ";
|
2020-03-05 12:48:28 -08:00
|
|
|
p.printSuccessorAndUseList(op.normalDest(), op.normalDestOperands());
|
2020-01-30 12:50:12 +01:00
|
|
|
p << " unwind ";
|
2020-03-05 12:48:28 -08:00
|
|
|
p.printSuccessorAndUseList(op.unwindDest(), op.unwindDestOperands());
|
|
|
|
|
|
|
|
p.printOptionalAttrDict(op.getAttrs(),
|
|
|
|
{InvokeOp::getOperandSegmentSizeAttr(), "callee"});
|
|
|
|
p << " : ";
|
|
|
|
p.printFunctionalType(
|
|
|
|
llvm::drop_begin(op.getOperandTypes(), isDirect ? 0 : 1),
|
|
|
|
op.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
|
|
|
|
static ParseResult parseInvokeOp(OpAsmParser &parser, OperationState &result) {
|
|
|
|
SmallVector<OpAsmParser::OperandType, 8> operands;
|
|
|
|
FunctionType funcType;
|
|
|
|
SymbolRefAttr funcAttr;
|
|
|
|
llvm::SMLoc trailingTypeLoc;
|
|
|
|
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");
|
|
|
|
|
|
|
|
LLVM::LLVMType llvmResultType;
|
|
|
|
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 {
|
|
|
|
llvmResultType = funcType.getResult(0).dyn_cast<LLVM::LLVMType>();
|
|
|
|
if (!llvmResultType)
|
|
|
|
return parser.emitError(trailingTypeLoc,
|
|
|
|
"expected result to have LLVM type");
|
|
|
|
}
|
|
|
|
|
|
|
|
SmallVector<LLVM::LLVMType, 8> argTypes;
|
|
|
|
argTypes.reserve(funcType.getNumInputs());
|
|
|
|
for (Type ty : funcType.getInputs()) {
|
|
|
|
if (auto argType = ty.dyn_cast<LLVM::LLVMType>())
|
|
|
|
argTypes.push_back(argType);
|
|
|
|
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.
|
|
|
|
///===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
static LogicalResult verify(LandingpadOp op) {
|
|
|
|
Value value;
|
2020-12-09 11:50:18 +01:00
|
|
|
if (LLVMFuncOp func = op->getParentOfType<LLVMFuncOp>()) {
|
2020-03-19 13:09:31 +01:00
|
|
|
if (!func.personality().hasValue())
|
|
|
|
return op.emitError(
|
|
|
|
"llvm.landingpad needs to be in a function with a personality");
|
|
|
|
}
|
2020-01-30 12:50:12 +01:00
|
|
|
|
|
|
|
if (!op.cleanup() && op.getOperands().empty())
|
|
|
|
return op.emitError("landingpad instruction expects at least one clause or "
|
|
|
|
"cleanup attribute");
|
|
|
|
|
|
|
|
for (unsigned idx = 0, ie = op.getNumOperands(); idx < ie; idx++) {
|
|
|
|
value = op.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>()) {
|
|
|
|
if (auto addrOp = bcOp.arg().getDefiningOp<AddressOfOp>())
|
2020-01-30 12:50:12 +01:00
|
|
|
continue;
|
|
|
|
return op.emitError("constant clauses expected")
|
|
|
|
.attachNote(bcOp.getLoc())
|
|
|
|
<< "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;
|
|
|
|
return op.emitError("clause #")
|
|
|
|
<< idx << " is not a known constant - null, addressof, bitcast";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void printLandingpadOp(OpAsmPrinter &p, LandingpadOp &op) {
|
|
|
|
p << op.getOperationName() << (op.cleanup() ? " cleanup " : " ");
|
|
|
|
|
|
|
|
// Clauses
|
|
|
|
for (auto value : op.getOperands()) {
|
|
|
|
// 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() << ") ";
|
|
|
|
}
|
|
|
|
|
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"cleanup"});
|
|
|
|
|
|
|
|
p << ": " << op.getType();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <operation> ::= `llvm.landingpad` `cleanup`?
|
|
|
|
/// ((`catch` | `filter`) operand-type ssa-use)* attribute-dict?
|
|
|
|
static ParseResult parseLandingpadOp(OpAsmParser &parser,
|
|
|
|
OperationState &result) {
|
|
|
|
// 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
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-10-03 03:30:21 +00:00
|
|
|
static LogicalResult verify(CallOp &op) {
|
|
|
|
if (op.getNumResults() > 1)
|
|
|
|
return op.emitOpError("must have 0 or 1 result");
|
|
|
|
|
|
|
|
// Type for the callee, we'll get it differently depending if it is a direct
|
|
|
|
// or indirect call.
|
|
|
|
LLVMType fnType;
|
|
|
|
|
|
|
|
bool isIndirect = false;
|
|
|
|
|
|
|
|
// If this is an indirect call, the callee attribute is missing.
|
|
|
|
Optional<StringRef> calleeName = op.callee();
|
|
|
|
if (!calleeName) {
|
|
|
|
isIndirect = true;
|
|
|
|
if (!op.getNumOperands())
|
|
|
|
return op.emitOpError(
|
|
|
|
"must have either a `callee` attribute or at least an operand");
|
|
|
|
fnType = op.getOperand(0).getType().dyn_cast<LLVMType>();
|
|
|
|
if (!fnType)
|
|
|
|
return op.emitOpError("indirect call to a non-llvm type: ")
|
|
|
|
<< op.getOperand(0).getType();
|
|
|
|
auto ptrType = fnType.dyn_cast<LLVMPointerType>();
|
|
|
|
if (!ptrType)
|
|
|
|
return op.emitOpError("indirect call expects a pointer as callee: ")
|
|
|
|
<< fnType;
|
|
|
|
fnType = ptrType.getElementType();
|
|
|
|
} else {
|
|
|
|
Operation *callee = SymbolTable::lookupNearestSymbolFrom(op, *calleeName);
|
|
|
|
if (!callee)
|
|
|
|
return op.emitOpError()
|
|
|
|
<< "'" << *calleeName
|
|
|
|
<< "' does not reference a symbol in the current scope";
|
|
|
|
auto fn = dyn_cast<LLVMFuncOp>(callee);
|
|
|
|
if (!fn)
|
|
|
|
return op.emitOpError() << "'" << *calleeName
|
|
|
|
<< "' does not reference a valid LLVM function";
|
|
|
|
|
|
|
|
fnType = fn.getType();
|
|
|
|
}
|
2020-12-22 11:22:21 +01:00
|
|
|
|
|
|
|
LLVMFunctionType funcType = fnType.dyn_cast<LLVMFunctionType>();
|
|
|
|
if (!funcType)
|
2020-10-03 03:30:21 +00:00
|
|
|
return op.emitOpError("callee does not have a functional type: ") << fnType;
|
|
|
|
|
|
|
|
// Verify that the operand and result types match the callee.
|
|
|
|
|
2020-12-22 11:22:21 +01:00
|
|
|
if (!funcType.isVarArg() &&
|
|
|
|
funcType.getNumParams() != (op.getNumOperands() - isIndirect))
|
2020-10-03 03:30:21 +00:00
|
|
|
return op.emitOpError()
|
|
|
|
<< "incorrect number of operands ("
|
|
|
|
<< (op.getNumOperands() - isIndirect)
|
2020-12-22 11:22:21 +01:00
|
|
|
<< ") for callee (expecting: " << funcType.getNumParams() << ")";
|
2020-10-03 03:30:21 +00:00
|
|
|
|
2020-12-22 11:22:21 +01:00
|
|
|
if (funcType.getNumParams() > (op.getNumOperands() - isIndirect))
|
2020-10-03 03:30:21 +00:00
|
|
|
return op.emitOpError() << "incorrect number of operands ("
|
|
|
|
<< (op.getNumOperands() - isIndirect)
|
|
|
|
<< ") for varargs callee (expecting at least: "
|
2020-12-22 11:22:21 +01:00
|
|
|
<< 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)
|
|
|
|
if (op.getOperand(i + isIndirect).getType() != funcType.getParamType(i))
|
2020-10-03 03:30:21 +00:00
|
|
|
return op.emitOpError() << "operand type mismatch for operand " << i
|
|
|
|
<< ": " << op.getOperand(i + isIndirect).getType()
|
2020-12-22 11:22:21 +01:00
|
|
|
<< " != " << funcType.getParamType(i);
|
2020-10-03 03:30:21 +00:00
|
|
|
|
|
|
|
if (op.getNumResults() &&
|
2020-12-22 11:22:21 +01:00
|
|
|
op.getResult(0).getType() != funcType.getReturnType())
|
2020-10-03 03:30:21 +00:00
|
|
|
return op.emitOpError()
|
|
|
|
<< "result type mismatch: " << op.getResult(0).getType()
|
2020-12-22 11:22:21 +01:00
|
|
|
<< " != " << funcType.getReturnType();
|
2020-10-03 03:30:21 +00:00
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printCallOp(OpAsmPrinter &p, CallOp &op) {
|
2019-04-02 15:33:54 -07:00
|
|
|
auto callee = op.callee();
|
|
|
|
bool isDirect = callee.hasValue();
|
|
|
|
|
|
|
|
// Print the direct callee if present as a function attribute, or an indirect
|
|
|
|
// callee (first operand) otherwise.
|
2019-09-20 20:43:02 -07:00
|
|
|
p << op.getOperationName() << ' ';
|
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
|
2020-01-11 08:54:04 -08:00
|
|
|
p << op.getOperand(0);
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2020-08-04 11:46:26 -07:00
|
|
|
auto args = op.getOperands().drop_front(isDirect ? 0 : 1);
|
|
|
|
p << '(' << args << ')';
|
2019-09-20 20:43:02 -07:00
|
|
|
p.printOptionalAttrDict(op.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.
|
2020-01-27 19:57:14 -08:00
|
|
|
p << " : "
|
2020-12-17 12:24:45 -08:00
|
|
|
<< FunctionType::get(op.getContext(), args.getTypes(), op.getResultTypes());
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.call` (function-id | ssa-use) `(` ssa-use-list `)`
|
|
|
|
// attribute-dict? `:` function-type
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseCallOp(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;
|
2019-05-29 13:33:22 -07:00
|
|
|
llvm::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");
|
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();
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes(funcType.getResults());
|
2019-04-02 15:33:54 -07:00
|
|
|
} else {
|
|
|
|
// Construct the LLVM IR Dialect function type that the first operand
|
|
|
|
// should match.
|
|
|
|
if (funcType.getNumResults() > 1)
|
2019-09-20 11:36:49 -07:00
|
|
|
return parser.emitError(trailingTypeLoc,
|
|
|
|
"expected function with 0 or 1 result");
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
Builder &builder = parser.getBuilder();
|
2019-05-22 14:56:07 -07:00
|
|
|
LLVM::LLVMType 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 {
|
2019-05-22 14:56:07 -07:00
|
|
|
llvmResultType = funcType.getResult(0).dyn_cast<LLVM::LLVMType>();
|
|
|
|
if (!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
|
|
|
}
|
|
|
|
|
2019-05-22 14:56:07 -07:00
|
|
|
SmallVector<LLVM::LLVMType, 8> argTypes;
|
2019-04-02 15:33:54 -07:00
|
|
|
argTypes.reserve(funcType.getNumInputs());
|
|
|
|
for (int i = 0, e = funcType.getNumInputs(); i < e; ++i) {
|
|
|
|
auto argType = funcType.getInput(i).dyn_cast<LLVM::LLVMType>();
|
|
|
|
if (!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
|
|
|
|
2019-09-20 19:47:05 -07:00
|
|
|
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) {
|
2020-12-22 11:22:21 +01:00
|
|
|
auto vectorType = vector.getType().cast<LLVM::LLVMVectorType>();
|
|
|
|
auto llvmType = vectorType.getElementType();
|
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
|
|
|
}
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printExtractElementOp(OpAsmPrinter &p, ExtractElementOp &op) {
|
2020-01-11 08:54:04 -08:00
|
|
|
p << op.getOperationName() << ' ' << op.vector() << "[" << op.position()
|
|
|
|
<< " : " << op.position().getType() << "]";
|
2019-09-20 20:43:02 -07:00
|
|
|
p.printOptionalAttrDict(op.getAttrs());
|
2020-01-11 08:54:04 -08:00
|
|
|
p << " : " << op.vector().getType();
|
2019-08-09 05:24:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.extractelement` ssa-use `, ` ssa-use
|
|
|
|
// attribute-dict? `:` type
|
2019-09-20 11:36:49 -07:00
|
|
|
static ParseResult parseExtractElementOp(OpAsmParser &parser,
|
2019-09-20 19:47:05 -07:00
|
|
|
OperationState &result) {
|
2019-08-09 05:24:47 -07:00
|
|
|
llvm::SMLoc loc;
|
|
|
|
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();
|
2020-12-22 11:22:21 +01:00
|
|
|
auto vectorType = type.dyn_cast<LLVM::LLVMVectorType>();
|
|
|
|
if (!vectorType)
|
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");
|
2020-12-22 11:22:21 +01:00
|
|
|
result.addTypes(vectorType.getElementType());
|
2019-08-09 05:24:47 -07:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::ExtractValueOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printExtractValueOp(OpAsmPrinter &p, ExtractValueOp &op) {
|
2020-01-11 08:54:04 -08:00
|
|
|
p << op.getOperationName() << ' ' << op.container() << op.position();
|
2019-09-20 20:43:02 -07:00
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"position"});
|
2020-01-11 08:54:04 -08:00
|
|
|
p << " : " << op.container().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.
|
2019-09-20 11:36:49 -07:00
|
|
|
static LLVM::LLVMType getInsertExtractValueElementType(OpAsmParser &parser,
|
2019-04-02 15:33:54 -07:00
|
|
|
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,
|
2019-04-02 15:33:54 -07:00
|
|
|
llvm::SMLoc attributeLoc,
|
|
|
|
llvm::SMLoc typeLoc) {
|
2020-12-22 11:22:21 +01:00
|
|
|
auto llvmType = containerType.dyn_cast<LLVM::LLVMType>();
|
|
|
|
if (!llvmType)
|
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
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.extractvalue` ssa-use
|
|
|
|
// `[` integer-literal (`,` integer-literal)* `]`
|
|
|
|
// attribute-dict? `:` type
|
2019-09-20 11:36:49 -07:00
|
|
|
static ParseResult parseExtractValueOp(OpAsmParser &parser,
|
2019-09-20 19:47:05 -07:00
|
|
|
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;
|
2019-04-02 15:33:54 -07:00
|
|
|
llvm::SMLoc attributeLoc, trailingTypeLoc;
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2019-08-09 05:24:47 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::InsertElementOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printInsertElementOp(OpAsmPrinter &p, InsertElementOp &op) {
|
2020-01-11 08:54:04 -08:00
|
|
|
p << op.getOperationName() << ' ' << op.value() << ", " << op.vector() << "["
|
|
|
|
<< op.position() << " : " << op.position().getType() << "]";
|
2019-09-20 20:43:02 -07:00
|
|
|
p.printOptionalAttrDict(op.getAttrs());
|
2020-01-11 08:54:04 -08:00
|
|
|
p << " : " << op.vector().getType();
|
2019-08-09 05:24:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.insertelement` ssa-use `,` ssa-use `,` ssa-use
|
|
|
|
// attribute-dict? `:` type
|
2019-09-20 11:36:49 -07:00
|
|
|
static ParseResult parseInsertElementOp(OpAsmParser &parser,
|
2019-09-20 19:47:05 -07:00
|
|
|
OperationState &result) {
|
2019-08-09 05:24:47 -07:00
|
|
|
llvm::SMLoc loc;
|
|
|
|
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();
|
|
|
|
|
2020-12-22 11:22:21 +01:00
|
|
|
auto llvmVectorType = vectorType.dyn_cast<LLVM::LLVMVectorType>();
|
|
|
|
if (!llvmVectorType)
|
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");
|
2020-12-22 11:22:21 +01:00
|
|
|
Type valueType = llvmVectorType.getElementType();
|
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();
|
|
|
|
}
|
|
|
|
|
2019-04-02 15:33:54 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::InsertValueOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printInsertValueOp(OpAsmPrinter &p, InsertValueOp &op) {
|
2020-01-11 08:54:04 -08:00
|
|
|
p << op.getOperationName() << ' ' << op.value() << ", " << op.container()
|
2019-09-20 20:43:02 -07:00
|
|
|
<< op.position();
|
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"position"});
|
2020-01-11 08:54:04 -08:00
|
|
|
p << " : " << op.container().getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.insertvaluevalue` ssa-use `,` ssa-use
|
|
|
|
// `[` integer-literal (`,` integer-literal)* `]`
|
|
|
|
// attribute-dict? `:` type
|
2019-09-20 11:36:49 -07:00
|
|
|
static ParseResult parseInsertValueOp(OpAsmParser &parser,
|
2019-09-20 19:47:05 -07:00
|
|
|
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;
|
2019-04-02 15:33:54 -07:00
|
|
|
llvm::SMLoc attributeLoc, trailingTypeLoc;
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Printing/parsing for LLVM::ReturnOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printReturnOp(OpAsmPrinter &p, ReturnOp &op) {
|
|
|
|
p << op.getOperationName();
|
|
|
|
p.printOptionalAttrDict(op.getAttrs());
|
2019-04-02 15:33:54 -07:00
|
|
|
assert(op.getNumOperands() <= 1);
|
|
|
|
|
|
|
|
if (op.getNumOperands() == 0)
|
|
|
|
return;
|
|
|
|
|
2020-01-11 08:54:04 -08:00
|
|
|
p << ' ' << op.getOperand(0) << " : " << op.getOperand(0).getType();
|
2019-04-02 15:33:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.return` ssa-use-list attribute-dict? `:`
|
|
|
|
// type-list-no-parens
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseReturnOp(OpAsmParser &parser, OperationState &result) {
|
2019-04-02 15:33:54 -07:00
|
|
|
SmallVector<OpAsmParser::OperandType, 1> operands;
|
|
|
|
Type type;
|
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseOperandList(operands) ||
|
2019-11-05 13:32:07 -08:00
|
|
|
parser.parseOptionalAttrDict(result.attributes))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
2019-04-02 15:33:54 -07:00
|
|
|
if (operands.empty())
|
2019-05-06 22:01:31 -07:00
|
|
|
return success();
|
2019-04-02 15:33:54 -07:00
|
|
|
|
2019-09-20 11:36:49 -07:00
|
|
|
if (parser.parseColonType(type) ||
|
2019-09-20 19:47:05 -07:00
|
|
|
parser.resolveOperand(operands[0], type, result.operands))
|
2019-05-06 22:01:31 -07:00
|
|
|
return failure();
|
|
|
|
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(),
|
|
|
|
global_name());
|
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(),
|
|
|
|
global_name());
|
2019-08-12 06:10:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static LogicalResult verify(AddressOfOp op) {
|
|
|
|
auto global = op.getGlobal();
|
2020-06-29 12:16:23 +02:00
|
|
|
auto function = op.getFunction();
|
|
|
|
if (!global && !function)
|
|
|
|
return op.emitOpError(
|
|
|
|
"must reference a global defined by 'llvm.mlir.global' or 'llvm.func'");
|
|
|
|
|
2020-12-22 11:22:21 +01:00
|
|
|
if (global &&
|
|
|
|
LLVM::LLVMPointerType::get(global.getType(), global.addr_space()) !=
|
|
|
|
op.getResult().getType())
|
2019-09-03 09:10:24 -07:00
|
|
|
return op.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
|
|
|
|
2020-12-22 11:22:21 +01:00
|
|
|
if (function && LLVM::LLVMPointerType::get(function.getType()) !=
|
|
|
|
op.getResult().getType())
|
2019-08-12 06:10:29 -07:00
|
|
|
return op.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"; }
|
|
|
|
|
2020-04-23 16:02:46 +02:00
|
|
|
void GlobalOp::build(OpBuilder &builder, OperationState &result, LLVMType type,
|
2019-12-02 03:27:38 -08:00
|
|
|
bool isConstant, Linkage linkage, StringRef name,
|
2019-12-06 12:00:01 -08:00
|
|
|
Attribute value, unsigned addrSpace,
|
|
|
|
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));
|
2019-10-17 20:08:01 -07:00
|
|
|
result.addAttribute("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);
|
2020-04-23 16:02:46 +02:00
|
|
|
result.addAttribute(getLinkageAttrName(),
|
|
|
|
builder.getI64IntegerAttr(static_cast<int64_t>(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
|
|
|
}
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printGlobalOp(OpAsmPrinter &p, GlobalOp op) {
|
2020-01-24 17:51:10 +01:00
|
|
|
p << op.getOperationName() << ' ' << stringifyLinkage(op.linkage()) << ' ';
|
2019-08-09 05:01:23 -07:00
|
|
|
if (op.constant())
|
2019-09-20 20:43:02 -07:00
|
|
|
p << "constant ";
|
2019-10-08 17:44:39 -07:00
|
|
|
p.printSymbolName(op.sym_name());
|
|
|
|
p << '(';
|
2019-09-21 01:19:43 -07:00
|
|
|
if (auto value = op.getValueOrNull())
|
|
|
|
p.printAttribute(value);
|
2019-09-20 20:43:02 -07:00
|
|
|
p << ')';
|
2019-12-02 03:27:38 -08:00
|
|
|
p.printOptionalAttrDict(op.getAttrs(),
|
|
|
|
{SymbolTable::getSymbolAttrName(), "type", "constant",
|
2019-12-03 00:26:13 -08:00
|
|
|
"value", getLinkageAttrName()});
|
2019-08-09 08:59:45 -07:00
|
|
|
|
|
|
|
// Print the trailing type unless it's a string global.
|
2019-09-21 01:19:43 -07:00
|
|
|
if (op.getValueOrNull().dyn_cast_or_null<StringAttr>())
|
2019-08-09 08:59:45 -07:00
|
|
|
return;
|
2019-12-12 15:31:39 -08:00
|
|
|
p << " : " << op.type();
|
2019-11-05 15:10:28 -08:00
|
|
|
|
|
|
|
Region &initializer = op.getInitializerRegion();
|
|
|
|
if (!initializer.empty())
|
|
|
|
p.printRegion(initializer, /*printEntryBlockArgs=*/false);
|
2019-08-09 05:01:23 -07:00
|
|
|
}
|
|
|
|
|
[MLIR] Add llvm.mlir.cast op for semantic preserving cast between dialect types.
Summary: See discussion here: https://llvm.discourse.group/t/rfc-dialect-type-cast-op/538/11
Reviewers: ftynse
Subscribers: bixia, sanjoy.google, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, nicolasvasilache, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, Joonsoo, llvm-commits
Differential Revision: https://reviews.llvm.org/D75141
2020-02-21 18:13:56 -08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Verifier for LLVM::DialectCastOp.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
[mlir] Support index and memref types in llvm.mlir.cast
This operation is designed to support partial conversion, more specifically the
IR state in which some operations expect or produce built-in types and some
operations produce and expect LLVM dialect types. It is reasonable for it to
support cast between built-in types and any equivalent that could be produced
by the type conversion. (At the same time, we don't want the dialect to depend
on the type conversion as it could lead to a dependency cycle). Introduce
support for casting from index to any integer type and back, and from memref to
bare pointer or memref descriptor type and back.
Contrary to what the TODO in the code stated, there are no particular
precautions necessary to handle the bare pointer conversion for memerfs. This
conversion applies exclusively to statically-shaped memrefs, so we can always
recover the full descriptor contents from the type.
This patch simultaneously tightens the verification for other types to only
accept matching pairs of types, e.g., i64 and !llvm.i64, as opposed to the
previous implementation that only checked if the types were generally allowed
byt not for matching, e.g. i64 could be "casted" to !llvm.bfloat, which is not
the intended semantics.
Move the relevant test under test/Dialect/LLVMIR because it is not specific to
the conversion pass, but rather exercises an op in the dialect. If we decide
this op does not belong to the LLVM dialect, both the dialect and the op should
move together.
Reviewed By: silvas, ezhulenev
Differential Revision: https://reviews.llvm.org/D93405
2020-12-16 18:32:26 +01:00
|
|
|
/// Checks if `llvmType` is dialect cast-compatible with `index` type. Does not
|
|
|
|
/// report the error, the user is expected to produce an appropriate message.
|
|
|
|
// TODO: make the size depend on data layout rather than on the conversion
|
|
|
|
// pass option, and pull that information here.
|
|
|
|
static LogicalResult verifyCastWithIndex(LLVMType llvmType) {
|
|
|
|
return success(llvmType.isa<LLVMIntegerType>());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Checks if `llvmType` is dialect cast-compatible with built-in `type` and
|
|
|
|
/// reports errors to the location of `op`.
|
|
|
|
static LogicalResult verifyCast(DialectCastOp op, LLVMType llvmType,
|
|
|
|
Type type) {
|
|
|
|
// Index is compatible with any integer.
|
|
|
|
if (type.isIndex()) {
|
|
|
|
if (succeeded(verifyCastWithIndex(llvmType)))
|
|
|
|
return success();
|
|
|
|
|
|
|
|
return op.emitOpError("invalid cast between index and non-integer type");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Simple one-to-one mappings for floating point types.
|
|
|
|
if (type.isF16()) {
|
|
|
|
if (llvmType.isa<LLVMHalfType>())
|
|
|
|
return success();
|
|
|
|
return op.emitOpError(
|
|
|
|
"invalid cast between f16 and a type other than !llvm.half");
|
|
|
|
}
|
|
|
|
if (type.isBF16()) {
|
|
|
|
if (llvmType.isa<LLVMBFloatType>())
|
|
|
|
return success();
|
|
|
|
return op->emitOpError(
|
|
|
|
"invalid cast between bf16 and a type other than !llvm.bfloat");
|
|
|
|
}
|
|
|
|
if (type.isF32()) {
|
|
|
|
if (llvmType.isa<LLVMFloatType>())
|
|
|
|
return success();
|
|
|
|
return op->emitOpError(
|
|
|
|
"invalid cast between f32 and a type other than !llvm.float");
|
|
|
|
}
|
|
|
|
if (type.isF64()) {
|
|
|
|
if (llvmType.isa<LLVMDoubleType>())
|
|
|
|
return success();
|
|
|
|
return op->emitOpError(
|
|
|
|
"invalid cast between f64 and a type other than !llvm.double");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Singless integers are compatible with LLVM integer of the same bitwidth.
|
|
|
|
if (type.isSignlessInteger()) {
|
|
|
|
auto llvmInt = llvmType.dyn_cast<LLVMIntegerType>();
|
|
|
|
if (!llvmInt)
|
|
|
|
return op->emitOpError(
|
|
|
|
"invalid cast between integer and non-integer type");
|
|
|
|
if (llvmInt.getBitWidth() == type.getIntOrFloatBitWidth())
|
|
|
|
return success();
|
|
|
|
|
|
|
|
return op->emitOpError(
|
|
|
|
"invalid cast between integers with mismatching bitwidth");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Vectors are compatible if they are 1D non-scalable, and their element types
|
|
|
|
// are compatible.
|
|
|
|
if (auto vectorType = type.dyn_cast<VectorType>()) {
|
|
|
|
if (vectorType.getRank() != 1)
|
|
|
|
return op->emitOpError("only 1-d vector is allowed");
|
|
|
|
|
2020-12-22 11:22:21 +01:00
|
|
|
auto llvmVector = llvmType.dyn_cast<LLVMFixedVectorType>();
|
|
|
|
if (!llvmVector)
|
[mlir] Support index and memref types in llvm.mlir.cast
This operation is designed to support partial conversion, more specifically the
IR state in which some operations expect or produce built-in types and some
operations produce and expect LLVM dialect types. It is reasonable for it to
support cast between built-in types and any equivalent that could be produced
by the type conversion. (At the same time, we don't want the dialect to depend
on the type conversion as it could lead to a dependency cycle). Introduce
support for casting from index to any integer type and back, and from memref to
bare pointer or memref descriptor type and back.
Contrary to what the TODO in the code stated, there are no particular
precautions necessary to handle the bare pointer conversion for memerfs. This
conversion applies exclusively to statically-shaped memrefs, so we can always
recover the full descriptor contents from the type.
This patch simultaneously tightens the verification for other types to only
accept matching pairs of types, e.g., i64 and !llvm.i64, as opposed to the
previous implementation that only checked if the types were generally allowed
byt not for matching, e.g. i64 could be "casted" to !llvm.bfloat, which is not
the intended semantics.
Move the relevant test under test/Dialect/LLVMIR because it is not specific to
the conversion pass, but rather exercises an op in the dialect. If we decide
this op does not belong to the LLVM dialect, both the dialect and the op should
move together.
Reviewed By: silvas, ezhulenev
Differential Revision: https://reviews.llvm.org/D93405
2020-12-16 18:32:26 +01:00
|
|
|
return op->emitOpError("only fixed-sized vector is allowed");
|
|
|
|
|
2020-12-22 11:22:21 +01:00
|
|
|
if (vectorType.getDimSize(0) != llvmVector.getNumElements())
|
[mlir] Support index and memref types in llvm.mlir.cast
This operation is designed to support partial conversion, more specifically the
IR state in which some operations expect or produce built-in types and some
operations produce and expect LLVM dialect types. It is reasonable for it to
support cast between built-in types and any equivalent that could be produced
by the type conversion. (At the same time, we don't want the dialect to depend
on the type conversion as it could lead to a dependency cycle). Introduce
support for casting from index to any integer type and back, and from memref to
bare pointer or memref descriptor type and back.
Contrary to what the TODO in the code stated, there are no particular
precautions necessary to handle the bare pointer conversion for memerfs. This
conversion applies exclusively to statically-shaped memrefs, so we can always
recover the full descriptor contents from the type.
This patch simultaneously tightens the verification for other types to only
accept matching pairs of types, e.g., i64 and !llvm.i64, as opposed to the
previous implementation that only checked if the types were generally allowed
byt not for matching, e.g. i64 could be "casted" to !llvm.bfloat, which is not
the intended semantics.
Move the relevant test under test/Dialect/LLVMIR because it is not specific to
the conversion pass, but rather exercises an op in the dialect. If we decide
this op does not belong to the LLVM dialect, both the dialect and the op should
move together.
Reviewed By: silvas, ezhulenev
Differential Revision: https://reviews.llvm.org/D93405
2020-12-16 18:32:26 +01:00
|
|
|
return op->emitOpError(
|
|
|
|
"invalid cast between vectors with mismatching sizes");
|
|
|
|
|
|
|
|
return verifyCast(op, llvmVector.getElementType(),
|
|
|
|
vectorType.getElementType());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auto memrefType = type.dyn_cast<MemRefType>()) {
|
|
|
|
// Bare pointer convention: statically-shaped memref is compatible with an
|
|
|
|
// LLVM pointer to the element type.
|
|
|
|
if (auto ptrType = llvmType.dyn_cast<LLVMPointerType>()) {
|
|
|
|
if (!memrefType.hasStaticShape())
|
|
|
|
return op->emitOpError(
|
|
|
|
"unexpected bare pointer for dynamically shaped memref");
|
|
|
|
if (memrefType.getMemorySpace() != ptrType.getAddressSpace())
|
|
|
|
return op->emitError("invalid conversion between memref and pointer in "
|
|
|
|
"different memory spaces");
|
|
|
|
|
|
|
|
return verifyCast(op, ptrType.getElementType(),
|
|
|
|
memrefType.getElementType());
|
[MLIR] Add llvm.mlir.cast op for semantic preserving cast between dialect types.
Summary: See discussion here: https://llvm.discourse.group/t/rfc-dialect-type-cast-op/538/11
Reviewers: ftynse
Subscribers: bixia, sanjoy.google, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, nicolasvasilache, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, Joonsoo, llvm-commits
Differential Revision: https://reviews.llvm.org/D75141
2020-02-21 18:13:56 -08:00
|
|
|
}
|
[mlir] Support index and memref types in llvm.mlir.cast
This operation is designed to support partial conversion, more specifically the
IR state in which some operations expect or produce built-in types and some
operations produce and expect LLVM dialect types. It is reasonable for it to
support cast between built-in types and any equivalent that could be produced
by the type conversion. (At the same time, we don't want the dialect to depend
on the type conversion as it could lead to a dependency cycle). Introduce
support for casting from index to any integer type and back, and from memref to
bare pointer or memref descriptor type and back.
Contrary to what the TODO in the code stated, there are no particular
precautions necessary to handle the bare pointer conversion for memerfs. This
conversion applies exclusively to statically-shaped memrefs, so we can always
recover the full descriptor contents from the type.
This patch simultaneously tightens the verification for other types to only
accept matching pairs of types, e.g., i64 and !llvm.i64, as opposed to the
previous implementation that only checked if the types were generally allowed
byt not for matching, e.g. i64 could be "casted" to !llvm.bfloat, which is not
the intended semantics.
Move the relevant test under test/Dialect/LLVMIR because it is not specific to
the conversion pass, but rather exercises an op in the dialect. If we decide
this op does not belong to the LLVM dialect, both the dialect and the op should
move together.
Reviewed By: silvas, ezhulenev
Differential Revision: https://reviews.llvm.org/D93405
2020-12-16 18:32:26 +01:00
|
|
|
|
|
|
|
// Otherwise, memrefs are convertible to a descriptor, which is a structure
|
|
|
|
// type.
|
|
|
|
auto structType = llvmType.dyn_cast<LLVMStructType>();
|
|
|
|
if (!structType)
|
|
|
|
return op->emitOpError("invalid cast between a memref and a type other "
|
|
|
|
"than pointer or memref descriptor");
|
|
|
|
|
|
|
|
unsigned expectedNumElements = memrefType.getRank() == 0 ? 3 : 5;
|
|
|
|
if (structType.getBody().size() != expectedNumElements) {
|
|
|
|
return op->emitOpError() << "expected memref descriptor with "
|
|
|
|
<< expectedNumElements << " elements";
|
[MLIR] Add llvm.mlir.cast op for semantic preserving cast between dialect types.
Summary: See discussion here: https://llvm.discourse.group/t/rfc-dialect-type-cast-op/538/11
Reviewers: ftynse
Subscribers: bixia, sanjoy.google, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, nicolasvasilache, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, Joonsoo, llvm-commits
Differential Revision: https://reviews.llvm.org/D75141
2020-02-21 18:13:56 -08:00
|
|
|
}
|
[mlir] Support index and memref types in llvm.mlir.cast
This operation is designed to support partial conversion, more specifically the
IR state in which some operations expect or produce built-in types and some
operations produce and expect LLVM dialect types. It is reasonable for it to
support cast between built-in types and any equivalent that could be produced
by the type conversion. (At the same time, we don't want the dialect to depend
on the type conversion as it could lead to a dependency cycle). Introduce
support for casting from index to any integer type and back, and from memref to
bare pointer or memref descriptor type and back.
Contrary to what the TODO in the code stated, there are no particular
precautions necessary to handle the bare pointer conversion for memerfs. This
conversion applies exclusively to statically-shaped memrefs, so we can always
recover the full descriptor contents from the type.
This patch simultaneously tightens the verification for other types to only
accept matching pairs of types, e.g., i64 and !llvm.i64, as opposed to the
previous implementation that only checked if the types were generally allowed
byt not for matching, e.g. i64 could be "casted" to !llvm.bfloat, which is not
the intended semantics.
Move the relevant test under test/Dialect/LLVMIR because it is not specific to
the conversion pass, but rather exercises an op in the dialect. If we decide
this op does not belong to the LLVM dialect, both the dialect and the op should
move together.
Reviewed By: silvas, ezhulenev
Differential Revision: https://reviews.llvm.org/D93405
2020-12-16 18:32:26 +01:00
|
|
|
|
|
|
|
// The first two elements are pointers to the element type.
|
|
|
|
auto allocatedPtr = structType.getBody()[0].dyn_cast<LLVMPointerType>();
|
|
|
|
if (!allocatedPtr ||
|
|
|
|
allocatedPtr.getAddressSpace() != memrefType.getMemorySpace())
|
|
|
|
return op->emitOpError("expected first element of a memref descriptor to "
|
|
|
|
"be a pointer in the address space of the memref");
|
|
|
|
if (failed(verifyCast(op, allocatedPtr.getElementType(),
|
|
|
|
memrefType.getElementType())))
|
|
|
|
return failure();
|
|
|
|
|
|
|
|
auto alignedPtr = structType.getBody()[1].dyn_cast<LLVMPointerType>();
|
|
|
|
if (!alignedPtr ||
|
|
|
|
alignedPtr.getAddressSpace() != memrefType.getMemorySpace())
|
|
|
|
return op->emitOpError(
|
|
|
|
"expected second element of a memref descriptor to "
|
|
|
|
"be a pointer in the address space of the memref");
|
|
|
|
if (failed(verifyCast(op, alignedPtr.getElementType(),
|
|
|
|
memrefType.getElementType())))
|
|
|
|
return failure();
|
|
|
|
|
|
|
|
// The second element (offset) is an equivalent of index.
|
|
|
|
if (failed(verifyCastWithIndex(structType.getBody()[2])))
|
|
|
|
return op->emitOpError("expected third element of a memref descriptor to "
|
|
|
|
"be index-compatible integers");
|
|
|
|
|
|
|
|
// 0D memrefs don't have sizes/strides.
|
|
|
|
if (memrefType.getRank() == 0)
|
[MLIR] Add llvm.mlir.cast op for semantic preserving cast between dialect types.
Summary: See discussion here: https://llvm.discourse.group/t/rfc-dialect-type-cast-op/538/11
Reviewers: ftynse
Subscribers: bixia, sanjoy.google, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, nicolasvasilache, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, Joonsoo, llvm-commits
Differential Revision: https://reviews.llvm.org/D75141
2020-02-21 18:13:56 -08:00
|
|
|
return success();
|
[mlir] Support index and memref types in llvm.mlir.cast
This operation is designed to support partial conversion, more specifically the
IR state in which some operations expect or produce built-in types and some
operations produce and expect LLVM dialect types. It is reasonable for it to
support cast between built-in types and any equivalent that could be produced
by the type conversion. (At the same time, we don't want the dialect to depend
on the type conversion as it could lead to a dependency cycle). Introduce
support for casting from index to any integer type and back, and from memref to
bare pointer or memref descriptor type and back.
Contrary to what the TODO in the code stated, there are no particular
precautions necessary to handle the bare pointer conversion for memerfs. This
conversion applies exclusively to statically-shaped memrefs, so we can always
recover the full descriptor contents from the type.
This patch simultaneously tightens the verification for other types to only
accept matching pairs of types, e.g., i64 and !llvm.i64, as opposed to the
previous implementation that only checked if the types were generally allowed
byt not for matching, e.g. i64 could be "casted" to !llvm.bfloat, which is not
the intended semantics.
Move the relevant test under test/Dialect/LLVMIR because it is not specific to
the conversion pass, but rather exercises an op in the dialect. If we decide
this op does not belong to the LLVM dialect, both the dialect and the op should
move together.
Reviewed By: silvas, ezhulenev
Differential Revision: https://reviews.llvm.org/D93405
2020-12-16 18:32:26 +01:00
|
|
|
|
|
|
|
// Sizes and strides are rank-sized arrays of `index` equivalents.
|
|
|
|
auto sizes = structType.getBody()[3].dyn_cast<LLVMArrayType>();
|
|
|
|
if (!sizes || failed(verifyCastWithIndex(sizes.getElementType())) ||
|
|
|
|
sizes.getNumElements() != memrefType.getRank())
|
|
|
|
return op->emitOpError(
|
|
|
|
"expected fourth element of a memref descriptor "
|
|
|
|
"to be an array of <rank> index-compatible integers");
|
|
|
|
|
|
|
|
auto strides = structType.getBody()[4].dyn_cast<LLVMArrayType>();
|
|
|
|
if (!strides || failed(verifyCastWithIndex(strides.getElementType())) ||
|
|
|
|
strides.getNumElements() != memrefType.getRank())
|
|
|
|
return op->emitOpError(
|
|
|
|
"expected fifth element of a memref descriptor "
|
|
|
|
"to be an array of <rank> index-compatible integers");
|
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unranked memrefs are compatible with their descriptors.
|
|
|
|
if (auto unrankedMemrefType = type.dyn_cast<UnrankedMemRefType>()) {
|
|
|
|
auto structType = llvmType.dyn_cast<LLVMStructType>();
|
|
|
|
if (!structType || structType.getBody().size() != 2)
|
|
|
|
return op->emitOpError(
|
|
|
|
"expected descriptor to be a struct with two elements");
|
|
|
|
|
|
|
|
if (failed(verifyCastWithIndex(structType.getBody()[0])))
|
|
|
|
return op->emitOpError("expected first element of a memref descriptor to "
|
|
|
|
"be an index-compatible integer");
|
|
|
|
|
|
|
|
auto ptrType = structType.getBody()[1].dyn_cast<LLVMPointerType>();
|
2020-12-22 11:22:21 +01:00
|
|
|
auto ptrElementType =
|
|
|
|
ptrType ? ptrType.getElementType().dyn_cast<LLVMIntegerType>()
|
|
|
|
: nullptr;
|
|
|
|
if (!ptrElementType || ptrElementType.getBitWidth() != 8)
|
[mlir] Support index and memref types in llvm.mlir.cast
This operation is designed to support partial conversion, more specifically the
IR state in which some operations expect or produce built-in types and some
operations produce and expect LLVM dialect types. It is reasonable for it to
support cast between built-in types and any equivalent that could be produced
by the type conversion. (At the same time, we don't want the dialect to depend
on the type conversion as it could lead to a dependency cycle). Introduce
support for casting from index to any integer type and back, and from memref to
bare pointer or memref descriptor type and back.
Contrary to what the TODO in the code stated, there are no particular
precautions necessary to handle the bare pointer conversion for memerfs. This
conversion applies exclusively to statically-shaped memrefs, so we can always
recover the full descriptor contents from the type.
This patch simultaneously tightens the verification for other types to only
accept matching pairs of types, e.g., i64 and !llvm.i64, as opposed to the
previous implementation that only checked if the types were generally allowed
byt not for matching, e.g. i64 could be "casted" to !llvm.bfloat, which is not
the intended semantics.
Move the relevant test under test/Dialect/LLVMIR because it is not specific to
the conversion pass, but rather exercises an op in the dialect. If we decide
this op does not belong to the LLVM dialect, both the dialect and the op should
move together.
Reviewed By: silvas, ezhulenev
Differential Revision: https://reviews.llvm.org/D93405
2020-12-16 18:32:26 +01:00
|
|
|
return op->emitOpError("expected second element of a memref descriptor "
|
|
|
|
"to be an !llvm.ptr<i8>");
|
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Everything else is not supported.
|
|
|
|
return op->emitError("unsupported cast");
|
|
|
|
}
|
|
|
|
|
|
|
|
static LogicalResult verify(DialectCastOp op) {
|
|
|
|
if (auto llvmType = op.getType().dyn_cast<LLVMType>())
|
|
|
|
return verifyCast(op, llvmType, op.in().getType());
|
|
|
|
|
|
|
|
auto llvmType = op.in().getType().dyn_cast<LLVMType>();
|
|
|
|
if (!llvmType)
|
|
|
|
return op->emitOpError("expected one LLVM type and one built-in type");
|
|
|
|
|
|
|
|
return verifyCast(op, llvmType, op.getType());
|
[MLIR] Add llvm.mlir.cast op for semantic preserving cast between dialect types.
Summary: See discussion here: https://llvm.discourse.group/t/rfc-dialect-type-cast-op/538/11
Reviewers: ftynse
Subscribers: bixia, sanjoy.google, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, nicolasvasilache, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, Joonsoo, llvm-commits
Differential Revision: https://reviews.llvm.org/D75141
2020-02-21 18:13:56 -08: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) {
|
|
|
|
for (auto en : llvm::enumerate(keywords)) {
|
|
|
|
if (succeeded(parser.parseOptionalKeyword(en.value())))
|
|
|
|
return en.index();
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-01-24 17:51:10 +01:00
|
|
|
namespace {
|
|
|
|
template <typename Ty> struct EnumTraits {};
|
|
|
|
|
|
|
|
#define REGISTER_ENUM_TYPE(Ty) \
|
|
|
|
template <> struct EnumTraits<Ty> { \
|
|
|
|
static StringRef stringify(Ty value) { return stringify##Ty(value); } \
|
|
|
|
static unsigned getMaxEnumVal() { return getMaxEnumValFor##Ty(); } \
|
|
|
|
}
|
|
|
|
|
|
|
|
REGISTER_ENUM_TYPE(Linkage);
|
|
|
|
} // end namespace
|
|
|
|
|
|
|
|
template <typename EnumTy>
|
|
|
|
static ParseResult parseOptionalLLVMKeyword(OpAsmParser &parser,
|
|
|
|
OperationState &result,
|
|
|
|
StringRef name) {
|
|
|
|
SmallVector<StringRef, 10> names;
|
|
|
|
for (unsigned i = 0, e = getMaxEnumValForLinkage(); i <= e; ++i)
|
|
|
|
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)
|
|
|
|
return failure();
|
2020-01-24 17:51:10 +01:00
|
|
|
result.addAttribute(name, parser.getBuilder().getI64IntegerAttr(index));
|
2019-12-02 03:27:38 -08:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
2020-04-14 13:01:53 +02:00
|
|
|
// operation ::= `llvm.mlir.global` linkage? `constant`? `@` identifier
|
2019-12-02 03:27:38 -08:00
|
|
|
// `(` attribute? `)` attribute-list? (`:` type)? region?
|
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].
|
2019-09-20 19:47:05 -07:00
|
|
|
static ParseResult parseGlobalOp(OpAsmParser &parser, OperationState &result) {
|
2020-01-24 17:51:10 +01:00
|
|
|
if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result,
|
|
|
|
getLinkageAttrName())))
|
2020-04-14 13:01:53 +02:00
|
|
|
result.addAttribute(getLinkageAttrName(),
|
|
|
|
parser.getBuilder().getI64IntegerAttr(
|
|
|
|
static_cast<int64_t>(LLVM::Linkage::External)));
|
2019-12-02 03:27:38 -08: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>()) {
|
2019-09-20 11:36:49 -07:00
|
|
|
MLIRContext *context = parser.getBuilder().getContext();
|
2020-12-22 11:22:56 +01:00
|
|
|
auto arrayType = LLVM::LLVMArrayType::get(
|
|
|
|
LLVM::LLVMIntegerType::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
|
|
|
}
|
|
|
|
|
2019-10-17 20:08:01 -07:00
|
|
|
result.addAttribute("type", TypeAttr::get(types[0]));
|
2019-08-09 05:01:23 -07:00
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
static LogicalResult verify(GlobalOp op) {
|
2020-08-11 17:17:27 +02:00
|
|
|
if (!LLVMPointerType::isValidElementType(op.getType()))
|
2019-08-09 05:01:23 -07:00
|
|
|
return op.emitOpError(
|
|
|
|
"expects type to be a valid element type for an LLVM pointer");
|
2020-12-09 11:50:18 +01:00
|
|
|
if (op->getParentOp() && !satisfiesLLVMModule(op->getParentOp()))
|
2019-08-09 05:01:23 -07:00
|
|
|
return op.emitOpError("must appear at the module level");
|
2019-09-21 01:19:43 -07:00
|
|
|
|
|
|
|
if (auto strAttr = op.getValueOrNull().dyn_cast_or_null<StringAttr>()) {
|
2020-12-22 11:22:21 +01:00
|
|
|
auto type = op.getType().dyn_cast<LLVMArrayType>();
|
|
|
|
LLVMIntegerType elementType =
|
|
|
|
type ? type.getElementType().dyn_cast<LLVMIntegerType>() : nullptr;
|
|
|
|
if (!elementType || elementType.getBitWidth() != 8 ||
|
|
|
|
type.getNumElements() != strAttr.getValue().size())
|
2019-08-09 08:59:45 -07:00
|
|
|
return op.emitOpError(
|
|
|
|
"requires an i8 array type of the length equal to that of the string "
|
|
|
|
"attribute");
|
|
|
|
}
|
2019-11-05 15:10:28 -08:00
|
|
|
|
|
|
|
if (Block *b = op.getInitializerBlock()) {
|
|
|
|
ReturnOp ret = cast<ReturnOp>(b->getTerminator());
|
|
|
|
if (ret.operand_type_begin() == ret.operand_type_end())
|
|
|
|
return op.emitOpError("initializer region cannot return void");
|
|
|
|
if (*ret.operand_type_begin() != op.getType())
|
|
|
|
return op.emitOpError("initializer region type ")
|
|
|
|
<< *ret.operand_type_begin() << " does not match global type "
|
|
|
|
<< op.getType();
|
|
|
|
|
|
|
|
if (op.getValueOrNull())
|
|
|
|
return op.emitOpError("cannot have both initializer value and region");
|
|
|
|
}
|
2019-08-09 05:01:23 -07:00
|
|
|
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) {
|
2020-12-22 11:22:21 +01:00
|
|
|
auto containerType = v1.getType().cast<LLVM::LLVMVectorType>();
|
|
|
|
auto vType =
|
2020-12-22 11:22:56 +01:00
|
|
|
LLVMFixedVectorType::get(containerType.getElementType(), mask.size());
|
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
|
|
|
}
|
|
|
|
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printShuffleVectorOp(OpAsmPrinter &p, ShuffleVectorOp &op) {
|
2020-01-11 08:54:04 -08:00
|
|
|
p << op.getOperationName() << ' ' << op.v1() << ", " << op.v2() << " "
|
2019-09-20 20:43:02 -07:00
|
|
|
<< op.mask();
|
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"mask"});
|
2020-01-11 08:54:04 -08:00
|
|
|
p << " : " << op.v1().getType() << ", " << op.v2().getType();
|
2019-08-09 05:24:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.shufflevector` ssa-use `, ` ssa-use
|
|
|
|
// `[` integer-literal (`,` integer-literal)* `]`
|
|
|
|
// attribute-dict? `:` type
|
2019-09-20 11:36:49 -07:00
|
|
|
static ParseResult parseShuffleVectorOp(OpAsmParser &parser,
|
2019-09-20 19:47:05 -07:00
|
|
|
OperationState &result) {
|
2019-08-09 05:24:47 -07:00
|
|
|
llvm::SMLoc loc;
|
|
|
|
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();
|
2020-12-22 11:22:21 +01:00
|
|
|
auto containerType = typeV1.dyn_cast<LLVM::LLVMVectorType>();
|
|
|
|
if (!containerType)
|
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");
|
2020-12-22 11:22:21 +01:00
|
|
|
auto vType =
|
2020-12-22 11:22:56 +01:00
|
|
|
LLVMFixedVectorType::get(containerType.getElementType(), maskAttr.size());
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addTypes(vType);
|
2019-08-09 05:24:47 -07: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);
|
|
|
|
|
2020-12-22 11:22:21 +01:00
|
|
|
LLVMFunctionType type = getType();
|
|
|
|
for (unsigned i = 0, e = type.getNumParams(); i < e; ++i)
|
|
|
|
entry->addArgument(type.getParamType(i));
|
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,
|
|
|
|
StringRef name, LLVMType type, LLVM::Linkage linkage,
|
2019-12-03 00:26:13 -08:00
|
|
|
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));
|
2020-04-23 16:02:46 +02:00
|
|
|
result.addAttribute(getLinkageAttrName(),
|
|
|
|
builder.getI64IntegerAttr(static_cast<int64_t>(linkage)));
|
2019-09-20 19:47:05 -07:00
|
|
|
result.attributes.append(attrs.begin(), attrs.end());
|
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;
|
|
|
|
|
2020-12-22 11:22:21 +01:00
|
|
|
unsigned numInputs = type.cast<LLVMFunctionType>().getNumParams();
|
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
|
|
|
assert(numInputs == argAttrs.size() &&
|
|
|
|
"expected as many argument attribute lists as arguments");
|
|
|
|
SmallString<8> argAttrName;
|
|
|
|
for (unsigned i = 0; i < numInputs; ++i)
|
2020-12-17 17:10:12 -08:00
|
|
|
if (DictionaryAttr argDict = argAttrs[i])
|
2019-09-20 19:47:05 -07:00
|
|
|
result.addAttribute(getArgAttrName(i, argAttrName), argDict);
|
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.
|
2019-12-03 00:26:13 -08:00
|
|
|
static Type buildLLVMFunctionType(OpAsmParser &parser, llvm::SMLoc loc,
|
|
|
|
ArrayRef<Type> inputs, ArrayRef<Type> outputs,
|
|
|
|
impl::VariadicFlag variadicFlag) {
|
|
|
|
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.
|
|
|
|
SmallVector<LLVMType, 4> llvmInputs;
|
|
|
|
for (auto t : inputs) {
|
|
|
|
auto llvmTy = t.dyn_cast<LLVMType>();
|
|
|
|
if (!llvmTy) {
|
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 {};
|
|
|
|
}
|
|
|
|
llvmInputs.push_back(llvmTy);
|
|
|
|
}
|
|
|
|
|
|
|
|
// No output is denoted as "void" in LLVM type system.
|
2020-12-22 11:22:56 +01:00
|
|
|
LLVMType llvmOutput = outputs.empty() ? LLVMVoidType::get(b.getContext())
|
2019-08-05 01:57:27 -07:00
|
|
|
: outputs.front().dyn_cast<LLVMType>();
|
|
|
|
if (!llvmOutput) {
|
2019-12-03 00:26:13 -08:00
|
|
|
parser.emitError(loc, "failed to construct function type: expected LLVM "
|
|
|
|
"type for function results");
|
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
|
|
|
|
//
|
|
|
|
static ParseResult parseLLVMFuncOp(OpAsmParser &parser,
|
|
|
|
OperationState &result) {
|
|
|
|
// Default to external linkage if no keyword is provided.
|
2020-01-24 17:51:10 +01:00
|
|
|
if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result,
|
|
|
|
getLinkageAttrName())))
|
2019-12-03 00:26:13 -08:00
|
|
|
result.addAttribute(getLinkageAttrName(),
|
|
|
|
parser.getBuilder().getI64IntegerAttr(
|
|
|
|
static_cast<int64_t>(LLVM::Linkage::External)));
|
|
|
|
|
|
|
|
StringAttr nameAttr;
|
|
|
|
SmallVector<OpAsmParser::OperandType, 8> entryArgs;
|
2020-05-06 13:48:36 -07:00
|
|
|
SmallVector<NamedAttrList, 1> argAttrs;
|
|
|
|
SmallVector<NamedAttrList, 1> resultAttrs;
|
2019-12-03 00:26:13 -08:00
|
|
|
SmallVector<Type, 8> argTypes;
|
|
|
|
SmallVector<Type, 4> resultTypes;
|
|
|
|
bool isVariadic;
|
|
|
|
|
|
|
|
auto signatureLocation = parser.getCurrentLocation();
|
|
|
|
if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
|
|
|
|
result.attributes) ||
|
|
|
|
impl::parseFunctionSignature(parser, /*allowVariadic=*/true, entryArgs,
|
|
|
|
argTypes, argAttrs, isVariadic, resultTypes,
|
|
|
|
resultAttrs))
|
|
|
|
return failure();
|
|
|
|
|
|
|
|
auto type =
|
|
|
|
buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes,
|
|
|
|
impl::VariadicFlag(isVariadic));
|
|
|
|
if (!type)
|
|
|
|
return failure();
|
|
|
|
result.addAttribute(impl::getTypeAttrName(), TypeAttr::get(type));
|
|
|
|
|
|
|
|
if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
|
|
|
|
return failure();
|
|
|
|
impl::addArgAndResultAttrs(parser.getBuilder(), result, argAttrs,
|
|
|
|
resultAttrs);
|
|
|
|
|
|
|
|
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.
|
2019-09-20 20:43:02 -07:00
|
|
|
static void printLLVMFuncOp(OpAsmPrinter &p, LLVMFuncOp op) {
|
2019-12-03 00:26:13 -08:00
|
|
|
p << op.getOperationName() << ' ';
|
2020-01-24 17:51:10 +01:00
|
|
|
if (op.linkage() != LLVM::Linkage::External)
|
|
|
|
p << stringifyLinkage(op.linkage()) << ' ';
|
2019-12-03 00:26:13 -08:00
|
|
|
p.printSymbolName(op.getName());
|
|
|
|
|
2020-12-22 11:22:21 +01:00
|
|
|
LLVMFunctionType fnType = op.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
|
|
|
|
2020-12-22 11:22:21 +01:00
|
|
|
LLVMType returnType = fnType.getReturnType();
|
|
|
|
if (!returnType.isa<LLVMVoidType>())
|
2019-08-05 01:57:27 -07:00
|
|
|
resTypes.push_back(returnType);
|
|
|
|
|
2019-12-03 00:26:13 -08:00
|
|
|
impl::printFunctionSignature(p, op, argTypes, op.isVarArg(), resTypes);
|
|
|
|
impl::printFunctionAttributes(p, op, argTypes.size(), resTypes.size(),
|
|
|
|
{getLinkageAttrName()});
|
|
|
|
|
|
|
|
// Print the body if this is not an external function.
|
|
|
|
Region &body = op.body();
|
|
|
|
if (!body.empty())
|
|
|
|
p.printRegion(body, /*printEntryBlockArgs=*/false,
|
|
|
|
/*printBlockTerminators=*/true);
|
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
|
|
|
// Hook for OpTrait::FunctionLike, called after verifying that the 'type'
|
|
|
|
// attribute is present. This can check for preconditions of the
|
|
|
|
// getNumArguments hook not failing.
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hook for OpTrait::FunctionLike, returns the number of function arguments.
|
|
|
|
// Depends on the type attribute being correct as checked by verifyType
|
2020-12-22 11:22:21 +01:00
|
|
|
unsigned LLVMFuncOp::getNumFuncArguments() { return getType().getNumParams(); }
|
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-10-18 16:02:56 -07:00
|
|
|
// Hook for OpTrait::FunctionLike, returns the number of function results.
|
|
|
|
// Depends on the type attribute being correct as checked by verifyType
|
|
|
|
unsigned LLVMFuncOp::getNumFuncResults() {
|
|
|
|
// We model LLVM functions that return void as having zero results,
|
|
|
|
// and all others as having one result.
|
|
|
|
// If we modeled a void return as one result, then it would be possible to
|
|
|
|
// attach an MLIR result attribute to it, and it isn't clear what semantics we
|
|
|
|
// would assign to that.
|
2020-12-22 11:22:21 +01:00
|
|
|
if (getType().getReturnType().isa<LLVMVoidType>())
|
2019-10-18 16:02:56 -07:00
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
// - entry block arguments are of LLVM types and match the function signature.
|
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
|
|
|
static LogicalResult verify(LLVMFuncOp op) {
|
2019-12-03 00:26:13 -08:00
|
|
|
if (op.linkage() == LLVM::Linkage::Common)
|
|
|
|
return op.emitOpError()
|
2020-01-24 17:51:10 +01:00
|
|
|
<< "functions cannot have '"
|
|
|
|
<< stringifyLinkage(LLVM::Linkage::Common) << "' linkage";
|
2019-12-03 00:26:13 -08:00
|
|
|
|
|
|
|
if (op.isExternal()) {
|
|
|
|
if (op.linkage() != LLVM::Linkage::External &&
|
|
|
|
op.linkage() != LLVM::Linkage::ExternWeak)
|
|
|
|
return op.emitOpError()
|
|
|
|
<< "external functions must have '"
|
2020-01-24 17:51:10 +01:00
|
|
|
<< 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
|
|
|
|
2019-08-08 09:41:48 -07:00
|
|
|
if (op.isVarArg())
|
|
|
|
return op.emitOpError("only external functions can be variadic");
|
|
|
|
|
2020-12-22 11:22:21 +01:00
|
|
|
unsigned numArguments = op.getType().getNumParams();
|
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
|
|
|
Block &entryBlock = op.front();
|
|
|
|
for (unsigned i = 0; i < numArguments; ++i) {
|
2020-01-11 08:54:04 -08:00
|
|
|
Type argType = entryBlock.getArgument(i).getType();
|
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
|
|
|
auto argLLVMType = argType.dyn_cast<LLVMType>();
|
|
|
|
if (!argLLVMType)
|
|
|
|
return op.emitOpError("entry block argument #")
|
|
|
|
<< i << " is not of LLVM type";
|
2020-12-22 11:22:21 +01:00
|
|
|
if (op.getType().getParamType(i) != argLLVMType)
|
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 op.emitOpError("the type of entry block argument #")
|
|
|
|
<< 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.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
static LogicalResult verify(LLVM::ConstantOp op) {
|
|
|
|
if (!(op.value().isa<IntegerAttr>() || op.value().isa<FloatAttr>() ||
|
|
|
|
op.value().isa<ElementsAttr>() || op.value().isa<StringAttr>()))
|
|
|
|
return op.emitOpError()
|
|
|
|
<< "only supports integer, float, string or elements attributes";
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
llvm::SMLoc loc;
|
|
|
|
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) {
|
|
|
|
llvm::SMLoc loc;
|
|
|
|
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
|
|
|
|
[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
|
|
|
static void printAtomicRMWOp(OpAsmPrinter &p, AtomicRMWOp &op) {
|
|
|
|
p << op.getOperationName() << ' ' << stringifyAtomicBinOp(op.bin_op()) << ' '
|
|
|
|
<< op.ptr() << ", " << op.val() << ' '
|
|
|
|
<< stringifyAtomicOrdering(op.ordering()) << ' ';
|
|
|
|
p.printOptionalAttrDict(op.getAttrs(), {"bin_op", "ordering"});
|
|
|
|
p << " : " << op.res().getType();
|
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.atomicrmw` keyword ssa-use `,` ssa-use keyword
|
|
|
|
// attribute-dict? `:` type
|
|
|
|
static ParseResult parseAtomicRMWOp(OpAsmParser &parser,
|
|
|
|
OperationState &result) {
|
|
|
|
LLVMType type;
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
static LogicalResult verify(AtomicRMWOp op) {
|
2020-12-22 11:22:21 +01:00
|
|
|
auto ptrType = op.ptr().getType().cast<LLVM::LLVMPointerType>();
|
2020-01-17 21:09:53 +01:00
|
|
|
auto valType = op.val().getType().cast<LLVM::LLVMType>();
|
2020-12-22 11:22:21 +01:00
|
|
|
if (valType != ptrType.getElementType())
|
2020-01-17 21:09:53 +01:00
|
|
|
return op.emitOpError("expected LLVM IR element type for operand #0 to "
|
|
|
|
"match type for operand #1");
|
|
|
|
auto resType = op.res().getType().cast<LLVM::LLVMType>();
|
|
|
|
if (resType != valType)
|
|
|
|
return op.emitOpError(
|
|
|
|
"expected LLVM IR result type to match type for operand #1");
|
|
|
|
if (op.bin_op() == AtomicBinOp::fadd || op.bin_op() == AtomicBinOp::fsub) {
|
2020-12-22 11:22:21 +01:00
|
|
|
if (!mlir::LLVM::isCompatibleFloatingPointType(valType))
|
2020-01-17 21:09:53 +01:00
|
|
|
return op.emitOpError("expected LLVM IR floating point type");
|
|
|
|
} else if (op.bin_op() == AtomicBinOp::xchg) {
|
2020-12-22 11:22:21 +01:00
|
|
|
auto intType = valType.dyn_cast<LLVMIntegerType>();
|
|
|
|
unsigned intBitWidth = intType ? intType.getBitWidth() : 0;
|
|
|
|
if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 &&
|
|
|
|
intBitWidth != 64 && !valType.isa<LLVMBFloatType>() &&
|
|
|
|
!valType.isa<LLVMHalfType>() && !valType.isa<LLVMFloatType>() &&
|
|
|
|
!valType.isa<LLVMDoubleType>())
|
2020-01-17 21:09:53 +01:00
|
|
|
return op.emitOpError("unexpected LLVM IR type for 'xchg' bin_op");
|
|
|
|
} else {
|
2020-12-22 11:22:21 +01:00
|
|
|
auto intType = valType.dyn_cast<LLVMIntegerType>();
|
|
|
|
unsigned intBitWidth = intType ? intType.getBitWidth() : 0;
|
|
|
|
if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 &&
|
|
|
|
intBitWidth != 64)
|
2020-01-17 21:09:53 +01:00
|
|
|
return op.emitOpError("expected LLVM IR integer type");
|
|
|
|
}
|
|
|
|
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.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
static void printAtomicCmpXchgOp(OpAsmPrinter &p, AtomicCmpXchgOp &op) {
|
|
|
|
p << op.getOperationName() << ' ' << op.ptr() << ", " << op.cmp() << ", "
|
|
|
|
<< op.val() << ' ' << stringifyAtomicOrdering(op.success_ordering()) << ' '
|
|
|
|
<< stringifyAtomicOrdering(op.failure_ordering());
|
|
|
|
p.printOptionalAttrDict(op.getAttrs(),
|
|
|
|
{"success_ordering", "failure_ordering"});
|
|
|
|
p << " : " << op.val().getType();
|
|
|
|
}
|
|
|
|
|
|
|
|
// <operation> ::= `llvm.cmpxchg` ssa-use `,` ssa-use `,` ssa-use
|
|
|
|
// keyword keyword attribute-dict? `:` type
|
|
|
|
static ParseResult parseAtomicCmpXchgOp(OpAsmParser &parser,
|
|
|
|
OperationState &result) {
|
|
|
|
auto &builder = parser.getBuilder();
|
|
|
|
LLVMType type;
|
|
|
|
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();
|
|
|
|
|
2020-12-22 11:22:56 +01:00
|
|
|
auto boolType = LLVMIntegerType::get(builder.getContext(), 1);
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
static LogicalResult verify(AtomicCmpXchgOp op) {
|
2020-12-22 11:22:21 +01:00
|
|
|
auto ptrType = op.ptr().getType().cast<LLVM::LLVMPointerType>();
|
|
|
|
if (!ptrType)
|
[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 op.emitOpError("expected LLVM IR pointer type for operand #0");
|
|
|
|
auto cmpType = op.cmp().getType().cast<LLVM::LLVMType>();
|
|
|
|
auto valType = op.val().getType().cast<LLVM::LLVMType>();
|
2020-12-22 11:22:21 +01:00
|
|
|
if (cmpType != ptrType.getElementType() || cmpType != valType)
|
[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 op.emitOpError("expected LLVM IR element type for operand #0 to "
|
|
|
|
"match type for all other operands");
|
2020-12-22 11:22:21 +01:00
|
|
|
auto intType = valType.dyn_cast<LLVMIntegerType>();
|
|
|
|
unsigned intBitWidth = intType ? intType.getBitWidth() : 0;
|
|
|
|
if (!valType.isa<LLVMPointerType>() && intBitWidth != 8 &&
|
|
|
|
intBitWidth != 16 && intBitWidth != 32 && intBitWidth != 64 &&
|
|
|
|
!valType.isa<LLVMBFloatType>() && !valType.isa<LLVMHalfType>() &&
|
|
|
|
!valType.isa<LLVMFloatType>() && !valType.isa<LLVMDoubleType>())
|
[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 op.emitOpError("unexpected LLVM IR type");
|
|
|
|
if (op.success_ordering() < AtomicOrdering::monotonic ||
|
|
|
|
op.failure_ordering() < AtomicOrdering::monotonic)
|
|
|
|
return op.emitOpError("ordering must be at least 'monotonic'");
|
|
|
|
if (op.failure_ordering() == AtomicOrdering::release ||
|
|
|
|
op.failure_ordering() == AtomicOrdering::acq_rel)
|
|
|
|
return op.emitOpError("failure ordering cannot be 'release' or 'acq_rel'");
|
|
|
|
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?
|
|
|
|
static ParseResult parseFenceOp(OpAsmParser &parser, OperationState &result) {
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void printFenceOp(OpAsmPrinter &p, FenceOp &op) {
|
|
|
|
StringRef syncscopeKeyword = "syncscope";
|
|
|
|
p << op.getOperationName() << ' ';
|
2020-12-12 10:50:41 +01:00
|
|
|
if (!op->getAttr(syncscopeKeyword).cast<StringAttr>().getValue().empty())
|
|
|
|
p << "syncscope(" << op->getAttr(syncscopeKeyword) << ") ";
|
2020-03-17 17:43:21 +01:00
|
|
|
p << stringifyAtomicOrdering(op.ordering());
|
|
|
|
}
|
|
|
|
|
|
|
|
static LogicalResult verify(FenceOp &op) {
|
|
|
|
if (op.ordering() == AtomicOrdering::not_atomic ||
|
|
|
|
op.ordering() == AtomicOrdering::unordered ||
|
|
|
|
op.ordering() == AtomicOrdering::monotonic)
|
|
|
|
return op.emitOpError("can be given only acquire, release, acq_rel, "
|
|
|
|
"and seq_cst orderings");
|
|
|
|
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
|
|
|
//===----------------------------------------------------------------------===//
|
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() {
|
2020-08-04 11:37:50 +02:00
|
|
|
// clang-format off
|
|
|
|
addTypes<LLVMVoidType,
|
|
|
|
LLVMHalfType,
|
|
|
|
LLVMBFloatType,
|
|
|
|
LLVMFloatType,
|
|
|
|
LLVMDoubleType,
|
|
|
|
LLVMFP128Type,
|
|
|
|
LLVMX86FP80Type,
|
|
|
|
LLVMPPCFP128Type,
|
|
|
|
LLVMX86MMXType,
|
|
|
|
LLVMTokenType,
|
|
|
|
LLVMLabelType,
|
|
|
|
LLVMMetadataType,
|
|
|
|
LLVMFunctionType,
|
|
|
|
LLVMIntegerType,
|
|
|
|
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 {
|
2020-08-04 11:37:50 +02:00
|
|
|
return detail::printType(type.cast<LLVMType>(), 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) {
|
|
|
|
// 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.
|
|
|
|
if (attr.first.strref() != LLVM::LLVMDialect::getDataLayoutAttrName())
|
|
|
|
return success();
|
|
|
|
if (auto stringAttr = attr.second.dyn_cast<StringAttr>())
|
|
|
|
return verifyDataLayoutString(
|
|
|
|
stringAttr.getValue(),
|
|
|
|
[op](const Twine &message) { op->emitOpError() << message.str(); });
|
|
|
|
|
|
|
|
return op->emitOpError() << "expected '"
|
|
|
|
<< LLVM::LLVMDialect::getDataLayoutAttrName()
|
|
|
|
<< "' to be a string attribute";
|
|
|
|
}
|
|
|
|
|
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) {
|
2019-03-06 09:34:53 -08:00
|
|
|
// Check that llvm.noalias is a boolean attribute.
|
2020-11-10 16:59:54 +01:00
|
|
|
if (argAttr.first == LLVMDialect::getNoAliasAttrName() &&
|
|
|
|
!argAttr.second.isa<BoolAttr>())
|
2019-07-11 15:05:19 -07:00
|
|
|
return op->emitError()
|
2019-05-06 09:46:11 -07:00
|
|
|
<< "llvm.noalias argument attribute of non boolean type";
|
2020-06-19 10:59:07 +02:00
|
|
|
// Check that llvm.align is an integer attribute.
|
2020-11-10 16:59:54 +01:00
|
|
|
if (argAttr.first == LLVMDialect::getAlignAttrName() &&
|
|
|
|
!argAttr.second.isa<IntegerAttr>())
|
2020-06-19 10:59:07 +02:00
|
|
|
return op->emitError()
|
|
|
|
<< "llvm.align argument attribute of non integer type";
|
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.
|
|
|
|
OpBuilder moduleBuilder(module.getBodyRegion());
|
2020-08-06 00:52:20 +02:00
|
|
|
MLIRContext *ctx = builder.getContext();
|
2020-12-22 11:22:56 +01:00
|
|
|
auto type = LLVM::LLVMArrayType::get(LLVM::LLVMIntegerType::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,
|
|
|
|
builder.getStringAttr(value));
|
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>(
|
2020-12-22 11:22:56 +01:00
|
|
|
loc, LLVM::LLVMIntegerType::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>(
|
|
|
|
loc, LLVM::LLVMPointerType::get(LLVMIntegerType::get(ctx, 8)), globalPtr,
|
|
|
|
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>();
|
|
|
|
}
|