forked from OSchip/llvm-project
[mlir] Add EmitC dialect
This upstreams the EmitC dialect and the corresponding Cpp target, both initially presented with [1], from [2] to MLIR core. For the related discussion, see [3]. [1] https://reviews.llvm.org/D76571 [2] https://github.com/iml130/mlir-emitc [3] https://llvm.discourse.group/t/emitc-generating-c-c-from-mlir/3388 Co-authored-by: Jacques Pienaar <jpienaar@google.com> Co-authored-by: Simon Camphausen <simon.camphausen@iml.fraunhofer.de> Co-authored-by: Oliver Scherf <oliver.scherf@iml.fraunhofer.de> Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D103969
This commit is contained in:
parent
1bd4085e0b
commit
876de062f9
|
@ -5,6 +5,7 @@ add_subdirectory(ArmSVE)
|
|||
add_subdirectory(AMX)
|
||||
add_subdirectory(Complex)
|
||||
add_subdirectory(DLTI)
|
||||
add_subdirectory(EmitC)
|
||||
add_subdirectory(GPU)
|
||||
add_subdirectory(Math)
|
||||
add_subdirectory(Linalg)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(IR)
|
|
@ -0,0 +1,7 @@
|
|||
add_mlir_dialect(EmitC emitc)
|
||||
add_mlir_doc(EmitC EmitC Dialects/ -gen-dialect-doc)
|
||||
|
||||
set(LLVM_TARGET_DEFINITIONS EmitCAttributes.td)
|
||||
mlir_tablegen(EmitCAttributes.h.inc -gen-attrdef-decls)
|
||||
mlir_tablegen(EmitCAttributes.cpp.inc -gen-attrdef-defs)
|
||||
add_public_tablegen_target(MLIREmitCAttributesIncGen)
|
|
@ -0,0 +1,32 @@
|
|||
//===- EmitC.h - EmitC Dialect ----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares EmitC in MLIR.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MLIR_DIALECT_EMITC_IR_EMITC_H
|
||||
#define MLIR_DIALECT_EMITC_IR_EMITC_H
|
||||
|
||||
#include "mlir/IR/BuiltinOps.h"
|
||||
#include "mlir/IR/BuiltinTypes.h"
|
||||
#include "mlir/IR/Dialect.h"
|
||||
#include "mlir/Interfaces/SideEffectInterfaces.h"
|
||||
|
||||
#include "mlir/Dialect/EmitC/IR/EmitCDialect.h.inc"
|
||||
|
||||
#define GET_ATTRDEF_CLASSES
|
||||
#include "mlir/Dialect/EmitC/IR/EmitCAttributes.h.inc"
|
||||
|
||||
#define GET_TYPEDEF_CLASSES
|
||||
#include "mlir/Dialect/EmitC/IR/EmitCTypes.h.inc"
|
||||
|
||||
#define GET_OP_CLASSES
|
||||
#include "mlir/Dialect/EmitC/IR/EmitC.h.inc"
|
||||
|
||||
#endif // MLIR_DIALECT_EMITC_IR_EMITC_H
|
|
@ -0,0 +1,148 @@
|
|||
//===- EmitC.td - EmitC operations--------------------------*- tablegen -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines the MLIR EmitC operations.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MLIR_DIALECT_EMITC_IR_EMITC
|
||||
#define MLIR_DIALECT_EMITC_IR_EMITC
|
||||
|
||||
include "mlir/Dialect/EmitC/IR/EmitCAttributes.td"
|
||||
include "mlir/Dialect/EmitC/IR/EmitCTypes.td"
|
||||
|
||||
include "mlir/Interfaces/SideEffectInterfaces.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// EmitC op definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Base class for EmitC dialect ops.
|
||||
class EmitC_Op<string mnemonic, list<OpTrait> traits = []>
|
||||
: Op<EmitC_Dialect, mnemonic, traits> {
|
||||
let verifier = "return ::verify(*this);";
|
||||
}
|
||||
|
||||
def EmitC_ApplyOp : EmitC_Op<"apply", []> {
|
||||
let summary = "Apply operation";
|
||||
let description = [{
|
||||
With the `apply` operation the operators & (address of) and * (contents of)
|
||||
can be applied to a single operand.
|
||||
|
||||
Example:
|
||||
|
||||
```mlir
|
||||
// Custom form of applying the & operator.
|
||||
%0 = emitc.apply "&"(%arg0) : (i32) -> !emitc.opaque<"int32_t*">
|
||||
|
||||
// Generic form of the same operation.
|
||||
%0 = "emitc.apply"(%arg0) {applicableOperator = "&"}
|
||||
: (i32) -> !emitc.opaque<"int32_t*">
|
||||
|
||||
```
|
||||
}];
|
||||
let arguments = (ins
|
||||
Arg<StrAttr, "the operator to apply">:$applicableOperator,
|
||||
AnyType:$operand
|
||||
);
|
||||
let results = (outs AnyType:$result);
|
||||
let assemblyFormat = [{
|
||||
$applicableOperator `(` $operand `)` attr-dict `:` functional-type($operand, results)
|
||||
}];
|
||||
}
|
||||
|
||||
def EmitC_CallOp : EmitC_Op<"call", []> {
|
||||
let summary = "Call operation";
|
||||
let description = [{
|
||||
The `call` operation represents a C++ function call. The call allows
|
||||
specifying order of operands and attributes in the call as follows:
|
||||
|
||||
- integer value of index type refers to an operand;
|
||||
- attribute which will get lowered to constant value in call;
|
||||
|
||||
Example:
|
||||
|
||||
```mlir
|
||||
// Custom form defining a call to `foo()`.
|
||||
%0 = emitc.call "foo" () : () -> i32
|
||||
|
||||
// Generic form of the same operation.
|
||||
%0 = "emitc.call"() {callee = "foo"} : () -> i32
|
||||
```
|
||||
}];
|
||||
let arguments = (ins
|
||||
Arg<StrAttr, "the C++ function to call">:$callee,
|
||||
Arg<OptionalAttr<ArrayAttr>, "the order of operands and further attributes">:$args,
|
||||
Arg<OptionalAttr<ArrayAttr>, "template arguments">:$template_args,
|
||||
Variadic<AnyType>:$operands
|
||||
);
|
||||
let results = (outs Variadic<AnyType>);
|
||||
let assemblyFormat = [{
|
||||
$callee `(` $operands `)` attr-dict `:` functional-type($operands, results)
|
||||
}];
|
||||
}
|
||||
|
||||
def EmitC_ConstantOp : EmitC_Op<"constant", [ConstantLike]> {
|
||||
let summary = "Constant operation";
|
||||
let description = [{
|
||||
The `constant` operation produces an SSA value equal to some constant
|
||||
specified by an attribute. This can be used to form simple integer and
|
||||
floating point constants, as well as more exotic things like tensor
|
||||
constants. The `constant` operation also supports the EmitC opaque
|
||||
attribute and the EmitC opaque type.
|
||||
|
||||
Example:
|
||||
|
||||
```mlir
|
||||
// Integer constant
|
||||
%0 = "emitc.constant"(){value = 42 : i32} : () -> i32
|
||||
|
||||
// Constant emitted as `int32_t* = NULL;`
|
||||
%1 = "emitc.constant"()
|
||||
{value = #emitc.opaque<"NULL"> : !emitc.opaque<"int32_t*">}
|
||||
: () -> !emitc.opaque<"int32_t*">
|
||||
```
|
||||
}];
|
||||
|
||||
let arguments = (ins AnyAttr:$value);
|
||||
let results = (outs AnyType);
|
||||
|
||||
let hasFolder = 1;
|
||||
}
|
||||
|
||||
def EmitC_IncludeOp
|
||||
: EmitC_Op<"include", [NoSideEffect, HasParent<"ModuleOp">]> {
|
||||
let summary = "Include operation";
|
||||
let description = [{
|
||||
The `include` operation allows to define a source file inclusion via the
|
||||
`#include` directive.
|
||||
|
||||
Example:
|
||||
|
||||
```mlir
|
||||
// Custom form defining the inclusion of `<myheader>`.
|
||||
emitc.include "myheader.h" is_standard_include
|
||||
|
||||
// Generic form of the same operation.
|
||||
"emitc.include" (){include = "myheader.h", is_standard_include} : () -> ()
|
||||
|
||||
// Generic form defining the inclusion of `"myheader"`.
|
||||
"emitc.include" (){include = "myheader.h"} : () -> ()
|
||||
```
|
||||
}];
|
||||
let arguments = (ins
|
||||
Arg<StrAttr, "source file to include">:$include,
|
||||
UnitAttr:$is_standard_include
|
||||
);
|
||||
let assemblyFormat = [{
|
||||
$include attr-dict (`is_standard_include` $is_standard_include^)?
|
||||
}];
|
||||
let verifier = ?;
|
||||
}
|
||||
|
||||
#endif // MLIR_DIALECT_EMITC_IR_EMITC
|
|
@ -0,0 +1,45 @@
|
|||
//===- EmitCAttributes.td - EmitC attributes ---------------*- tablegen -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines the MLIR EmitC attributes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MLIR_DIALECT_EMITC_IR_EMITCATTRIBUTES
|
||||
#define MLIR_DIALECT_EMITC_IR_EMITCATTRIBUTES
|
||||
|
||||
include "mlir/Dialect/EmitC/IR/EmitCBase.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// EmitC attribute definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class EmitC_Attr<string name, string attrMnemonic>
|
||||
: AttrDef<EmitC_Dialect, name> {
|
||||
let mnemonic = attrMnemonic;
|
||||
}
|
||||
|
||||
def EmitC_OpaqueAttr : EmitC_Attr<"Opaque", "opaque"> {
|
||||
let summary = "An opaque attribute";
|
||||
|
||||
let description = [{
|
||||
An opaque attribute of which the value gets emitted as is.
|
||||
|
||||
Example:
|
||||
|
||||
```mlir
|
||||
#emitc.opaque<"">
|
||||
#emitc.opaque<"NULL">
|
||||
#emitc.opaque<"nullptr">
|
||||
```
|
||||
}];
|
||||
|
||||
let parameters = (ins StringRefParameter<"the opaque value">:$value);
|
||||
}
|
||||
|
||||
#endif // MLIR_DIALECT_EMITC_IR_EMITCATTRIBUTES
|
|
@ -0,0 +1,28 @@
|
|||
//===- EmitCBase.td - EmitC dialect ------------------------*- tablegen -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines the MLIR EmitC dialect.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MLIR_DIALECT_EMITC_IR_EMITCBASE
|
||||
#define MLIR_DIALECT_EMITC_IR_EMITCBASE
|
||||
|
||||
include "mlir/IR/OpBase.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// EmitC dialect definition
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def EmitC_Dialect : Dialect {
|
||||
let name = "emitc";
|
||||
let cppNamespace = "::mlir::emitc";
|
||||
let hasConstantMaterializer = 1;
|
||||
}
|
||||
|
||||
#endif // MLIR_DIALECT_EMITC_IR_EMITCBASE
|
|
@ -0,0 +1,46 @@
|
|||
//===- EmitCTypes.td - EmitC types -------------------------*- tablegen -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines the MLIR EmitC types.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#ifndef MLIR_DIALECT_EMITC_IR_EMITCTYPES
|
||||
#define MLIR_DIALECT_EMITC_IR_EMITCTYPES
|
||||
|
||||
include "mlir/Dialect/EmitC/IR/EmitCBase.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// EmitC type definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class EmitC_Type<string name, string typeMnemonic>
|
||||
: TypeDef<EmitC_Dialect, name> {
|
||||
let mnemonic = typeMnemonic;
|
||||
}
|
||||
|
||||
def EmitC_OpaqueType : EmitC_Type<"Opaque", "opaque"> {
|
||||
let summary = "An opaque type";
|
||||
|
||||
let description = [{
|
||||
An opaque data type of which the value gets emitted as is.
|
||||
|
||||
Example:
|
||||
|
||||
```mlir
|
||||
!emitc.opaque<"int">
|
||||
!emitc.opaque<"float *">
|
||||
!emitc.opaque<"std::vector<std::string>">
|
||||
```
|
||||
}];
|
||||
|
||||
let parameters = (ins StringRefParameter<"the opaque value">:$value);
|
||||
}
|
||||
|
||||
#endif // MLIR_DIALECT_EMITC_IR_EMITCTYPES
|
|
@ -21,6 +21,7 @@
|
|||
#include "mlir/Dialect/Async/IR/Async.h"
|
||||
#include "mlir/Dialect/Complex/IR/Complex.h"
|
||||
#include "mlir/Dialect/DLTI/DLTI.h"
|
||||
#include "mlir/Dialect/EmitC/IR/EmitC.h"
|
||||
#include "mlir/Dialect/GPU/GPUDialect.h"
|
||||
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
|
||||
#include "mlir/Dialect/LLVMIR/NVVMDialect.h"
|
||||
|
@ -57,6 +58,7 @@ inline void registerAllDialects(DialectRegistry ®istry) {
|
|||
async::AsyncDialect,
|
||||
complex::ComplexDialect,
|
||||
DLTIDialect,
|
||||
emitc::EmitCDialect,
|
||||
gpu::GPUDialect,
|
||||
LLVM::LLVMDialect,
|
||||
linalg::LinalgDialect,
|
||||
|
|
|
@ -5,6 +5,7 @@ add_subdirectory(Async)
|
|||
add_subdirectory(AMX)
|
||||
add_subdirectory(Complex)
|
||||
add_subdirectory(DLTI)
|
||||
add_subdirectory(EmitC)
|
||||
add_subdirectory(GPU)
|
||||
add_subdirectory(Linalg)
|
||||
add_subdirectory(LLVMIR)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(IR)
|
|
@ -0,0 +1,14 @@
|
|||
add_mlir_dialect_library(MLIREmitC
|
||||
EmitC.cpp
|
||||
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
${MLIR_MAIN_INCLUDE_DIR}/mlir/Dialect/EmitC
|
||||
|
||||
DEPENDS
|
||||
MLIREmitCIncGen
|
||||
MLIREmitCAttributesIncGen
|
||||
|
||||
LINK_LIBS PUBLIC
|
||||
MLIRIR
|
||||
MLIRSideEffectInterfaces
|
||||
)
|
|
@ -0,0 +1,212 @@
|
|||
//===- EmitC.cpp - EmitC Dialect ------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "mlir/Dialect/EmitC/IR/EmitC.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/DialectImplementation.h"
|
||||
#include "llvm/ADT/TypeSwitch.h"
|
||||
|
||||
using namespace mlir;
|
||||
using namespace mlir::emitc;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// EmitCDialect
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void EmitCDialect::initialize() {
|
||||
addOperations<
|
||||
#define GET_OP_LIST
|
||||
#include "mlir/Dialect/EmitC/IR/EmitC.cpp.inc"
|
||||
>();
|
||||
addTypes<
|
||||
#define GET_TYPEDEF_LIST
|
||||
#include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"
|
||||
>();
|
||||
addAttributes<
|
||||
#define GET_ATTRDEF_LIST
|
||||
#include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc"
|
||||
>();
|
||||
}
|
||||
|
||||
/// Materialize a single constant operation from a given attribute value with
|
||||
/// the desired resultant type.
|
||||
Operation *EmitCDialect::materializeConstant(OpBuilder &builder,
|
||||
Attribute value, Type type,
|
||||
Location loc) {
|
||||
return builder.create<ConstantOp>(loc, type, value);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ApplyOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static LogicalResult verify(ApplyOp op) {
|
||||
StringRef applicableOperator = op.applicableOperator();
|
||||
|
||||
// Applicable operator must not be empty.
|
||||
if (applicableOperator.empty())
|
||||
return op.emitOpError("applicable operator must not be empty");
|
||||
|
||||
// Only `*` and `&` are supported.
|
||||
if (applicableOperator != "&" && applicableOperator != "*")
|
||||
return op.emitOpError("applicable operator is illegal");
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CallOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static LogicalResult verify(emitc::CallOp op) {
|
||||
// Callee must not be empty.
|
||||
if (op.callee().empty())
|
||||
return op.emitOpError("callee must not be empty");
|
||||
|
||||
if (Optional<ArrayAttr> argsAttr = op.args()) {
|
||||
for (Attribute arg : argsAttr.getValue()) {
|
||||
if (arg.getType().isa<IndexType>()) {
|
||||
int64_t index = arg.cast<IntegerAttr>().getInt();
|
||||
// Args with elements of type index must be in range
|
||||
// [0..operands.size).
|
||||
if ((index < 0) || (index >= static_cast<int64_t>(op.getNumOperands())))
|
||||
return op.emitOpError("index argument is out of range");
|
||||
|
||||
// Args with elements of type ArrayAttr must have a type.
|
||||
} else if (arg.isa<ArrayAttr>() && arg.getType().isa<NoneType>()) {
|
||||
return op.emitOpError("array argument has no type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Optional<ArrayAttr> templateArgsAttr = op.template_args()) {
|
||||
for (Attribute tArg : templateArgsAttr.getValue()) {
|
||||
if (!tArg.isa<TypeAttr>() && !tArg.isa<IntegerAttr>() &&
|
||||
!tArg.isa<FloatAttr>() && !tArg.isa<emitc::OpaqueAttr>())
|
||||
return op.emitOpError("template argument has invalid type");
|
||||
}
|
||||
}
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ConstantOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// The constant op requires that the attribute's type matches the return type.
|
||||
static LogicalResult verify(emitc::ConstantOp &op) {
|
||||
Attribute value = op.value();
|
||||
Type type = op.getType();
|
||||
if (!value.getType().isa<NoneType>() && type != value.getType())
|
||||
return op.emitOpError() << "requires attribute's type (" << value.getType()
|
||||
<< ") to match op's return type (" << type << ")";
|
||||
return success();
|
||||
}
|
||||
|
||||
OpFoldResult emitc::ConstantOp::fold(ArrayRef<Attribute> operands) {
|
||||
assert(operands.empty() && "constant has no operands");
|
||||
return value();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TableGen'd op method definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define GET_OP_CLASSES
|
||||
#include "mlir/Dialect/EmitC/IR/EmitC.cpp.inc"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// EmitC Attributes
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define GET_ATTRDEF_CLASSES
|
||||
#include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc"
|
||||
|
||||
Attribute emitc::OpaqueAttr::parse(MLIRContext *context,
|
||||
DialectAsmParser &parser, Type type) {
|
||||
if (parser.parseLess())
|
||||
return Attribute();
|
||||
StringRef value;
|
||||
llvm::SMLoc loc = parser.getCurrentLocation();
|
||||
if (parser.parseOptionalString(&value)) {
|
||||
parser.emitError(loc) << "expected string";
|
||||
return Attribute();
|
||||
}
|
||||
if (parser.parseGreater())
|
||||
return Attribute();
|
||||
return get(context, value);
|
||||
}
|
||||
|
||||
Attribute EmitCDialect::parseAttribute(DialectAsmParser &parser,
|
||||
Type type) const {
|
||||
llvm::SMLoc typeLoc = parser.getCurrentLocation();
|
||||
StringRef mnemonic;
|
||||
if (parser.parseKeyword(&mnemonic))
|
||||
return Attribute();
|
||||
Attribute genAttr;
|
||||
OptionalParseResult parseResult =
|
||||
generatedAttributeParser(getContext(), parser, mnemonic, type, genAttr);
|
||||
if (parseResult.hasValue())
|
||||
return genAttr;
|
||||
parser.emitError(typeLoc, "unknown attribute in EmitC dialect");
|
||||
return Attribute();
|
||||
}
|
||||
|
||||
void EmitCDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const {
|
||||
if (failed(generatedAttributePrinter(attr, os)))
|
||||
llvm_unreachable("unexpected 'EmitC' attribute kind");
|
||||
}
|
||||
|
||||
void emitc::OpaqueAttr::print(DialectAsmPrinter &printer) const {
|
||||
printer << "opaque<\"" << getValue() << "\">";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// EmitC Types
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define GET_TYPEDEF_CLASSES
|
||||
#include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"
|
||||
|
||||
Type emitc::OpaqueType::parse(MLIRContext *context, DialectAsmParser &parser) {
|
||||
if (parser.parseLess())
|
||||
return Type();
|
||||
StringRef value;
|
||||
llvm::SMLoc loc = parser.getCurrentLocation();
|
||||
if (parser.parseOptionalString(&value) || value.empty()) {
|
||||
parser.emitError(loc) << "expected non empty string";
|
||||
return Type();
|
||||
}
|
||||
if (parser.parseGreater())
|
||||
return Type();
|
||||
return get(context, value);
|
||||
}
|
||||
|
||||
Type EmitCDialect::parseType(DialectAsmParser &parser) const {
|
||||
llvm::SMLoc typeLoc = parser.getCurrentLocation();
|
||||
StringRef mnemonic;
|
||||
if (parser.parseKeyword(&mnemonic))
|
||||
return Type();
|
||||
Type genType;
|
||||
OptionalParseResult parseResult =
|
||||
generatedTypeParser(getContext(), parser, mnemonic, genType);
|
||||
if (parseResult.hasValue())
|
||||
return genType;
|
||||
parser.emitError(typeLoc, "unknown type in EmitC dialect");
|
||||
return Type();
|
||||
}
|
||||
|
||||
void EmitCDialect::printType(Type type, DialectAsmPrinter &os) const {
|
||||
if (failed(generatedTypePrinter(type, os)))
|
||||
llvm_unreachable("unexpected 'EmitC' type kind");
|
||||
}
|
||||
|
||||
void emitc::OpaqueType::print(DialectAsmPrinter &printer) const {
|
||||
printer << "opaque<\"" << getValue() << "\">";
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
// RUN: mlir-opt %s -split-input-file -verify-diagnostics
|
||||
|
||||
func @const_attribute_return_type_1() {
|
||||
// expected-error @+1 {{'emitc.constant' op requires attribute's type ('i64') to match op's return type ('i32')}}
|
||||
%c0 = "emitc.constant"(){value = 42: i64} : () -> i32
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @const_attribute_return_type_2() {
|
||||
// expected-error @+1 {{'emitc.constant' op requires attribute's type ('!emitc.opaque<"int32_t*">') to match op's return type ('!emitc.opaque<"int32_t">')}}
|
||||
%c0 = "emitc.constant"(){value = "nullptr" : !emitc.opaque<"int32_t*">} : () -> !emitc.opaque<"int32_t">
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @index_args_out_of_range_1() {
|
||||
// expected-error @+1 {{'emitc.call' op index argument is out of range}}
|
||||
emitc.call "test" () {args = [0 : index]} : () -> ()
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @index_args_out_of_range_2(%arg : i32) {
|
||||
// expected-error @+1 {{'emitc.call' op index argument is out of range}}
|
||||
emitc.call "test" (%arg, %arg) {args = [2 : index]} : (i32, i32) -> ()
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @empty_callee() {
|
||||
// expected-error @+1 {{'emitc.call' op callee must not be empty}}
|
||||
emitc.call "" () : () -> ()
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @nonetype_arg(%arg : i32) {
|
||||
// expected-error @+1 {{'emitc.call' op array argument has no type}}
|
||||
emitc.call "nonetype_arg"(%arg) {args = [0 : index, [0, 1, 2]]} : (i32) -> i32
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @array_template_arg(%arg : i32) {
|
||||
// expected-error @+1 {{'emitc.call' op template argument has invalid type}}
|
||||
emitc.call "nonetype_template_arg"(%arg) {template_args = [[0, 1, 2]]} : (i32) -> i32
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @dense_template_argument(%arg : i32) {
|
||||
// expected-error @+1 {{'emitc.call' op template argument has invalid type}}
|
||||
emitc.call "dense_template_argument"(%arg) {template_args = [dense<[1.0, 1.0]> : tensor<2xf32>]} : (i32) -> i32
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @empty_operator(%arg : i32) {
|
||||
// expected-error @+1 {{'emitc.apply' op applicable operator must not be empty}}
|
||||
%2 = emitc.apply ""(%arg) : (i32) -> !emitc.opaque<"int32_t*">
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @illegal_operator(%arg : i32) {
|
||||
// expected-error @+1 {{'emitc.apply' op applicable operator is illegal}}
|
||||
%2 = emitc.apply "+"(%arg) : (i32) -> !emitc.opaque<"int32_t*">
|
||||
return
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
// RUN: mlir-opt -verify-diagnostics %s | FileCheck %s
|
||||
|
||||
"emitc.include" (){include = "test.h", is_standard_include} : () -> ()
|
||||
emitc.include "test.h" is_standard_include
|
||||
|
||||
// CHECK-LABEL: func @f(%{{.*}}: i32, %{{.*}}: !emitc.opaque<"int32_t">) {
|
||||
func @f(%arg0: i32, %f: !emitc.opaque<"int32_t">) {
|
||||
%1 = "emitc.call"() {callee = "blah"} : () -> i64
|
||||
emitc.call "foo" (%1) {args = [
|
||||
0 : index, dense<[0, 1]> : tensor<2xi32>, 0 : index
|
||||
]} : (i64) -> ()
|
||||
return
|
||||
}
|
||||
|
||||
func @c(%arg0: i32) {
|
||||
%1 = "emitc.constant"(){value = 42 : i32} : () -> i32
|
||||
return
|
||||
}
|
||||
|
||||
func @a(%arg0: i32, %arg1: i32) {
|
||||
%1 = "emitc.apply"(%arg0) {applicableOperator = "&"} : (i32) -> !emitc.opaque<"int32_t*">
|
||||
%2 = emitc.apply "&"(%arg1) : (i32) -> !emitc.opaque<"int32_t*">
|
||||
return
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// RUN: mlir-opt -verify-diagnostics %s | FileCheck %s
|
||||
// check parser
|
||||
// RUN: mlir-opt -verify-diagnostics %s | mlir-opt -verify-diagnostics | FileCheck %s
|
||||
|
||||
// CHECK-LABEL: func @opaque_types() {
|
||||
func @opaque_types() {
|
||||
// CHECK-NEXT: !emitc.opaque<"int">
|
||||
emitc.call "f"() {args = [!emitc<"opaque<\"int\">">]} : () -> ()
|
||||
// CHECK-NEXT: !emitc.opaque<"byte">
|
||||
emitc.call "f"() {args = [!emitc<"opaque<\"byte\">">]} : () -> ()
|
||||
// CHECK-NEXT: !emitc.opaque<"unsigned">
|
||||
emitc.call "f"() {args = [!emitc<"opaque<\"unsigned\">">]} : () -> ()
|
||||
// CHECK-NEXT: !emitc.opaque<"status_t">
|
||||
emitc.call "f"() {args = [!emitc<"opaque<\"status_t\">">]} : () -> ()
|
||||
// CHECK-NEXT: !emitc.opaque<"std::vector<std::string>">
|
||||
emitc.call "f"() {args = [!emitc.opaque<"std::vector<std::string>">]} : () -> ()
|
||||
return
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
// CHECK-NEXT: async
|
||||
// CHECK-NEXT: complex
|
||||
// CHECK-NEXT: dlti
|
||||
// CHECK-NEXT: emitc
|
||||
// CHECK-NEXT: gpu
|
||||
// CHECK-NEXT: linalg
|
||||
// CHECK-NEXT: llvm
|
||||
|
|
Loading…
Reference in New Issue