3 const builtin_dialect
= require('./dialect/builtin');
4 const func_dialect
= require('./dialect/func');
5 const llvm_dialect
= require('./dialect/llvm');
6 const arith_dialect
= require('./dialect/arith');
7 const math_dialect
= require('./dialect/math');
8 const cf_dialect
= require('./dialect/cf');
9 const scf_dialect
= require('./dialect/scf');
10 const memref_dialect
= require('./dialect/memref');
11 const vector_dialect
= require('./dialect/vector');
12 const tensor_dialect
= require('./dialect/tensor');
13 const bufferization_dialect
= require('./dialect/bufferization');
14 const affine_dialect
= require('./dialect/affine');
15 const linalg_dialect
= require('./dialect/linalg');
18 // Top level production:
19 // (operation | attribute-alias-def | type-alias-def)
20 toplevel
: $ => seq($._toplevel
, repeat($._toplevel
)),
21 _toplevel
: $ => choice($.operation
, $.attribute_alias_def
, $.type_alias_def
),
23 // Common syntax (lang-ref)
25 // hex_digit ::= [0-9a-fA-F]
26 // letter ::= [a-zA-Z]
27 // id-punct ::= [$._-]
29 // integer-literal ::= decimal-literal | hexadecimal-literal
30 // decimal-literal ::= digit+
31 // hexadecimal-literal ::= `0x` hex_digit+
32 // float-literal ::= [-+]?[0-9]+[.][0-9]*([eE][-+]?[0-9]+)?
33 // string-literal ::= `"` [^"\n\f\v\r]* `"` TODO: define escaping rules
35 _digit
: $ => /[0-9]/,
36 integer_literal
: $ => choice($._decimal_literal
, $._hexadecimal_literal
),
37 _decimal_literal
: $ => token(seq(optional(/[-+]/), repeat1(/[0-9]/))),
38 _hexadecimal_literal
: $ => token(seq('0x', repeat1(/[0-9a-fA-F]/))),
40 token(seq(optional(/[-+]/), repeat1(/[0-9]/), '.', repeat(/[0-9]/),
41 optional(seq(/[eE]/, optional(/[-+]/), repeat1(/[0-9]/))))),
42 string_literal
: $ => token(seq('"', repeat(/[^\\"\n\f\v\r]+/), '"')),
43 bool_literal
: $ => token(choice('true', 'false')),
44 unit_literal
: $ => token('unit'),
45 complex_literal
: $ =>
46 seq('(', choice($.integer_literal
, $.float_literal
), ',',
47 choice($.integer_literal
, $.float_literal
), ')'),
49 seq(token(choice('dense', 'sparse')), '<',
51 seq($.nested_idx_list
, repeat(seq(',', $.nested_idx_list
))),
52 $._primitive_idx_literal
)),
54 array_literal
: $ => seq(token('array'), '<', $.type
, ':', $._idx_list
, '>'),
55 _literal
: $ => choice($.integer_literal
, $.float_literal
, $.string_literal
,
56 $.bool_literal
, $.tensor_literal
, $.array_literal
,
57 $.complex_literal
, $.unit_literal
),
59 nested_idx_list
: $ =>
60 seq('[', optional(choice($.nested_idx_list
, $._idx_list
)),
61 repeat(seq(',', $.nested_idx_list
)), ']'),
62 _idx_list
: $ => prec
.right(seq($._primitive_idx_literal
,
63 repeat(seq(',', $._primitive_idx_literal
)))),
64 _primitive_idx_literal
: $ => choice($.integer_literal
, $.float_literal
,
65 $.bool_literal
, $.complex_literal
),
68 // bare-id ::= (letter|[_]) (letter|digit|[_$.])*
69 // bare-id-list ::= bare-id (`,` bare-id)*
70 // value-id ::= `%` suffix-id
71 // suffix-id ::= (digit+ | ((letter|id-punct) (letter|id-punct|digit)*))
72 // alias-name :: = bare-id
74 // symbol-ref-id ::= `@` (suffix-id | string-literal) (`::`
76 // value-id-list ::= value-id (`,` value-id)*
78 // // Uses of value, e.g. in an operand list to an operation.
79 // value-use ::= value-id
80 // value-use-list ::= value-use (`,` value-use)*
81 bare_id
: $ => token(seq(/[a-zA-Z_]/, repeat(/[a-zA-Z0-9_$.]/))),
82 _alias_or_dialect_id
: $ => token(seq(/[a-zA-Z_]/, repeat(/[a-zA-Z0-9_$]/))),
83 bare_id_list
: $ => seq($.bare_id
, repeat(seq(',', $.bare_id
))),
84 value_use
: $ => seq('%', $._suffix_id
),
85 _suffix_id
: $ => token(seq(
86 choice(repeat1(/[0-9]/), seq(/[a-zA-Z_$.-]/, repeat(/[a-zA-Z0-9_$.-]/))),
87 optional(seq(choice(':', '#'), repeat1(/[0-9]/))))),
88 symbol_ref_id
: $ => seq('@', choice($._suffix_id
, $.string_literal
),
89 optional(seq('::', $.symbol_ref_id
))),
90 _value_use_list
: $ => seq($.value_use
, repeat(seq(',', $.value_use
))),
93 // operation ::= op-result-list? (generic-operation |
96 // generic-operation ::= string-literal `(` value-use-list? `)`
97 // successor-list? region-list?
98 // dictionary-attribute? `:` function-type
99 // custom-operation ::= bare-id custom-operation-format
100 // op-result-list ::= op-result (`,` op-result)* `=`
101 // op-result ::= value-id (`:` integer-literal)
102 // successor-list ::= `[` successor (`,` successor)* `]`
103 // successor ::= caret-id (`:` bb-arg-list)?
104 // region-list ::= `(` region (`,` region)* `)`
105 // dictionary-attribute ::= `{` (attribute-entry (`,` attribute-entry)*)?
107 // trailing-location ::= (`loc` `(` location `)`)?
109 seq(field('lhs', optional($._op_result_list
)),
110 field('rhs', choice($.generic_operation
, $.custom_operation
)),
111 field('location', optional($.trailing_location
))),
112 generic_operation
: $ => seq(
113 $.string_literal
, $._value_use_list_parens
, optional($._successor_list
),
114 optional($._region_list
), optional($.attribute
), ':', $.function_type
),
115 // custom-operation rule is defined later in the grammar, post the generic.
116 _op_result_list
: $ => seq($.op_result
, repeat(seq(',', $.op_result
)), '='),
117 op_result
: $ => seq($.value_use
, optional(seq(':', $.integer_literal
))),
118 _successor_list
: $ =>
119 seq('[', $.successor
, repeat(seq(',', $.successor
)), ']'),
120 successor
: $ => seq($.caret_id
, optional($._value_arg_list
)),
121 _region_list
: $ => seq('(', $.region
, repeat(seq(',', $.region
)), ')'),
122 dictionary_attribute
: $ => seq('{', optional($.attribute_entry
),
123 repeat(seq(',', $.attribute_entry
)), '}'),
124 trailing_location
: $ => seq(token('loc'), '(', $.location
, ')'),
125 // TODO: Complete location forms.
126 location
: $ => $.string_literal
,
129 // block ::= block-label operation+
130 // block-label ::= block-id block-arg-list? `:`
131 // block-id ::= caret-id
132 // caret-id ::= `^` suffix-id
133 // value-id-and-type ::= value-id `:` type
135 // // Non-empty list of names and types.
136 // value-id-and-type-list ::= value-id-and-type (`,` value-id-and-type)*
138 // block-arg-list ::= `(` value-id-and-type-list? `)`
139 block
: $ => seq($.block_label
, repeat1($.operation
)),
140 block_label
: $ => seq($._block_id
, optional($.block_arg_list
), ':'),
141 _block_id
: $ => $.caret_id
,
142 caret_id
: $ => seq('^', $._suffix_id
),
143 _value_use_and_type
: $ => seq($.value_use
, optional(seq(':', $.type
))),
144 _value_use_and_type_list
: $ =>
145 seq($._value_use_and_type
, repeat(seq(',', $._value_use_and_type
))),
146 block_arg_list
: $ => seq('(', optional($._value_use_and_type_list
), ')'),
147 _value_arg_list
: $ => seq('(', optional($._value_use_type_list
), ')'),
148 _value_use_type_list
: $ => seq($._value_use_list
, $._type_annotation
),
151 // region ::= `{` entry-block? block* `}`
152 // entry-block ::= operation+
153 region
: $ => seq('{', optional($.entry_block
), repeat($.block
), '}'),
154 entry_block
: $ => repeat1($.operation
),
157 // type ::= type-alias | dialect-type | builtin-type
159 // type-list-no-parens ::= type (`,` type)*
160 // type-list-parens ::= `(` type-list-no-parens? `)`
162 // // This is a common way to refer to a value with a specified type.
163 // ssa-use-and-type ::= ssa-use `:` type
164 // ssa-use ::= value-use
166 // // Non-empty list of names and types.
167 // ssa-use-and-type-list ::= ssa-use-and-type (`,` ssa-use-and-type)*
169 // function-type ::= (type | type-list-parens) `->` (type |
171 type
: $ => choice($.type_alias
, $.dialect_type
, $.builtin_type
),
172 _type_list_no_parens
: $ => prec
.left(seq($.type
, repeat(seq(',', $.type
)))),
173 _type_list_parens
: $ => seq('(', optional($._type_list_no_parens
), ')'),
175 seq(choice($.type
, $._type_list_parens
), $._function_return
),
176 _function_return
: $ => seq(token('->'), choice($.type
, $._type_list_parens
)),
177 _type_annotation
: $ =>
178 seq(':', choice(seq($.type
, choice('from', 'into', 'to'), $.type
),
179 $._type_list_no_parens
)),
180 _function_type_annotation
: $ => seq(':', $.function_type
),
181 _literal_and_type
: $ => seq($._literal
, optional($._type_annotation
)),
184 // type-alias-def ::= '!' alias-name '=' type
185 // type-alias ::= '!' alias-name
186 type_alias_def
: $ => seq('!', $._alias_or_dialect_id
, '=', $.type
),
187 type_alias
: $ => seq('!', $._alias_or_dialect_id
),
190 // dialect-namespace ::= bare-id
192 // opaque-dialect-item ::= dialect-namespace '<' string-literal '>'
194 // pretty-dialect-item ::= dialect-namespace '.'
195 // pretty-dialect-item-lead-ident pretty-dialect-item-body?
197 // pretty-dialect-item-lead-ident ::= '[A-Za-z][A-Za-z0-9._]*'
198 // pretty-dialect-item-body ::= '<' pretty-dialect-item-contents+ '>'
199 // pretty-dialect-item-contents ::= pretty-dialect-item-body
200 // | '(' pretty-dialect-item-contents+ ')'
201 // | '[' pretty-dialect-item-contents+ ']'
202 // | '{' pretty-dialect-item-contents+ '}'
203 // | '[^[<({>\])}\0]+'
205 // dialect-type ::= '!' (opaque-dialect-item | pretty-dialect-item)
207 seq('!', choice($.opaque_dialect_item
, $.pretty_dialect_item
)),
208 dialect_namespace
: $ => $._alias_or_dialect_id
,
209 dialect_ident
: $ => $._alias_or_dialect_id
,
210 opaque_dialect_item
: $ =>
211 seq($.dialect_namespace
, '<', $.string_literal
, '>'),
212 pretty_dialect_item
: $ => seq($.dialect_namespace
, '.', $.dialect_ident
,
213 optional($.pretty_dialect_item_body
)),
214 pretty_dialect_item_body
: $ =>
215 seq('<', repeat($._pretty_dialect_item_contents
), '>'),
216 _pretty_dialect_item_contents
: $ =>
217 prec
.left(choice($.pretty_dialect_item_body
, repeat1(/[^<>]/))),
220 builtin_type
: $ => choice(
221 // TODO: Add opaque_type
222 $.integer_type
, $.float_type
, $.complex_type
, $.index_type
, $.memref_type
,
223 $.none_type
, $.tensor_type
, $.vector_type
, $.tuple_type
),
225 // signed-integer-type ::= `si`[1-9][0-9]*
226 // unsigned-integer-type ::= `ui`[1-9][0-9]*
227 // signless-integer-type ::= `i`[1-9][0-9]*
228 // integer-type ::= signed-integer-type | unsigned-integer-type |
229 // signless-integer-type
231 token(seq(choice('si', 'ui', 'i'), /[1-9]/, repeat(/[0-9]/))),
232 float_type
: $ => token(
233 choice('f16', 'f32', 'f64', 'f80', 'f128', 'bf16', 'f8E4M3FN', 'f8E5M2')),
234 index_type
: $ => token('index'),
235 none_type
: $ => token('none'),
236 complex_type
: $ => seq(token('complex'), '<', $._prim_type
, '>'),
238 choice($.integer_type
, $.float_type
, $.index_type
, $.complex_type
,
239 $.none_type
, $.memref_type
, $.vector_type
, $.tensor_type
),
241 // memref-type ::= `memref` `<` dimension-list-ranked type
242 // (`,` layout-specification)? (`,` memory-space)? `>`
243 // layout-specification ::= attribute-value
244 // memory-space ::= attribute-value
246 seq(token('memref'), '<', field('dimension_list', $.dim_list
),
247 optional(seq(',', $.attribute_value
)),
248 optional(seq(',', $.attribute_value
)), '>'),
249 dim_list
: $ => seq($._dim_primitive
, repeat(seq('x', $._dim_primitive
))),
250 _dim_primitive
: $ => choice($._prim_type
, repeat1($._digit
), '?', '*'),
252 // tensor-type ::= `tensor` `<` dimension-list type (`,` encoding)? `>`
253 // dimension-list ::= (dimension `x`)*
254 // dimension ::= `?` | decimal-literal
255 // encoding ::= attribute-value
256 // tensor-type ::= `tensor` `<` `*` `x` type `>`
257 tensor_type
: $ => seq(token('tensor'), '<', $.dim_list
,
258 optional(seq(',', $.tensor_encoding
)), '>'),
259 tensor_encoding
: $ => $.attribute_value
,
261 // vector-type ::= `vector` `<` vector-dim-list vector-element-type `>`
262 // vector-element-type ::= float-type | integer-type | index-type
263 // vector-dim-list := (static-dim-list `x`)? (`[` static-dim-list `]` `x`)?
264 // static-dim-list ::= decimal-literal (`x` decimal-literal)*
266 seq(token('vector'), '<', optional($.vector_dim_list
), $._prim_type
, '>'),
267 vector_dim_list
: $ =>
268 choice(seq($._static_dim_list
, 'x',
269 optional(seq('[', $._static_dim_list
, ']', 'x'))),
270 seq('[', $._static_dim_list
, ']', 'x')),
271 _static_dim_list
: $ =>
272 seq(repeat1($._digit
), repeat(seq('x', repeat1($._digit
)))),
274 // tuple-type ::= `tuple` `<` (type ( `,` type)*)? `>`
276 seq(token('tuple'), '<', $.tuple_dim
, repeat(seq(',', $.tuple_dim
)), '>'),
277 tuple_dim
: $ => $._prim_type
,
280 // attribute-entry ::= (bare-id | string-literal) `=` attribute-value
281 // attribute-value ::= attribute-alias | dialect-attribute |
283 attribute_entry
: $ => seq(choice($.bare_id
, $.string_literal
),
284 optional(seq('=', $.attribute_value
))),
285 attribute_value
: $ =>
286 choice(seq('[', optional($._attribute_value_nobracket
),
287 repeat(seq(',', $._attribute_value_nobracket
)), ']'),
288 $._attribute_value_nobracket
),
289 _attribute_value_nobracket
: $ =>
290 choice($.attribute_alias
, $.dialect_attribute
, $.builtin_attribute
,
291 $.dictionary_attribute
, $._literal_and_type
, $.type
),
292 attribute
: $ => choice($.attribute_alias
, $.dialect_attribute
,
293 $.builtin_attribute
, $.dictionary_attribute
),
295 // Attribute Value Aliases
296 // attribute-alias-def ::= '#' alias-name '=' attribute-value
297 // attribute-alias ::= '#' alias-name
298 attribute_alias_def
: $ =>
299 seq('#', $._alias_or_dialect_id
, '=', $.attribute_value
),
300 attribute_alias
: $ => seq('#', $._alias_or_dialect_id
),
302 // Dialect Attribute Values
303 dialect_attribute
: $ =>
304 seq('#', choice($.opaque_dialect_item
, $.pretty_dialect_item
)),
306 // Builtin Attribute Values
307 builtin_attribute
: $ => choice(
309 $.strided_layout
, $.affine_map
, $.affine_set
),
310 strided_layout
: $ => seq(token('strided'), '<', '[', $._dim_list_comma
, ']',
311 optional(seq(',', token('offset'), ':',
312 choice($.integer_literal
, '?', '*'))),
314 _dim_list_comma
: $ =>
315 seq($._dim_primitive
, repeat(seq(',', $._dim_primitive
))),
318 seq(token('affine_map'), '<', $._multi_dim_affine_expr_parens
,
319 optional($._multi_dim_affine_expr_sq
), token('->'),
320 $._multi_dim_affine_expr_parens
, '>'),
322 seq(token('affine_set'), '<', $._multi_dim_affine_expr_parens
,
323 optional($._multi_dim_affine_expr_sq
), ':',
324 $._multi_dim_affine_expr_parens
, '>'),
325 _multi_dim_affine_expr_parens
: $ =>
326 seq('(', optional($._multi_dim_affine_expr
), ')'),
327 _multi_dim_affine_expr_sq
: $ =>
328 seq('[', optional($._multi_dim_affine_expr
), ']'),
330 // affine-expr ::= `(` affine-expr `)`
331 // | affine-expr `+` affine-expr
332 // | affine-expr `-` affine-expr
333 // | `-`? integer-literal `*` affine-expr
334 // | affine-expr `ceildiv` integer-literal
335 // | affine-expr `floordiv` integer-literal
336 // | affine-expr `mod` integer-literal
339 // | `-`? integer-literal
340 // multi-dim-affine-expr ::= `(` `)`
341 // | `(` affine-expr (`,` affine-expr)* `)`
343 // semi-affine-expr ::= `(` semi-affine-expr `)`
344 // | semi-affine-expr `+` semi-affine-expr
345 // | semi-affine-expr `-` semi-affine-expr
346 // | symbol-or-const `*` semi-affine-expr
347 // | semi-affine-expr `ceildiv` symbol-or-const
348 // | semi-affine-expr `floordiv` symbol-or-const
349 // | semi-affine-expr `mod` symbol-or-const
351 // | `-`? integer-literal
352 // symbol-or-const ::= `-`? integer-literal | symbol-id
353 // multi-dim-semi-affine-expr ::= `(` semi-affine-expr (`,` semi-affine-expr)*
356 // affine-constraint ::= affine-expr `>=` `affine-expr`
357 // | affine-expr `<=` `affine-expr`
358 // | affine-expr `==` `affine-expr`
359 // affine-constraint-conjunction ::= affine-constraint (`,`
360 // affine-constraint)*
362 _multi_dim_affine_expr
: $ =>
363 seq($._affine_expr
, repeat(seq(',', $._affine_expr
))),
364 _affine_expr
: $ => prec
.right(choice(
365 seq('(', $._affine_expr
, ')'), seq('-', $._affine_expr
),
366 seq($._affine_expr
, $._affine_token
, $._affine_expr
), $._affine_prim
)),
368 choice($.integer_literal
, $.value_use
, $.bare_id
,
369 seq('symbol', '(', $.value_use
, ')'),
370 seq(choice('max', 'min'), '(', $._value_use_list
, ')')),
371 _affine_token
: $ => token(
372 choice('+', '-', '*', 'ceildiv', 'floordiv', 'mod', '==', '>=', '<=')),
374 func_return
: $ => seq(token('->'), $.type_list_attr_parens
),
375 func_arg_list
: $ => seq(
376 '(', optional(choice($.variadic
, $._value_id_and_type_attr_list
)), ')'),
377 _value_id_and_type_attr_list
: $ => seq(
378 $._value_id_and_type_attr
, repeat(seq(',', $._value_id_and_type_attr
)),
379 optional(seq(',', $.variadic
))),
380 _value_id_and_type_attr
: $ => seq($._function_arg
, optional($.attribute
)),
382 choice(seq($.value_use
, ':', $.type
), $.value_use
, $.type
),
383 type_list_attr_parens
: $ =>
385 seq('(', $.type
, optional($.attribute
),
386 repeat(seq(',', $.type
, optional($.attribute
))), ')'),
388 variadic
: $ => token('...'),
390 // (func.func|llvm.func) takes arguments, an optional return type, and and
393 seq(field('visibility', optional('private')),
394 field('name', $.symbol_ref_id
), field('arguments', $.func_arg_list
),
395 field('return', optional($.func_return
)),
396 field('attributes', optional(seq(token('attributes'), $.attribute
))),
397 field('body', optional($.region
))),
399 // dim-use-list ::= `(` ssa-use-list? `)`
400 // symbol-use-list ::= `[` ssa-use-list? `]`
401 // dim-and-symbol-use-list ::= dim-use-list symbol-use-list?
402 _value_use_list_parens
: $ => seq('(', optional($._value_use_list
), ')'),
403 _dim_and_symbol_use_list
: $ =>
404 seq($._value_use_list_parens
, optional($._dense_idx_list
)),
406 // assignment-list ::= assignment | assignment `,` assignment-list
407 // assignment ::= ssa-value `=` ssa-value
408 _value_assignment_list
: $ => seq('(', optional($._value_assignment
),
409 repeat(seq(',', $._value_assignment
)), ')'),
410 _value_assignment
: $ => seq($.value_use
, '=', $.value_use
),
412 _dense_idx_list
: $ => seq(
414 optional(seq(choice($.integer_literal
, $.value_use
),
415 repeat(seq(',', choice($.integer_literal
, $.value_use
))))),
418 // lower-bound ::= `max`? affine-map-attribute dim-and-symbol-use-list |
420 // upper-bound ::= `min`? affine-map-attribute dim-and-symbol-use-list |
422 // shorthand-bound ::= ssa-id | `-`? integer-literal
424 choice(seq($.attribute
, $._dim_and_symbol_use_list
), $._shorthand_bound
),
425 _shorthand_bound
: $ => choice($.value_use
, $.integer_literal
),
427 // Dialect-specific attributes
428 restrict_attr
: $ => token('restrict'),
429 writable_attr
: $ => token('writable'),
430 gather_dims_attr
: $ =>
431 seq(token('gather_dims'), '(', $._dense_idx_list
, ')'),
432 scatter_dims_attr
: $ =>
433 seq(token('scatter_dims'), '(', $._dense_idx_list
, ')'),
434 unique_attr
: $ => token('unique'),
435 nofold_attr
: $ => token('nofold'),
436 outer_dims_perm_attr
: $ =>
437 seq(token('outer_dims_perm'), '=', $._dense_idx_list
),
438 inner_dims_pos_attr
: $ =>
439 seq(token('inner_dims_pos'), '=', $._dense_idx_list
),
440 inner_tiles_attr
: $ => seq(token('inner_tiles'), '=', $._dense_idx_list
),
441 isWrite_attr
: $ => token(choice('read', 'write')),
442 localityHint_attr
: $ => seq(token('locality'), '<', $.integer_literal
, '>'),
443 isDataCache_attr
: $ => token(choice('data', 'instr')),
445 seq(token('fastmath'), '<',
446 seq($._fastmath_flag
, repeat(seq(',', $._fastmath_flag
))), '>'),
447 _fastmath_flag
: $ => token(choice('none', 'reassoc', 'nnan', 'ninf', 'nsz',
448 'arcp', 'contract', 'afn', 'fast')),
450 // Comment (standard BCPL)
451 comment
: $ => token(seq('//', /.*/
)),
454 custom_operation
: $ =>
455 choice($.builtin_dialect
, $.func_dialect
, $.llvm_dialect
, $.arith_dialect
,
456 $.math_dialect
, $.cf_dialect
, $.scf_dialect
, $.memref_dialect
,
457 $.vector_dialect
, $.tensor_dialect
, $.bufferization_dialect
,
458 $.affine_dialect
, $.linalg_dialect
)
461 module
.exports
= grammar({
463 extras
: $ => [/\s/, $.comment
],
464 conflicts
: $ => [[ $._static_dim_list
, $._static_dim_list
],
465 [ $.dictionary_attribute
, $.region
]],
466 rules
: Object
.assign(common
, builtin_dialect
, func_dialect
, llvm_dialect
,
467 arith_dialect
, math_dialect
, cf_dialect
, scf_dialect
,
468 memref_dialect
, vector_dialect
, tensor_dialect
,
469 bufferization_dialect
, affine_dialect
, linalg_dialect
)