//===- PolynomialOps.td - Polynomial 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
//
//===----------------------------------------------------------------------===//
#ifndef POLYNOMIAL_ATTRIBUTES
#define POLYNOMIAL_ATTRIBUTES
include "mlir/IR/BuiltinAttributes.td"
include "mlir/Dialect/Polynomial/IR/PolynomialDialect.td"
class Polynomial_Attr<string name, string attrMnemonic, list<Trait> traits = []>
: AttrDef<Polynomial_Dialect, name, traits> {
let mnemonic = attrMnemonic;
}
def Polynomial_IntPolynomialAttr : Polynomial_Attr<"IntPolynomial", "int_polynomial"> {
let summary = "an attribute containing a single-variable polynomial with integer coefficients";
let description = [{
A polynomial attribute represents a single-variable polynomial with integer
coefficients, which is used to define the modulus of a `RingAttr`, as well
as to define constants and perform constant folding for `polynomial` ops.
The polynomial must be expressed as a list of monomial terms, with addition
or subtraction between them. The choice of variable name is arbitrary, but
must be consistent across all the monomials used to define a single
attribute. The order of monomial terms is arbitrary, each monomial degree
must occur at most once.
Example:
```mlir
#poly = #polynomial.int_polynomial<x**1024 + 1>
```
}];
let parameters = (ins "::mlir::polynomial::IntPolynomial":$polynomial);
let hasCustomAssemblyFormat = 1;
}
def Polynomial_FloatPolynomialAttr : Polynomial_Attr<"FloatPolynomial", "float_polynomial"> {
let summary = "an attribute containing a single-variable polynomial with double precision floating point coefficients";
let description = [{
A polynomial attribute represents a single-variable polynomial with double
precision floating point coefficients.
The polynomial must be expressed as a list of monomial terms, with addition
or subtraction between them. The choice of variable name is arbitrary, but
must be consistent across all the monomials used to define a single
attribute. The order of monomial terms is arbitrary, each monomial degree
must occur at most once.
Example:
```mlir
#poly = #polynomial.float_polynomial<0.5 x**7 + 1.5>
```
}];
let parameters = (ins "FloatPolynomial":$polynomial);
let hasCustomAssemblyFormat = 1;
}
def Polynomial_TypedIntPolynomialAttr : Polynomial_Attr<
"TypedIntPolynomial", "typed_int_polynomial", [TypedAttrInterface]> {
let summary = "a typed int_polynomial";
let description = [{
Example:
```mlir
!poly_ty = !polynomial.polynomial<ring=<coefficientType=i32>>
#poly = int<1 x**7 + 4> : !poly_ty
#poly_verbose = #polynomial.typed_int_polynomial<1 x**7 + 4> : !poly_ty
```
}];
let parameters = (ins "::mlir::Type":$type, "::mlir::polynomial::IntPolynomialAttr":$value);
let assemblyFormat = "$value `:` $type";
let builders = [
AttrBuilderWithInferredContext<(ins "Type":$type,
"const IntPolynomial &":$value), [{
return $_get(
type.getContext(),
type,
IntPolynomialAttr::get(type.getContext(), value));
}]>,
AttrBuilderWithInferredContext<(ins "Type":$type,
"const Attribute &":$value), [{
return $_get(type.getContext(), type, ::llvm::cast<IntPolynomialAttr>(value));
}]>
];
let extraClassDeclaration = [{
using ValueType = ::mlir::Attribute;
}];
}
def Polynomial_TypedFloatPolynomialAttr : Polynomial_Attr<
"TypedFloatPolynomial", "typed_float_polynomial", [TypedAttrInterface]> {
let summary = "a typed float_polynomial";
let description = [{
Example:
```mlir
!poly_ty = !polynomial.polynomial<ring=<coefficientType=f32>>
#poly = float<1.4 x**7 + 4.5> : !poly_ty
#poly_verbose = #polynomial.typed_float_polynomial<1.4 x**7 + 4.5> : !poly_ty
```
}];
let parameters = (ins "::mlir::Type":$type, "::mlir::polynomial::FloatPolynomialAttr":$value);
let assemblyFormat = "$value `:` $type";
let builders = [
AttrBuilderWithInferredContext<(ins "Type":$type,
"const FloatPolynomial &":$value), [{
return $_get(
type.getContext(),
type,
FloatPolynomialAttr::get(type.getContext(), value));
}]>,
AttrBuilderWithInferredContext<(ins "Type":$type,
"const Attribute &":$value), [{
return $_get(type.getContext(), type, ::llvm::cast<FloatPolynomialAttr>(value));
}]>
];
let extraClassDeclaration = [{
using ValueType = ::mlir::Attribute;
}];
}
def Polynomial_RingAttr : Polynomial_Attr<"Ring", "ring"> {
let summary = "an attribute specifying a polynomial ring";
let description = [{
A ring describes the domain in which polynomial arithmetic occurs. The ring
attribute in `polynomial` represents the more specific case of polynomials
with a single indeterminate; whose coefficients can be represented by
another MLIR type (`coefficientType`); and, if the coefficient type is
integral, whose coefficients are taken modulo some statically known modulus
(`coefficientModulus`).
Additionally, a polynomial ring can specify a _polynomialModulus_, which converts
polynomial arithmetic to the analogue of modular integer arithmetic, where
each polynomial is represented as its remainder when dividing by the
modulus. For single-variable polynomials, an "polynomialModulus" is always specificed
via a single polynomial, which we call `polynomialModulus`.
An expressive example is polynomials with i32 coefficients, whose
coefficients are taken modulo `2**32 - 5`, with a polynomial modulus of
`x**1024 - 1`.
```mlir
#poly_mod = #polynomial.int_polynomial<-1 + x**1024>
#ring = #polynomial.ring<coefficientType=i32,
coefficientModulus=4294967291:i32,
polynomialModulus=#poly_mod>
%0 = ... : polynomial.polynomial<#ring>
```
In this case, the value of a polynomial is always "converted" to a
canonical form by applying repeated reductions by setting `x**1024 = 1`
and simplifying.
The coefficient and polynomial modulus parameters are optional, and the
coefficient modulus is only allowed if the coefficient type is integral.
The coefficient modulus, if specified, should be positive and not larger
than `2 ** width(coefficientType)`.
If the coefficient modulus is not specified, the handling of coefficients
overflows is determined by subsequent lowering passes, which may choose to
wrap around or widen the overflow at their discretion.
Note that coefficient modulus is contained in `i64` by default, which is signed.
To specify a 64 bit number without intepreting it as a negative number, its container
type should be manually specified like `coefficientModulus=18446744073709551615:i128`.
}];
let parameters = (ins
"Type": $coefficientType,
OptionalParameter<"::mlir::IntegerAttr">: $coefficientModulus,
OptionalParameter<"::mlir::polynomial::IntPolynomialAttr">: $polynomialModulus
);
let genVerifyDecl = 1;
let assemblyFormat = "`<` struct(params) `>`";
let builders = [
AttrBuilderWithInferredContext<
(ins "::mlir::Type":$coefficientTy,
CArg<"::mlir::IntegerAttr", "nullptr"> :$coefficientModulusAttr,
CArg<"::mlir::polynomial::IntPolynomialAttr", "nullptr"> :$polynomialModulusAttr), [{
return $_get(
coefficientTy.getContext(),
coefficientTy,
coefficientModulusAttr,
polynomialModulusAttr);
}]>,
];
}
def Polynomial_PrimitiveRootAttr: Polynomial_Attr<"PrimitiveRoot", "primitive_root"> {
let summary = "an attribute containing an integer and its degree as a root of unity";
let description = [{
A primitive root attribute stores an integer root `value` and an integer
`degree`, corresponding to a primitive root of unity of the given degree in
an unspecified ring.
This is used as an attribute on `polynomial.ntt` and `polynomial.intt` ops
to specify the root of unity used in lowering the transform.
Example:
```mlir
#poly = #polynomial.primitive_root<value=123 : i32, degree : 7 index>
```
}];
let parameters = (ins
"::mlir::IntegerAttr":$value,
"::mlir::IntegerAttr":$degree
);
let assemblyFormat = "`<` struct(params) `>`";
}
#endif // POLYNOMIAL_ATTRIBUTES