@@ -35,18 +35,18 @@ def Polynomial_Dialect : Dialect {
3535
3636 ```mlir
3737 // A constant polynomial in a ring with i32 coefficients and no polynomial modulus
38- #ring = #polynomial.ring<ctype =i32>
38+ #ring = #polynomial.ring<coefficientType =i32>
3939 %a = polynomial.constant <1 + x**2 - 3x**3> : polynomial.polynomial<#ring>
4040
4141 // A constant polynomial in a ring with i32 coefficients, modulo (x^1024 + 1)
4242 #modulus = #polynomial.polynomial<1 + x**1024>
43- #ring = #polynomial.ring<ctype =i32, ideal =#modulus>
43+ #ring = #polynomial.ring<coefficientType =i32, polynomialModulus =#modulus>
4444 %a = polynomial.constant <1 + x**2 - 3x**3> : polynomial.polynomial<#ring>
4545
4646 // A constant polynomial in a ring with i32 coefficients, with a polynomial
4747 // modulus of (x^1024 + 1) and a coefficient modulus of 17.
4848 #modulus = #polynomial.polynomial<1 + x**1024>
49- #ring = #polynomial.ring<ctype =i32, cmod =17, ideal =#modulus>
49+ #ring = #polynomial.ring<coefficientType =i32, coefficientModulus =17, polynomialModulus =#modulus>
5050 %a = polynomial.constant <1 + x**2 - 3x**3> : polynomial.polynomial<#ring>
5151 ```
5252 }];
@@ -63,7 +63,21 @@ class Polynomial_Attr<string name, string attrMnemonic, list<Trait> traits = []>
6363def Polynomial_PolynomialAttr : Polynomial_Attr<"Polynomial", "polynomial"> {
6464 let summary = "An attribute containing a single-variable polynomial.";
6565 let description = [{
66- #poly = #polynomial.poly<x**1024 + 1>
66+ A polynomial attribute represents a single-variable polynomial, which
67+ is used to define the modulus of a `RingAttr`, as well as to define constants
68+ and perform constant folding for `polynomial` ops.
69+
70+ The polynomial must be expressed as a list of monomial terms, with addition
71+ or subtraction between them. The choice of variable name is arbitrary, but
72+ must be consistent across all the monomials used to define a single
73+ attribute. The order of monomial terms is arbitrary, each monomial degree
74+ must occur at most once.
75+
76+ Example:
77+
78+ ```mlir
79+ #poly = #polynomial.polynomial<x**1024 + 1>
80+ ```
6781 }];
6882 let parameters = (ins "Polynomial":$polynomial);
6983 let hasCustomAssemblyFormat = 1;
@@ -79,10 +93,10 @@ def Polynomial_RingAttr : Polynomial_Attr<"Ring", "ring"> {
7993 integral, whose coefficients are taken modulo some statically known modulus
8094 (`coefficientModulus`).
8195
82- Additionally, a polynomial ring can specify an _ideal_ , which converts
96+ Additionally, a polynomial ring can specify a _polynomialModulus_ , which converts
8397 polynomial arithmetic to the analogue of modular integer arithmetic, where
8498 each polynomial is represented as its remainder when dividing by the
85- modulus. For single-variable polynomials, an "ideal " is always specificed
99+ modulus. For single-variable polynomials, an "polynomialModulus " is always specificed
86100 via a single polynomial, which we call `polynomialModulus`.
87101
88102 An expressive example is polynomials with i32 coefficients, whose
@@ -122,32 +136,284 @@ class Polynomial_Type<string name, string typeMnemonic>
122136
123137def Polynomial_PolynomialType : Polynomial_Type<"Polynomial", "polynomial"> {
124138 let summary = "An element of a polynomial ring.";
125-
126139 let description = [{
127140 A type for polynomials in a polynomial quotient ring.
128141 }];
129-
130142 let parameters = (ins Polynomial_RingAttr:$ring);
131143 let assemblyFormat = "`<` $ring `>`";
132144}
133145
146+ def PolynomialLike: TypeOrContainer<Polynomial_PolynomialType, "polynomial-like">;
147+
134148class Polynomial_Op<string mnemonic, list<Trait> traits = []> :
135- Op<Polynomial_Dialect, mnemonic, traits # [Pure]>;
149+ Op<Polynomial_Dialect, mnemonic, traits # [Pure]> {
150+ let assemblyFormat = "operands attr-dict `:` functional-type(operands, results)";
151+ }
136152
137153class Polynomial_UnaryOp<string mnemonic, list<Trait> traits = []> :
138154 Polynomial_Op<mnemonic, traits # [SameOperandsAndResultType]> {
139155 let arguments = (ins Polynomial_PolynomialType:$operand);
140156 let results = (outs Polynomial_PolynomialType:$result);
141-
142- let assemblyFormat = "$operand attr-dict `:` qualified(type($result))";
143157}
144158
145159class Polynomial_BinaryOp<string mnemonic, list<Trait> traits = []> :
146- Polynomial_Op<mnemonic, traits # [SameOperandsAndResultType]> {
147- let arguments = (ins Polynomial_PolynomialType:$lhs, Polynomial_PolynomialType:$rhs);
148- let results = (outs Polynomial_PolynomialType:$result);
160+ Polynomial_Op<mnemonic, !listconcat(traits, [Pure, SameOperandsAndResultType, ElementwiseMappable])> {
161+ let arguments = (ins PolynomialLike:$lhs, PolynomialLike:$rhs);
162+ let results = (outs PolynomialLike:$result);
163+ let assemblyFormat = "operands attr-dict `:` type($result)";
164+ }
165+
166+ def Polynomial_AddOp : Polynomial_BinaryOp<"add", [Commutative]> {
167+ let summary = "Addition operation between polynomials.";
168+ let description = [{
169+ Performs polynomial addition on the operands. The operands may be single
170+ polynomials or containers of identically-typed polynomials, i.e., polynomials
171+ from the same underlying ring with the same coefficient types.
172+
173+ Addition is defined to occur in the ring defined by the ring attribute of
174+ the two operands, meaning the addition is taken modulo the coefficientModulus
175+ and the polynomialModulus of the ring.
176+
177+ Example:
178+
179+ ```mlir
180+ // add two polynomials modulo x^1024 - 1
181+ #poly = #polynomial.polynomial<x**1024 - 1>
182+ #ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
183+ %0 = polynomial.constant #polynomial.polynomial<1 + x**2> : !polynomial.polynomial<#ring>
184+ %1 = polynomial.constant #polynomial.polynomial<x**5 - x + 1> : !polynomial.polynomial<#ring>
185+ %2 = polynomial.add %0, %1 : !polynomial.polynomial<#ring>
186+ ```
187+ }];
188+ }
189+
190+ def Polynomial_SubOp : Polynomial_BinaryOp<"sub"> {
191+ let summary = "Subtraction operation between polynomials.";
192+ let description = [{
193+ Performs polynomial subtraction on the operands. The operands may be single
194+ polynomials or containers of identically-typed polynomials, i.e., polynomials
195+ from the same underlying ring with the same coefficient types.
196+
197+ Subtraction is defined to occur in the ring defined by the ring attribute of
198+ the two operands, meaning the subtraction is taken modulo the coefficientModulus
199+ and the polynomialModulus of the ring.
200+
201+ Example:
149202
150- let assemblyFormat = "$lhs `,` $rhs attr-dict `:` qualified(type($result))";
203+ ```mlir
204+ // subtract two polynomials modulo x^1024 - 1
205+ #poly = #polynomial.polynomial<x**1024 - 1>
206+ #ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
207+ %0 = polynomial.constant #polynomial.polynomial<1 + x**2> : !polynomial.polynomial<#ring>
208+ %1 = polynomial.constant #polynomial.polynomial<x**5 - x + 1> : !polynomial.polynomial<#ring>
209+ %2 = polynomial.sub %0, %1 : !polynomial.polynomial<#ring>
210+ ```
211+ }];
212+ }
213+
214+ def Polynomial_MulOp : Polynomial_BinaryOp<"mul", [Commutative]> {
215+ let summary = "Multiplication operation between polynomials.";
216+ let description = [{
217+ Performs polynomial multiplication on the operands. The operands may be single
218+ polynomials or containers of identically-typed polynomials, i.e., polynomials
219+ from the same underlying ring with the same coefficient types.
220+
221+ Multiplication is defined to occur in the ring defined by the ring attribute of
222+ the two operands, meaning the multiplication is taken modulo the coefficientModulus
223+ and the polynomialModulus of the ring.
224+
225+ Example:
226+
227+ ```mlir
228+ // multiply two polynomials modulo x^1024 - 1
229+ #poly = #polynomial.polynomial<x**1024 - 1>
230+ #ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
231+ %0 = polynomial.constant #polynomial.polynomial<1 + x**2> : !polynomial.polynomial<#ring>
232+ %1 = polynomial.constant #polynomial.polynomial<x**5 - x + 1> : !polynomial.polynomial<#ring>
233+ %2 = polynomial.mul %0, %1 : !polynomial.polynomial<#ring>
234+ ```
235+ }];
236+ }
237+
238+ def Polynomial_MulScalarOp : Polynomial_Op<"mul_scalar", [
239+ ElementwiseMappable, AllTypesMatch<["polynomial", "output"]>]> {
240+ let summary = "Multiplication by a scalar of the field.";
241+ let description = [{
242+ Multiplies the polynomial operand's coefficients by a given scalar value.
243+ The operation is defined to occur in the ring defined by the ring attribute
244+ of the two operands, meaning the multiplication is taken modulo the
245+ coefficientModulus of the ring.
246+
247+ The `scalar` input must have the same type as the polynomial ring's
248+ coefficientType.
249+
250+ Example:
251+
252+ ```mlir
253+ // multiply two polynomials modulo x^1024 - 1
254+ #poly = #polynomial.polynomial<x**1024 - 1>
255+ #ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
256+ %0 = polynomial.constant #polynomial.polynomial<1 + x**2> : !polynomial.polynomial<#ring>
257+ %1 = arith.constant 3 : i32
258+ %2 = polynomial.mul_scalar %0, %1 : !polynomial.polynomial<#ring>, i32
259+ ```
260+ }];
261+
262+ let arguments = (ins
263+ PolynomialLike:$polynomial,
264+ AnyInteger:$scalar
265+ );
266+ let results = (outs
267+ PolynomialLike:$output
268+ );
269+ let assemblyFormat = "operands attr-dict `:` type($polynomial) `,` type($scalar)";
270+ let hasVerifier = 1;
271+ }
272+
273+ def Polynomial_LeadingTermOp: Polynomial_Op<"leading_term"> {
274+ let summary = "Compute the leading term of the polynomial.";
275+ let description = [{
276+ The degree of a polynomial is the largest $k$ for which the coefficient
277+ `a_k` of `x^k` is nonzero. The leading term is the term `a_k * x^k`, which
278+ this op represents as a pair of results. The first is the degree `k` as an
279+ index, and the second is the coefficient, whose type matches the
280+ coefficient type of the polynomial's ring attribute.
281+
282+ Example:
283+
284+ ```mlir
285+ #poly = #polynomial.polynomial<x**1024 - 1>
286+ #ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
287+ %0 = polynomial.constant #polynomial.polynomial<1 + x**2> : !polynomial.polynomial<#ring>
288+ %1, %2 = polynomial.leading_term %0 : !polynomial.polynomial<#ring> -> (index, i32)
289+ ```
290+ }];
291+ let arguments = (ins Polynomial_PolynomialType:$input);
292+ let results = (outs Index:$degree, AnyInteger:$coefficient);
293+ let assemblyFormat = "operands attr-dict `:` type($input) `->` `(` type($degree) `,` type($coefficient) `)`";
294+ }
295+
296+ def Polynomial_MonomialOp: Polynomial_Op<"monomial"> {
297+ let summary = "Create a polynomial that consists of a single monomial.";
298+ let description = [{
299+ Construct a polynomial that consists of a single monomial term, from its
300+ degree and coefficient as dynamic inputs.
301+
302+ The coefficient type of the output polynomial's ring attribute must match
303+ the `coefficient` input type.
304+
305+ Example:
306+
307+ ```mlir
308+ #poly = #polynomial.polynomial<x**1024 - 1>
309+ #ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
310+ %deg = arith.constant 1023 : index
311+ %five = arith.constant 5 : i32
312+ %0 = polynomial.monomial %five, %deg : (i32, index) -> !polynomial.polynomial<#ring>
313+ ```
314+ }];
315+ let arguments = (ins AnyInteger:$coefficient, Index:$degree);
316+ let results = (outs Polynomial_PolynomialType:$output);
317+ }
318+
319+ def Polynomial_MonicMonomialMulOp: Polynomial_Op<"monic_monomial_mul", [AllTypesMatch<["input", "output"]>]> {
320+ let summary = "Multiply a polynomial by a monic monomial.";
321+ let description = [{
322+ Multiply a polynomial by a monic monomial, meaning a polynomial of the form
323+ `1 * x^k` for an index operand `k`.
324+
325+ In some special rings of polynomials, such as a ring of polynomials
326+ modulo `x^n - 1`, `monomial_mul` can be interpreted as a cyclic shift of
327+ the coefficients of the polynomial. For some rings, this results in
328+ optimized lowerings that involve rotations and rescaling of the
329+ coefficients of the input.
330+ }];
331+ let arguments = (ins PolynomialLike:$input, Index:$monomialDegree);
332+ let results = (outs PolynomialLike:$output);
333+ }
334+
335+ def Polynomial_FromTensorOp : Polynomial_Op<"from_tensor", [Pure]> {
336+ let summary = "Creates a polynomial from integer coefficients stored in a tensor.";
337+ let description = [{
338+ `polynomial.from_tensor` creates a polynomial value from a tensor of coefficients.
339+ The input tensor must list the coefficients in degree-increasing order.
340+
341+ The input one-dimensional tensor may have size at most the degree of the
342+ ring's polynomialModulus generator polynomial, with smaller dimension implying that
343+ all higher-degree terms have coefficient zero.
344+
345+ Example:
346+
347+ ```mlir
348+ #poly = #polynomial.polynomial<x**1024 - 1>
349+ #ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
350+ %two = arith.constant 2 : i32
351+ %five = arith.constant 5 : i32
352+ %coeffs = tensor.from_elements %two, %two, %five : tensor<3xi32>
353+ %poly = polynomial.from_tensor %coeffs : tensor<3xi32> -> !polynomial.polynomial<#ring>
354+ ```
355+ }];
356+ let arguments = (ins RankedTensorOf<[AnyInteger]>:$input);
357+ let results = (outs Polynomial_PolynomialType:$output);
358+
359+ let assemblyFormat = "$input attr-dict `:` type($input) `->` type($output)";
360+
361+ let builders = [
362+ // Builder that infers coefficient modulus from tensor bit width,
363+ // and uses whatever input ring is provided by the caller.
364+ OpBuilder<(ins "::mlir::Value":$input, "::mlir::polynomial::RingAttr":$ring)>
365+ ];
366+ let hasVerifier = 1;
367+ }
368+
369+ def Polynomial_ToTensorOp : Polynomial_Op<"to_tensor", [Pure]> {
370+ let summary = "Creates a tensor containing the coefficients of a polynomial.";
371+ let description = [{
372+ `polynomial.to_tensor` creates a dense tensor value containing the
373+ coefficients of the input polynomial. The output tensor contains the
374+ coefficients in degree-increasing order.
375+
376+ Operations that act on the coefficients of a polynomial, such as extracting
377+ a specific coefficient or extracting a range of coefficients, should be
378+ implemented by composing `to_tensor` with the relevant `tensor` dialect
379+ ops.
380+
381+ The output tensor has shape equal to the degree of the polynomial ring
382+ attribute's polynomialModulus, including zeroes.
383+
384+ Example:
385+
386+ ```mlir
387+ #poly = #polynomial.polynomial<x**1024 - 1>
388+ #ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
389+ %two = arith.constant 2 : i32
390+ %five = arith.constant 5 : i32
391+ %coeffs = tensor.from_elements %two, %two, %five : tensor<3xi32>
392+ %poly = polynomial.from_tensor %coeffs : tensor<3xi32> -> !polynomial.polynomial<#ring>
393+ %tensor = polynomial.to_tensor %poly : !polynomial.polynomial<#ring> -> tensor<1024xi32>
394+ ```
395+ }];
396+ let arguments = (ins Polynomial_PolynomialType:$input);
397+ let results = (outs RankedTensorOf<[AnyInteger]>:$output);
398+ let assemblyFormat = "$input attr-dict `:` type($input) `->` type($output)";
399+
400+ let hasVerifier = 1;
401+ }
402+
403+ def Polynomial_ConstantOp : Polynomial_Op<"constant", [Pure]> {
404+ let summary = "Define a constant polynomial via an attribute.";
405+ let description = [{
406+ Example:
407+
408+ ```mlir
409+ #poly = #polynomial.polynomial<x**1024 - 1>
410+ #ring = #polynomial.ring<coefficientType=i32, coefficientModulus=65536, polynomialModulus=#poly>
411+ %0 = polynomial.constant #polynomial.polynomial<1 + x**2> : !polynomial.polynomial<#ring>
412+ ```
413+ }];
414+ let arguments = (ins Polynomial_PolynomialAttr:$input);
415+ let results = (outs Polynomial_PolynomialType:$output);
416+ let assemblyFormat = "$input attr-dict `:` type($output)";
151417}
152418
153419#endif // POLYNOMIAL_OPS
0 commit comments