2020-04-27 08:20:58 +08:00
|
|
|
//===- NumpyOps.td - Core numpy dialect ops ----------------*- tablegen -*-===//
|
|
|
|
//
|
|
|
|
// This file is licensed 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
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-06-10 10:22:24 +08:00
|
|
|
#ifndef NPCOMP_DIALECT_NUMPY_IR_NUMPY_OPS
|
|
|
|
#define NPCOMP_DIALECT_NUMPY_IR_NUMPY_OPS
|
2020-04-27 08:20:58 +08:00
|
|
|
|
|
|
|
include "NumpyDialect.td"
|
2020-07-05 07:40:02 +08:00
|
|
|
include "npcomp/Typing/Analysis/CPA/Interfaces.td"
|
2020-05-22 04:09:06 +08:00
|
|
|
include "mlir/Interfaces/SideEffectInterfaces.td"
|
2020-04-29 11:32:49 +08:00
|
|
|
include "mlir/IR/SymbolInterfaces.td"
|
2020-04-27 08:20:58 +08:00
|
|
|
|
2020-05-05 06:47:01 +08:00
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
// IR casting and conversions
|
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
|
|
|
|
def Numpy_NarrowOp : Numpy_Op<"narrow", []> {
|
|
|
|
let summary = "Narrows an array to a known type at boundaries.";
|
|
|
|
let description = [{
|
|
|
|
During tracing, specific data types are often unknown. This op generically
|
|
|
|
narrows from an unknown to a known data type at boundaries.
|
|
|
|
}];
|
|
|
|
let arguments = (ins
|
|
|
|
Numpy_AnyArray:$operand
|
|
|
|
);
|
|
|
|
let results = (outs
|
|
|
|
Numpy_AnyArray:$result
|
|
|
|
);
|
|
|
|
let assemblyFormat = [{
|
|
|
|
$operand attr-dict `:` functional-type($operand, $result)
|
2020-06-29 08:58:26 +08:00
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
// NdArray type handling
|
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
|
2020-06-29 09:42:08 +08:00
|
|
|
def Numpy_CreateArrayFromTensorOp : Numpy_Op<"create_array_from_tensor", [
|
2020-07-04 09:16:34 +08:00
|
|
|
DeclareOpInterfaceMethods<NPCOMP_CPATypeInferenceOpInterface>,
|
2020-06-29 09:42:08 +08:00
|
|
|
NoSideEffect]> {
|
2020-06-29 08:58:26 +08:00
|
|
|
let summary = "Creates an ndarray from a tensor.";
|
|
|
|
let description = [{
|
|
|
|
Creates a new ndarray that will contain the data of the given tensor.
|
|
|
|
}];
|
|
|
|
let arguments = (ins
|
|
|
|
Numpy_AnyTensor:$source
|
|
|
|
);
|
|
|
|
let results = (outs
|
|
|
|
Numpy_AnyArray:$dest
|
|
|
|
);
|
|
|
|
let assemblyFormat = [{
|
|
|
|
$source attr-dict `:` functional-type($source, $dest)
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
2020-07-04 09:16:34 +08:00
|
|
|
def Numpy_CopyToTensorOp : Numpy_Op<"copy_to_tensor", [
|
|
|
|
DeclareOpInterfaceMethods<NPCOMP_CPATypeInferenceOpInterface>]> {
|
2020-06-29 08:58:26 +08:00
|
|
|
let summary = "Copies an ndarray, yielding a value-typed tensor.";
|
|
|
|
let description = [{
|
|
|
|
The semantics of this operation connote a copy of the data in the source
|
|
|
|
ndarray, producing a destination value that will have the value in the
|
|
|
|
ndarray at the point of the copy. Of course, downstream transformations
|
|
|
|
are free to rearrange things to elide the copy or otherwise eliminate the
|
|
|
|
need for it.
|
|
|
|
}];
|
|
|
|
let arguments = (ins
|
|
|
|
Numpy_NdArrayType:$source
|
|
|
|
);
|
|
|
|
let results = (outs
|
|
|
|
Numpy_AnyTensor:$dest
|
|
|
|
);
|
|
|
|
let assemblyFormat = [{
|
|
|
|
$source attr-dict `:` functional-type($source, $dest)
|
|
|
|
}];
|
2020-07-06 09:09:43 +08:00
|
|
|
let hasCanonicalizer = 1;
|
2020-05-05 06:47:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
// Universal function ops (ufunc)
|
|
|
|
// See: https://docs.scipy.org/doc/numpy/reference/ufuncs.html
|
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
|
2020-07-04 09:16:34 +08:00
|
|
|
def Numpy_BuiltinUfuncCallOp : Numpy_Op<"builtin_ufunc_call", [
|
|
|
|
DeclareOpInterfaceMethods<NPCOMP_CPATypeInferenceOpInterface>]> {
|
2020-06-30 06:27:39 +08:00
|
|
|
let summary = "A __call__ operation on a named/builtin ufunc";
|
|
|
|
let description = [{
|
|
|
|
Simple ufunc call semantics for builtin ufuncs with none of the advanced
|
|
|
|
arguments specified.
|
|
|
|
|
|
|
|
Note that without the `out=` parameter, ufunc call operations (unlike
|
|
|
|
others like `at`) are defined purely in the value domain and do not alias.
|
|
|
|
As such, they operate on tensors, not ndarray.
|
|
|
|
}];
|
|
|
|
let arguments = (ins
|
|
|
|
StrAttr:$qualified_name,
|
|
|
|
Variadic<Numpy_AnyTensor>:$inputs
|
|
|
|
);
|
|
|
|
let results = (outs
|
|
|
|
Numpy_AnyTensor:$output
|
|
|
|
);
|
|
|
|
let assemblyFormat = [{
|
|
|
|
`<` $qualified_name `>` `(` operands `)` attr-dict `:` functional-type(operands, results)
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
2020-05-05 06:47:01 +08:00
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
// Built-in array functions
|
|
|
|
//
|
|
|
|
// These are ops that mirror supported array functions in numpy or related
|
|
|
|
// libraries. Note that there is some evolution happening on the dispatch
|
|
|
|
// mechanism for these.
|
|
|
|
// See: https://numpy.org/neps/nep-0018-array-function-protocol.html
|
|
|
|
// See: https://numpy.org/neps/nep-0037-array-module.html
|
|
|
|
//
|
|
|
|
// Note that operators are in general free to take any arguments, but there
|
|
|
|
// are some conventions that are mirrored here:
|
|
|
|
//
|
|
|
|
// - `out` arguments indicate that the operation should perform a mutation
|
|
|
|
// of a specific array. This is not modeled at the individual op level,
|
|
|
|
// instead producing IR constructs to map the intent.
|
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
|
|
|
|
def Numpy_DotOp : Numpy_Op<"dot", []> {
|
|
|
|
let summary = "Represents the `numpy.dot` operator";
|
2020-05-03 10:52:21 +08:00
|
|
|
let description = [{
|
2020-05-05 07:20:36 +08:00
|
|
|
See: https://docs.scipy.org/doc/numpy/reference/generated/numpy.dot.html
|
2020-05-03 10:52:21 +08:00
|
|
|
}];
|
|
|
|
let arguments = (ins
|
2020-05-05 06:47:01 +08:00
|
|
|
Numpy_AnyArray:$a,
|
|
|
|
Numpy_AnyArray:$b
|
2020-05-03 10:52:21 +08:00
|
|
|
);
|
|
|
|
let results = (outs
|
2020-05-05 06:47:01 +08:00
|
|
|
Numpy_AnyArray:$output
|
2020-05-03 10:52:21 +08:00
|
|
|
);
|
|
|
|
let assemblyFormat = [{
|
2020-05-05 06:47:01 +08:00
|
|
|
operands attr-dict `:` functional-type(operands, $output)
|
2020-06-29 08:58:26 +08:00
|
|
|
}];
|
2020-05-03 10:52:21 +08:00
|
|
|
}
|
|
|
|
|
2020-05-05 07:20:36 +08:00
|
|
|
def Numpy_TransposeOp : Numpy_Op<"transpose", []> {
|
|
|
|
let summary = "Represents the `numpy.transpose` op with no permutation specified";
|
|
|
|
let description = [{
|
|
|
|
This op is equivalent to calling `numpy.transpose(arr)`, which reverses
|
|
|
|
the axes of the array. It is separate from the explicit form because it
|
|
|
|
is not always possible to locallly infer an appropriate axis transform
|
|
|
|
at the point of declaration.
|
|
|
|
|
|
|
|
See: https://docs.scipy.org/doc/numpy/reference/generated/numpy.transpose.html
|
|
|
|
}];
|
|
|
|
let arguments = (ins
|
|
|
|
Numpy_AnyArray:$a
|
|
|
|
);
|
|
|
|
let results = (outs
|
|
|
|
Numpy_AnyArray:$output
|
|
|
|
);
|
|
|
|
let assemblyFormat = [{
|
|
|
|
operands attr-dict `:` functional-type(operands, $output)
|
2020-06-29 08:58:26 +08:00
|
|
|
}];
|
2020-05-05 07:20:36 +08:00
|
|
|
}
|
|
|
|
|
2020-05-09 07:04:58 +08:00
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
// Slicing
|
|
|
|
// See: https://docs.scipy.org/doc/numpy/user/basics.indexing.html
|
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
|
|
|
|
def Numpy_GetSlice : Numpy_Op<"get_slice", []> {
|
|
|
|
let summary = "Gets a slice of an array";
|
|
|
|
let description = [{
|
|
|
|
This op encapsulates all forms of indexing into an array by taking a
|
|
|
|
variable number of `slice` arguments, each of which represents a single
|
|
|
|
entry in a generalized indexing-tuple. Once full type inference has
|
|
|
|
been performed, there should be sufficient static information to determine
|
|
|
|
the exact slice semantics solely by the signature of types of the `slice`
|
|
|
|
arguments.
|
|
|
|
|
|
|
|
Note that there is a more general form of this op that is generally
|
|
|
|
needed for AST extraction that takes a variable length `tuple` instead
|
|
|
|
of a static list of arguments. It is expected that during type refinement
|
|
|
|
most such uses should degenerate to this static variant.
|
|
|
|
|
|
|
|
Per numpy semantics, many forms of slice return a view instead of a copy,
|
|
|
|
and determining the exact form requires additional analysis.
|
|
|
|
}];
|
|
|
|
let arguments = (ins
|
|
|
|
Numpy_AnyArray:$a,
|
|
|
|
Variadic<Numpy_SliceTupleElement>:$slice_elements
|
|
|
|
);
|
|
|
|
let results = (outs
|
|
|
|
Numpy_AnyArray:$result
|
|
|
|
);
|
|
|
|
let assemblyFormat = [{
|
|
|
|
operands attr-dict `:` functional-type(operands, $result)
|
2020-06-29 08:58:26 +08:00
|
|
|
}];
|
2020-05-09 07:04:58 +08:00
|
|
|
}
|
|
|
|
|
2020-06-10 10:22:24 +08:00
|
|
|
#endif // NPCOMP_DIALECT_NUMPY_IR_NUMPY_OPS
|