//===- ComplexOps.td - Complex op definitions ----------------*- 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
//
//===----------------------------------------------------------------------===//
#ifndef COMPLEX_OPS
#define COMPLEX_OPS
include "mlir/Dialect/Arith/IR/ArithBase.td"
include "mlir/Dialect/Arith/IR/ArithOpsInterfaces.td"
include "mlir/Dialect/Complex/IR/ComplexBase.td"
include "mlir/IR/OpAsmInterface.td"
include "mlir/Interfaces/InferTypeOpInterface.td"
include "mlir/Interfaces/SideEffectInterfaces.td"
class Complex_Op<string mnemonic, list<Trait> traits = []>
: Op<Complex_Dialect, mnemonic, traits>;
// Base class for standard arithmetic operations on complex numbers with a
// floating-point element type. These operations take two operands and return
// one result, all of which must be complex numbers of the same type.
class ComplexArithmeticOp<string mnemonic, list<Trait> traits = []> :
Complex_Op<mnemonic, traits # [Pure, SameOperandsAndResultType,
Elementwise, DeclareOpInterfaceMethods<ArithFastMathInterface>]> {
let arguments = (ins Complex<AnyFloat>:$lhs, Complex<AnyFloat>:$rhs, DefaultValuedAttr<
Arith_FastMathAttr, "::mlir::arith::FastMathFlags::none">:$fastmath);
let results = (outs Complex<AnyFloat>:$result);
let assemblyFormat = "$lhs `,` $rhs (`fastmath` `` $fastmath^)? attr-dict `:` type($result)";
}
// Base class for standard unary operations on complex numbers with a
// floating-point element type. These operations take one operand and return
// one result; the operand must be a complex number.
class ComplexUnaryOp<string mnemonic, list<Trait> traits = []> :
Complex_Op<mnemonic, traits # [Pure, Elementwise, DeclareOpInterfaceMethods<ArithFastMathInterface>]> {
let arguments = (ins Complex<AnyFloat>:$complex, DefaultValuedAttr<
Arith_FastMathAttr, "::mlir::arith::FastMathFlags::none">:$fastmath);
let assemblyFormat = "$complex (`fastmath` `` $fastmath^)? attr-dict `:` type($complex)";
}
//===----------------------------------------------------------------------===//
// AbsOp
//===----------------------------------------------------------------------===//
def AbsOp : ComplexUnaryOp<"abs",
[TypesMatchWith<"complex element type matches result type",
"complex", "result",
"::llvm::cast<ComplexType>($_self).getElementType()">]> {
let summary = "computes absolute value of a complex number";
let description = [{
The `abs` op takes a single complex number and computes its absolute value.
Example:
```mlir
%a = complex.abs %b : complex<f32>
```
}];
let results = (outs AnyFloat:$result);
}
//===----------------------------------------------------------------------===//
// AddOp
//===----------------------------------------------------------------------===//
def AddOp : ComplexArithmeticOp<"add"> {
let summary = "complex addition";
let description = [{
The `add` operation takes two complex numbers and returns their sum.
Example:
```mlir
%a = complex.add %b, %c : complex<f32>
```
}];
let hasFolder = 1;
}
//===----------------------------------------------------------------------===//
// Atan2
//===----------------------------------------------------------------------===//
def Atan2Op : ComplexArithmeticOp<"atan2"> {
let summary = "complex 2-argument arctangent";
let description = [{
For complex numbers it is expressed using complex logarithm
atan2(y, x) = -i * log((x + i * y) / sqrt(x**2 + y**2))
Example:
```mlir
%a = complex.atan2 %b, %c : complex<f32>
```
}];
}
//===----------------------------------------------------------------------===//
// Bitcast
//===----------------------------------------------------------------------===//
def BitcastOp : Complex_Op<"bitcast", [Pure]> {
let summary = "computes bitcast between complex and equal arith types";
let description = [{
Example:
```mlir
%a = complex.bitcast %b : complex<f32> -> i64
```
}];
let assemblyFormat = "$operand attr-dict `:` type($operand) `to` type($result)";
let arguments = (ins AnyType:$operand);
let results = (outs AnyType:$result);
let hasCanonicalizer = 1;
let hasFolder = 1;
let hasVerifier = 1;
}
//===----------------------------------------------------------------------===//
// ConstantOp
//===----------------------------------------------------------------------===//
def ConstantOp : Complex_Op<"constant", [
ConstantLike, Pure,
DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmResultNames"]>
]> {
let summary = "complex number constant operation";
let description = [{
The `complex.constant` operation creates a constant complex number from an
attribute containing the real and imaginary parts.
Example:
```mlir
%a = complex.constant [0.1, -1.0] : complex<f64>
```
}];
let arguments = (ins ArrayAttr:$value);
let results = (outs AnyComplex:$complex);
let assemblyFormat = "$value attr-dict `:` type($complex)";
let hasFolder = 1;
let hasVerifier = 1;
let extraClassDeclaration = [{
/// Returns true if a constant operation can be built with the given value
/// and result type.
static bool isBuildableWith(Attribute value, Type type);
}];
}
//===----------------------------------------------------------------------===//
// CosOp
//===----------------------------------------------------------------------===//
def CosOp : ComplexUnaryOp<"cos", [SameOperandsAndResultType]> {
let summary = "computes cosine of a complex number";
let description = [{
The `cos` op takes a single complex number and computes the cosine of
it, i.e. `cos(x)`, where `x` is the input value.
Example:
```mlir
%a = complex.cos %b : complex<f32>
```
}];
let results = (outs Complex<AnyFloat>:$result);
}
//===----------------------------------------------------------------------===//
// CreateOp
//===----------------------------------------------------------------------===//
def CreateOp : Complex_Op<"create",
[Pure,
AllTypesMatch<["real", "imaginary"]>,
TypesMatchWith<"complex element type matches real operand type",
"complex", "real",
"::llvm::cast<ComplexType>($_self).getElementType()">,
TypesMatchWith<"complex element type matches imaginary operand type",
"complex", "imaginary",
"::llvm::cast<ComplexType>($_self).getElementType()">]> {
let summary = "complex number creation operation";
let description = [{
The `complex.create` operation creates a complex number from two
floating-point operands, the real and the imaginary part.
Example:
```mlir
%a = complex.create %b, %c : complex<f32>
```
}];
let arguments = (ins AnyFloat:$real, AnyFloat:$imaginary);
let results = (outs Complex<AnyFloat>:$complex);
let assemblyFormat = "$real `,` $imaginary attr-dict `:` type($complex)";
let hasFolder = 1;
}
//===----------------------------------------------------------------------===//
// DivOp
//===----------------------------------------------------------------------===//
def DivOp : ComplexArithmeticOp<"div"> {
let summary = "complex division";
let description = [{
The `div` operation takes two complex numbers and returns result of their
division:
```mlir
%a = complex.div %b, %c : complex<f32>
```
}];
let hasFolder = 1;
}
//===----------------------------------------------------------------------===//
// EqualOp
//===----------------------------------------------------------------------===//
def EqualOp : Complex_Op<"eq",
[Pure, AllTypesMatch<["lhs", "rhs"]>, Elementwise]> {
let summary = "computes whether two complex values are equal";
let description = [{
The `eq` op takes two complex numbers and returns whether they are equal.
Example:
```mlir
%a = complex.eq %b, %c : complex<f32>
```
}];
let arguments = (ins Complex<AnyFloat>:$lhs, Complex<AnyFloat>:$rhs);
let results = (outs I1:$result);
let assemblyFormat = "$lhs `,` $rhs attr-dict `:` type($lhs)";
}
//===----------------------------------------------------------------------===//
// ExpOp
//===----------------------------------------------------------------------===//
def ExpOp : ComplexUnaryOp<"exp", [SameOperandsAndResultType]> {
let summary = "computes exponential of a complex number";
let description = [{
The `exp` op takes a single complex number and computes the exponential of
it, i.e. `exp(x)` or `e^(x)`, where `x` is the input value.
`e` denotes Euler's number and is approximately equal to 2.718281.
Example:
```mlir
%a = complex.exp %b : complex<f32>
```
}];
let results = (outs Complex<AnyFloat>:$result);
let hasFolder = 1;
}
//===----------------------------------------------------------------------===//
// Expm1Op
//===----------------------------------------------------------------------===//
def Expm1Op : ComplexUnaryOp<"expm1", [SameOperandsAndResultType]> {
let summary = "computes exponential of a complex number minus 1";
let description = [{
complex.expm1(x) := complex.exp(x) - 1
Example:
```mlir
%a = complex.expm1 %b : complex<f32>
```
}];
let results = (outs Complex<AnyFloat>:$result);
}
//===----------------------------------------------------------------------===//
// ImOp
//===----------------------------------------------------------------------===//
def ImOp : ComplexUnaryOp<"im",
[TypesMatchWith<"complex element type matches result type",
"complex", "imaginary",
"::llvm::cast<ComplexType>($_self).getElementType()">]> {
let summary = "extracts the imaginary part of a complex number";
let description = [{
The `im` op takes a single complex number and extracts the imaginary part.
Example:
```mlir
%a = complex.im %b : complex<f32>
```
}];
let results = (outs AnyFloat:$imaginary);
let hasFolder = 1;
let hasCanonicalizer = 1;
}
//===----------------------------------------------------------------------===//
// LogOp
//===----------------------------------------------------------------------===//
def LogOp : ComplexUnaryOp<"log", [SameOperandsAndResultType]> {
let summary = "computes natural logarithm of a complex number";
let description = [{
The `log` op takes a single complex number and computes the natural
logarithm of it, i.e. `log(x)` or `log_e(x)`, where `x` is the input value.
`e` denotes Euler's number and is approximately equal to 2.718281.
Example:
```mlir
%a = complex.log %b : complex<f32>
```
}];
let results = (outs Complex<AnyFloat>:$result);
let hasFolder = 1;
}
//===----------------------------------------------------------------------===//
// Log1pOp
//===----------------------------------------------------------------------===//
def Log1pOp : ComplexUnaryOp<"log1p", [SameOperandsAndResultType]> {
let summary = "computes natural logarithm of a complex number";
let description = [{
The `log` op takes a single complex number and computes the natural
logarithm of one plus the given value, i.e. `log(1 + x)` or `log_e(1 + x)`,
where `x` is the input value. `e` denotes Euler's number and is
approximately equal to 2.718281.
Example:
```mlir
%a = complex.log1p %b : complex<f32>
```
}];
let results = (outs Complex<AnyFloat>:$result);
}
//===----------------------------------------------------------------------===//
// MulOp
//===----------------------------------------------------------------------===//
def MulOp : ComplexArithmeticOp<"mul"> {
let summary = "complex multiplication";
let description = [{
The `mul` operation takes two complex numbers and returns their product:
```mlir
%a = complex.mul %b, %c : complex<f32>
```
}];
let hasFolder = 1;
}
//===----------------------------------------------------------------------===//
// NegOp
//===----------------------------------------------------------------------===//
def NegOp : ComplexUnaryOp<"neg", [SameOperandsAndResultType]> {
let summary = "Negation operator";
let description = [{
The `neg` op takes a single complex number `complex` and returns `-complex`.
Example:
```mlir
%a = complex.neg %b : complex<f32>
```
}];
let results = (outs Complex<AnyFloat>:$result);
let hasFolder = 1;
}
//===----------------------------------------------------------------------===//
// NotEqualOp
//===----------------------------------------------------------------------===//
def NotEqualOp : Complex_Op<"neq",
[Pure, AllTypesMatch<["lhs", "rhs"]>, Elementwise]> {
let summary = "computes whether two complex values are not equal";
let description = [{
The `neq` op takes two complex numbers and returns whether they are not
equal.
Example:
```mlir
%a = complex.neq %b, %c : complex<f32>
```
}];
let arguments = (ins Complex<AnyFloat>:$lhs, Complex<AnyFloat>:$rhs);
let results = (outs I1:$result);
let assemblyFormat = "$lhs `,` $rhs attr-dict `:` type($lhs)";
}
//===----------------------------------------------------------------------===//
// PowOp
//===----------------------------------------------------------------------===//
def PowOp : ComplexArithmeticOp<"pow"> {
let summary = "complex power function";
let description = [{
The `sqrt` operation takes a complex number raises it to the given complex
exponent.
Example:
```mlir
%a = complex.pow %b, %c : complex<f32>
```
}];
}
//===----------------------------------------------------------------------===//
// ReOp
//===----------------------------------------------------------------------===//
def ReOp : ComplexUnaryOp<"re",
[TypesMatchWith<"complex element type matches result type",
"complex", "real",
"::llvm::cast<ComplexType>($_self).getElementType()">]> {
let summary = "extracts the real part of a complex number";
let description = [{
The `re` op takes a single complex number and extracts the real part.
Example:
```mlir
%a = complex.re %b : complex<f32>
```
}];
let results = (outs AnyFloat:$real);
let hasFolder = 1;
let hasCanonicalizer = 1;
}
//===----------------------------------------------------------------------===//
// RsqrtOp
//===----------------------------------------------------------------------===//
def RsqrtOp : ComplexUnaryOp<"rsqrt", [SameOperandsAndResultType]> {
let summary = "complex reciprocal of square root";
let description = [{
The `rsqrt` operation computes reciprocal of square root.
Example:
```mlir
%a = complex.rsqrt %b : complex<f32>
```
}];
let results = (outs Complex<AnyFloat>:$result);
}
//===----------------------------------------------------------------------===//
// SignOp
//===----------------------------------------------------------------------===//
def SignOp : ComplexUnaryOp<"sign", [SameOperandsAndResultType]> {
let summary = "computes sign of a complex number";
let description = [{
The `sign` op takes a single complex number and computes the sign of
it, i.e. `y = sign(x) = x / |x|` if `x != 0`, otherwise `y = 0`.
Example:
```mlir
%a = complex.sign %b : complex<f32>
```
}];
let results = (outs Complex<AnyFloat>:$result);
}
//===----------------------------------------------------------------------===//
// SinOp
//===----------------------------------------------------------------------===//
def SinOp : ComplexUnaryOp<"sin", [SameOperandsAndResultType]> {
let summary = "computes sine of a complex number";
let description = [{
The `sin` op takes a single complex number and computes the sine of
it, i.e. `sin(x)`, where `x` is the input value.
Example:
```mlir
%a = complex.sin %b : complex<f32>
```
}];
let results = (outs Complex<AnyFloat>:$result);
}
//===----------------------------------------------------------------------===//
// SqrtOp
//===----------------------------------------------------------------------===//
def SqrtOp : ComplexUnaryOp<"sqrt", [SameOperandsAndResultType]> {
let summary = "complex square root";
let description = [{
The `sqrt` operation takes a complex number and returns its square root.
Example:
```mlir
%a = complex.sqrt %b : complex<f32>
```
}];
let results = (outs Complex<AnyFloat>:$result);
}
//===----------------------------------------------------------------------===//
// SubOp
//===----------------------------------------------------------------------===//
def SubOp : ComplexArithmeticOp<"sub"> {
let summary = "complex subtraction";
let description = [{
The `sub` operation takes two complex numbers and returns their difference.
Example:
```mlir
%a = complex.sub %b, %c : complex<f32>
```
}];
let hasFolder = 1;
}
//===----------------------------------------------------------------------===//
// TanhOp
//===----------------------------------------------------------------------===//
def TanhOp : ComplexUnaryOp<"tanh", [SameOperandsAndResultType]> {
let summary = "complex hyperbolic tangent";
let description = [{
The `tanh` operation takes a complex number and returns its hyperbolic
tangent.
Example:
```mlir
%a = complex.tanh %b : complex<f32>
```
}];
let results = (outs Complex<AnyFloat>:$result);
}
//===----------------------------------------------------------------------===//
// TanOp
//===----------------------------------------------------------------------===//
def TanOp : ComplexUnaryOp<"tan", [SameOperandsAndResultType]> {
let summary = "computes tangent of a complex number";
let description = [{
The `tan` op takes a single complex number and computes the tangent of
it, i.e. `tan(x)`, where `x` is the input value.
Example:
```mlir
%a = complex.tan %b : complex<f32>
```
}];
let results = (outs Complex<AnyFloat>:$result);
}
//===----------------------------------------------------------------------===//
// Conj
//===----------------------------------------------------------------------===//
def ConjOp : ComplexUnaryOp<"conj", [SameOperandsAndResultType]> {
let summary = "Calculate the complex conjugate";
let description = [{
The `conj` op takes a single complex number and computes the
complex conjugate.
Example:
```mlir
%a = complex.conj %b: complex<f32>
```
}];
let results = (outs Complex<AnyFloat>:$result);
let hasFolder = 1;
}
//===----------------------------------------------------------------------===//
// AngleOp
//===----------------------------------------------------------------------===//
def AngleOp : ComplexUnaryOp<"angle",
[TypesMatchWith<"complex element type matches result type",
"complex", "result",
"::llvm::cast<ComplexType>($_self).getElementType()">]> {
let summary = "computes argument value of a complex number";
let description = [{
The `angle` op takes a single complex number and computes its argument value with a branch cut along the negative real axis.
Example:
```mlir
%a = complex.angle %b : complex<f32>
```
}];
let results = (outs AnyFloat:$result);
}
#endif // COMPLEX_OPS