blob: 66b77e96a2ad51c4339237c5e32ddfd212f55693 [file] [log] [blame]
//===- ShapeBase.td ----------------------------------------*- 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
//
//===----------------------------------------------------------------------===//
//
// Base definitions for the `shape` dialect.
//
//===----------------------------------------------------------------------===//
#ifndef SHAPE_BASE_TD
#define SHAPE_BASE_TD
include "mlir/IR/OpBase.td"
//===----------------------------------------------------------------------===//
// Shape Inference dialect definitions
//===----------------------------------------------------------------------===//
def ShapeDialect : Dialect {
let name = "shape";
let summary = "Types and operations for shape dialect";
let description = [{
This dialect contains operations for shape inference.
Note: Unless explicitly stated, all functions that return a shape and take
shapes as input, return the invalid shape if one of its operands is an
invalid shape. This avoids flagging multiple errors for one verification
failure. The dialect itself does not specify how errors should be combined
(there are multiple different options, from always choosing first operand,
concatting etc. on how to combine them).
}];
let cppNamespace = "::mlir::shape";
let dependentDialects = ["arith::ArithmeticDialect", "tensor::TensorDialect"];
let hasConstantMaterializer = 1;
let hasOperationAttrVerify = 1;
let emitAccessorPrefix = kEmitAccessorPrefix_Both;
}
def Shape_ShapeType : DialectType<ShapeDialect,
CPred<"$_self.isa<::mlir::shape::ShapeType>()">, "shape">,
BuildableType<"$_builder.getType<::mlir::shape::ShapeType>()"> {
let description = [{
`shape.shape` represents either an unranked shape, a ranked shape with
possibly unknown dimensions or an invalid shape. The rank is of type
`shape.size` and, if rank is known, the extent is a 1D tensor of type
`shape.size`.
Shape is printed:
* `[*]` if it is an unranked shape
* `[?, 2]` if a rank 2 tensor with one unknown dimension
* `[3, 4]` is a rank 2 static tensor
* `[]` is a scalar
* `[1]` is a rank 1 tensor with 1 element
* `[invalid]` for an invalid shape
}];
}
def Shape_SizeType : DialectType<ShapeDialect,
CPred<"$_self.isa<::mlir::shape::SizeType>()">, "size">,
BuildableType<"$_builder.getType<::mlir::shape::SizeType>()"> {
let description = [{
`shape.size` represents a non-negative integer with support for being
unknown and invalid.
Operations on `shape.size` types are specialized to handle unknown/dynamic
value. So, for example, `<unknown> + x == <unknown>` for all non-error `x :
!shape.size` (e.g., an unknown value does not become known due to addition).
}];
}
def Shape_ValueShapeType : DialectType<ShapeDialect,
CPred<"$_self.isa<::mlir::shape::ValueShapeType>()">, "value shape">,
BuildableType<"::mlir::shape::ValueShapeType::get($_builder.getContext())">
{
let description = [{
`shape.value_shape` represents the value produced by an operation (this
corresponds to `Value` in the compiler) and a shape. Conceptually this is a
tuple of a value (potentially unknown) and `shape.shape`. The value and
shape can either or both be unknown. If both the `value` and `shape` are
known, then the shape of `value` is conformant with `shape`. That is, the
shape of the value conforms to the shape of the ValueShape, so that if we
have ValueShape `(value, shape)` then `join(shape_of(value), shape)` would
be error free and in particular it means that if both are statically known,
then they are equal.
}];
}
def Shape_ExtentTensorType :
1DTensorOf<[Index]>,
BuildableType<"::mlir::RankedTensorType::get({ShapedType::kDynamicSize}, "
"$_builder.getType<::mlir::IndexType>())"> {
let description = [{
The extent tensor is a tensor of rank one with arbitrarily many index
elements (tensor<?xindex>). Like `!shape.shape`, it is used to represent
shapes with the difference that it is guaranteed to be error-free.
}];
}
def Shape_ShapeOrSizeType : AnyTypeOf<[Shape_SizeType, Shape_ShapeType],
"shape or size">;
def Shape_ShapeOrExtentTensorType : AnyTypeOf<[Shape_ShapeType,
Shape_ExtentTensorType],
"shape or extent tensor">;
def Shape_SizeOrIndexType : AnyTypeOf<[Shape_SizeType, Index], "size or index">;
def Shape_WitnessType : DialectType<ShapeDialect,
CPred<"$_self.isa<::mlir::shape::WitnessType>()">, "witness">,
BuildableType<"$_builder.getType<::mlir::shape::WitnessType>()"> {
let description = [{
A witness is a structural device in the compiler to maintain ordering of
code relying on information obtained from passing assertions. Witnesses do
not represent any physical data.
"cstr_" operations will return witnesses and be lowered into assertion logic
when not resolvable at compile time.
"assuming_" operations will take witnesses as input and represent only
information to the compiler, so they do not exist in executing code. Code
that is dependent on "assuming_" operations can assume all cstr operations
transitively before are honored as true.
These abstractions are intended to allow the compiler more freedom with
assertions by merely showing the assertion through dataflow at this time
rather than a side effecting operation that acts as a barrier. This can be
viewed similarly to a compiler representation of promises from asynchronous,
possibly crashing assertions. Reliant code will not be reordered to before
the code and non-reliant code can be reordered freely, and there are no
guarantees on the final ordering of the assertions or their related code.
}];
}
#endif // SHAPE_BASE_TD