1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
|
.. _tblgen-mirpats:
========================
MIR Patterns in TableGen
========================
.. contents::
:local:
User's Guide
============
This section is intended for developers who want to use MIR patterns in their
TableGen files.
``NOTE``:
This feature is still in active development. This document may become outdated
over time. If you see something that's incorrect, please update it.
Use Cases
---------
MIR patterns are supported in the following places:
* GlobalISel ``GICombineRule``
* GlobalISel ``GICombinePatFrag``
Syntax
------
MIR patterns use the DAG datatype in TableGen.
.. code-block:: text
(inst operand0, operand1, ...)
``inst`` must be a def which inherits from ``Instruction`` (e.g. ``G_FADD``),
``Intrinsic`` or ``GICombinePatFrag``.
Operands essentially fall into one of two categories:
* immediates
* untyped, unnamed: ``0``
* untyped, named: ``0:$y``
* typed, unnamed: ``(i32 0)``
* typed, named: ``(i32 0):$y``
* machine operands
* untyped: ``$x``
* typed: ``i32:$x``
Semantics:
* A typed operand always adds an operand type check to the matcher.
* There is a trivial type inference system to propagate types.
* e.g. You only need to use ``i32:$x`` once in any pattern of a
``GICombinePatFrag`` alternative or ``GICombineRule``, then all
other patterns in that rule/alternative can simply use ``$x``
(``i32:$x`` is redundant).
* A named operand's behavior depends on whether the name has been seen before.
* For match patterns, reusing an operand name checks that the operands
are identical (see example 2 below).
* For apply patterns, reusing an operand name simply copies that operand into
the new instruction (see example 2 below).
Operands are ordered just like they would be in a MachineInstr: the defs (outs)
come first, then the uses (ins).
Patterns are generally grouped into another DAG datatype with a dummy operator
such as ``match``, ``apply`` or ``pattern``.
Finally, any DAG datatype in TableGen can be named. This also holds for
patterns. e.g. the following is valid: ``(G_FOO $root, (i32 0):$cst):$mypat``.
This may also be helpful to debug issues. Patterns are *always* named, and if
they don't have a name, an "anonymous" one is given to them. If you're trying
to debug an error related to a MIR pattern, but the error mentions an anonymous
pattern, you can try naming your patterns to see exactly where the issue is.
.. code-block:: text
:caption: Pattern Example 1
// Match
// %imp = G_IMPLICIT_DEF
// %root = G_MUL %x, %imp
(match (G_IMPLICIT_DEF $imp),
(G_MUL $root, $x, $imp))
.. code-block:: text
:caption: Pattern Example 2
// using $x twice here checks that the operand 1 and 2 of the G_AND are
// identical.
(match (G_AND $root, $x, $x))
// using $x again here copies operand 1 from G_AND into the new inst.
(apply (COPY $root, $x))
Types
-----
ValueType
~~~~~~~~~
Subclasses of ``ValueType`` are valid types, e.g. ``i32``.
GITypeOf
~~~~~~~~
``GITypeOf<"$x">`` is a ``GISpecialType`` that allows for the creation of a
register or immediate with the same type as another (register) operand.
Operand:
* An operand name as a string, prefixed by ``$``.
Semantics:
* Can only appear in an 'apply' pattern.
* The operand name used must appear in the 'match' pattern of the
same ``GICombineRule``.
.. code-block:: text
:caption: Example: Immediate
def mul_by_neg_one: GICombineRule <
(defs root:$root),
(match (G_MUL $dst, $x, -1)),
(apply (G_SUB $dst, (GITypeOf<"$x"> 0), $x))
>;
.. code-block:: text
:caption: Example: Temp Reg
def Test0 : GICombineRule<
(defs root:$dst),
(match (G_FMUL $dst, $src, -1)),
(apply (G_FSUB $dst, $src, $tmp),
(G_FNEG GITypeOf<"$dst">:$tmp, $src))>;
Builtin Operations
------------------
MIR Patterns also offer builtin operations, also called "builtin instructions".
They offer some powerful features that would otherwise require use of C++ code.
GIReplaceReg
~~~~~~~~~~~~
.. code-block:: text
:caption: Usage
(apply (GIReplaceReg $old, $new))
Operands:
* ``$old`` (out) register defined by a matched instruction
* ``$new`` (in) register
Semantics:
* Can only appear in an 'apply' pattern.
* If both old/new are operands of matched instructions,
``canReplaceReg`` is checked before applying the rule.
GIEraseRoot
~~~~~~~~~~~
.. code-block:: text
:caption: Usage
(apply (GIEraseRoot))
Semantics:
* Can only appear as the only pattern of an 'apply' pattern list.
* The root cannot have any output operands.
* The root must be a CodeGenInstruction
Instruction Flags
-----------------
MIR Patterns support both matching & writing ``MIFlags``.
.. code-block:: text
:caption: Example
def Test : GICombineRule<
(defs root:$dst),
(match (G_FOO $dst, $src, (MIFlags FmNoNans, FmNoInfs))),
(apply (G_BAR $dst, $src, (MIFlags FmReassoc)))>;
In ``apply`` patterns, we also support referring to a matched instruction to
"take" its MIFlags.
.. code-block:: text
:caption: Example
; We match NoNans/NoInfs, but $zext may have more flags.
; Copy them all into the output instruction, and set Reassoc on the output inst.
def TestCpyFlags : GICombineRule<
(defs root:$dst),
(match (G_FOO $dst, $src, (MIFlags FmNoNans, FmNoInfs)):$zext),
(apply (G_BAR $dst, $src, (MIFlags $zext, FmReassoc)))>;
The ``not`` operator can be used to check that a flag is NOT present
on a matched instruction, and to remove a flag from a generated instruction.
.. code-block:: text
:caption: Example
; We match NoInfs but we don't want NoNans/Reassoc to be set. $zext may have more flags.
; Copy them all into the output instruction but remove NoInfs on the output inst.
def TestNot : GICombineRule<
(defs root:$dst),
(match (G_FOO $dst, $src, (MIFlags FmNoInfs, (not FmNoNans, FmReassoc))):$zext),
(apply (G_BAR $dst, $src, (MIFlags $zext, (not FmNoInfs))))>;
Limitations
-----------
This a non-exhaustive list of known issues with MIR patterns at this time.
* Using ``GICombinePatFrag`` within another ``GICombinePatFrag`` is not
supported.
* ``GICombinePatFrag`` can only have a single root.
* Instructions with multiple defs cannot be the root of a ``GICombinePatFrag``.
* Using ``GICombinePatFrag`` in the ``apply`` pattern of a ``GICombineRule``
is not supported.
* We cannot rewrite a matched instruction other than the root.
* Matching/creating a (CImm) immediate >64 bits is not supported
(see comment in ``GIM_CheckConstantInt``)
* There is currently no way to constrain two register/immediate types to
match. e.g. if a pattern needs to work on both i32 and i64, you either
need to leave it untyped and check the type in C++, or duplicate the
pattern.
GICombineRule
-------------
MIR patterns can appear in the ``match`` or ``apply`` patterns of a
``GICombineRule``.
The ``root`` of the rule can either be a def of an instruction, or a
named pattern. The latter is helpful when the instruction you want
to match has no defs. The former is generally preferred because
it's less verbose.
.. code-block:: text
:caption: Combine Rule root is a def
// Fold x op 1 -> x
def right_identity_one: GICombineRule<
(defs root:$dst),
(match (G_MUL $dst, $x, 1)),
// Note: Patterns always need to create something, we can't just replace $dst with $x, so we need a COPY.
(apply (COPY $dst, $x))
>;
.. code-block:: text
:caption: Combine Rule root is a named pattern
def Foo : GICombineRule<
(defs root:$root),
(match (G_ZEXT $tmp, (i32 0)),
(G_STORE $tmp, $ptr):$root),
(apply (G_STORE (i32 0), $ptr):$root)>;
Combine Rules also allow mixing C++ code with MIR patterns, so that you
may perform additional checks when matching, or run a C++ action after
matching.
Note that C++ code in ``apply`` pattern is mutually exclusive with
other patterns. However, you can freely mix C++ code with other
types of patterns in ``match`` patterns.
C++ code in ``match`` patterns is always run last, after all other
patterns matched.
.. code-block:: text
:caption: Apply Pattern Examples with C++ code
// Valid
def Foo : GICombineRule<
(defs root:$root),
(match (G_ZEXT $tmp, (i32 0)),
(G_STORE $tmp, $ptr):$root,
"return myFinalCheck()"),
(apply "runMyAction(${root})")>;
// error: 'apply' patterns cannot mix C++ code with other types of patterns
def Bar : GICombineRule<
(defs root:$dst),
(match (G_ZEXT $dst, $src):$mi),
(apply (G_MUL $dst, $src, $src),
"runMyAction(${root})")>;
The following expansions are available for MIR patterns:
* operand names (``MachineOperand &``)
* pattern names (``MachineInstr *`` for ``match``,
``MachineInstrBuilder &`` for apply)
.. code-block:: text
:caption: Example C++ Expansions
def Foo : GICombineRule<
(defs root:$root),
(match (G_ZEXT $root, $src):$mi),
(apply "foobar(${root}.getReg(), ${src}.getReg(), ${mi}->hasImplicitDef())")>;
Common Pattern #1: Replace a Register with Another
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'apply' pattern must always redefine all operands defined by the match root.
Sometimes, we do not need to create instructions, simply replace a def with
another matched register. The ``GIReplaceReg`` builtin can do just that.
.. code-block:: text
def Foo : GICombineRule<
(defs root:$dst),
(match (G_FNEG $tmp, $src), (G_FNEG $dst, $tmp)),
(apply (GIReplaceReg $dst, $src))>;
This also works if the replacement register is a temporary register from the
``apply`` pattern.
.. code-block:: text
def ReplaceTemp : GICombineRule<
(defs root:$a),
(match (G_BUILD_VECTOR $tmp, $x, $y),
(G_UNMERGE_VALUES $a, $b, $tmp)),
(apply (G_UNMERGE_VALUES $a, i32:$new, $y),
(GIReplaceReg $b, $new))>
Common Pattern #2: Erasing a Def-less Root
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If we simply want to erase a def-less match root, we can use the
``GIEraseRoot`` builtin.
.. code-block:: text
def Foo : GICombineRule<
(defs root:$mi),
(match (G_STORE $a, $b):$mi),
(apply (GIEraseRoot))>;
Common Pattern #3: Emitting a Constant Value
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When an immediate operand appears in an 'apply' pattern, the behavior
depends on whether it's typed or not.
* If the immediate is typed, ``MachineIRBuilder::buildConstant`` is used
to create a ``G_CONSTANT``. A ``G_BUILD_VECTOR`` will be used for vectors.
* If the immediate is untyped, a simple immediate is added
(``MachineInstrBuilder::addImm``).
There is of course a special case for ``G_CONSTANT``. Immediates for
``G_CONSTANT`` must always be typed, and a CImm is added
(``MachineInstrBuilder::addCImm``).
.. code-block:: text
:caption: Constant Emission Examples:
// Example output:
// %0 = G_CONSTANT i32 0
// %dst = COPY %0
def Foo : GICombineRule<
(defs root:$dst),
(match (G_FOO $dst, $src)),
(apply (COPY $dst, (i32 0)))>;
// Example output:
// %dst = COPY 0
// Note that this would be ill-formed because COPY
// expects a register operand!
def Bar : GICombineRule<
(defs root:$dst),
(match (G_FOO $dst, $src)),
(apply (COPY $dst, (i32 0)))>;
// Example output:
// %dst = G_CONSTANT i32 0
def Bux : GICombineRule<
(defs root:$dst),
(match (G_FOO $dst, $src)),
(apply (G_CONSTANT $dst, (i32 0)))>;
GICombinePatFrag
----------------
``GICombinePatFrag`` is an equivalent of ``PatFrags`` for MIR patterns.
They have two main usecases:
* Reduce repetition by creating a ``GICombinePatFrag`` for common
patterns (see example 1).
* Implicitly duplicate a CombineRule for multiple variants of a
pattern (see example 2).
A ``GICombinePatFrag`` is composed of three elements:
* zero or more ``in`` (def) parameter
* zero or more ``out`` parameter
* A list of MIR patterns that can match.
* When a ``GICombinePatFrag`` is used within a pattern, the pattern is
cloned once for each alternative that can match.
Parameters can have the following types:
* ``gi_mo``, which is the implicit default (no type = ``gi_mo``).
* Refers to any operand of an instruction (register, BB ref, imm, etc.).
* Can be used in both ``in`` and ``out`` parameters.
* Users of the PatFrag can only use an operand name for this
parameter (e.g. ``(my_pat_frag $foo)``).
* ``root``
* This is identical to ``gi_mo``.
* Can only be used in ``out`` parameters to declare the root of the
pattern.
* Non-empty ``out`` parameter lists must always have exactly one ``root``.
* ``gi_imm``
* Refers to an (potentially typed) immediate.
* Can only be used in ``in`` parameters.
* Users of the PatFrag can only use an immediate for this parameter
(e.g. ``(my_pat_frag 0)`` or ``(my_pat_frag (i32 0))``)
``out`` operands can only be empty if the ``GICombinePatFrag`` only contains
C++ code. If the fragment contains instruction patterns, it has to have at
least one ``out`` operand of type ``root``.
``in`` operands are less restricted, but there is one important concept to
remember: you can pass "unbound" operand names, but only if the
``GICombinePatFrag`` binds it. See example 3 below.
``GICombinePatFrag`` are used just like any other instructions.
Note that the ``out`` operands are defs, so they come first in the list
of operands.
.. code-block:: text
:caption: Example 1: Reduce Repetition
def zext_cst : GICombinePatFrag<(outs root:$dst, $cst), (ins gi_imm:$val),
[(pattern (G_CONSTANT $cst, $val),
(G_ZEXT $dst, $cst))]
>;
def foo_to_impdef : GICombineRule<
(defs root:$dst),
(match (zext_cst $y, $cst, (i32 0))
(G_FOO $dst, $y)),
(apply (G_IMPLICIT_DEF $dst))>;
def store_ext_zero : GICombineRule<
(defs root:$root),
(match (zext_cst $y, $cst, (i32 0))
(G_STORE $y, $ptr):$root),
(apply (G_STORE $cst, $ptr):$root)>;
.. code-block:: text
:caption: Example 2: Generate Multiple Rules at Once
// Fold (freeze (freeze x)) -> (freeze x).
// Fold (fabs (fabs x)) -> (fabs x).
// Fold (fcanonicalize (fcanonicalize x)) -> (fcanonicalize x).
def idempotent_prop_frags : GICombinePatFrag<(outs root:$dst, $src), (ins),
[
(pattern (G_FREEZE $dst, $src), (G_FREEZE $src, $x)),
(pattern (G_FABS $dst, $src), (G_FABS $src, $x)),
(pattern (G_FCANONICALIZE $dst, $src), (G_FCANONICALIZE $src, $x))
]
>;
def idempotent_prop : GICombineRule<
(defs root:$dst),
(match (idempotent_prop_frags $dst, $src)),
(apply (COPY $dst, $src))>;
.. code-block:: text
:caption: Example 3: Unbound Operand Names
// This fragment binds $x to an operand in all of its
// alternative patterns.
def always_binds : GICombinePatFrag<
(outs root:$dst), (ins $x),
[
(pattern (G_FREEZE $dst, $x)),
(pattern (G_FABS $dst, $x)),
]
>;
// This fragment does not bind $x to an operand in any
// of its alternative patterns.
def does_not_bind : GICombinePatFrag<
(outs root:$dst), (ins $x),
[
(pattern (G_FREEZE $dst, $x)), // binds $x
(pattern (G_FOO $dst (i32 0))), // does not bind $x
(pattern "return myCheck(${x}.getReg())"), // does not bind $x
]
>;
// Here we pass $x, which is unbound, to always_binds.
// This works because if $x is unbound, always_binds will bind it for us.
def test0 : GICombineRule<
(defs root:$dst),
(match (always_binds $dst, $x)),
(apply (COPY $dst, $x))>;
// Here we pass $x, which is unbound, to does_not_bind.
// This cannot work because $x may not have been initialized in 'apply'.
// error: operand 'x' (for parameter 'src' of 'does_not_bind') cannot be unbound
def test1 : GICombineRule<
(defs root:$dst),
(match (does_not_bind $dst, $x)),
(apply (COPY $dst, $x))>;
// Here we pass $x, which is bound, to does_not_bind.
// This is fine because $x will always be bound when emitting does_not_bind
def test2 : GICombineRule<
(defs root:$dst),
(match (does_not_bind $tmp, $x)
(G_MUL $dst, $x, $tmp)),
(apply (COPY $dst, $x))>;
Gallery
=======
We should use precise patterns that state our intentions. Please avoid
using wip_match_opcode in patterns.
.. code-block:: text
:caption: Example fold zext(trunc:nuw)
// Imprecise: matches any G_ZEXT
def zext : GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_ZEXT):$root,
[{ return Helper.matchZextOfTrunc(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
// Imprecise: matches G_ZEXT of G_TRUNC
def zext_of_trunc : GICombineRule<
(defs root:$root),
(match (G_TRUNC $src, $x),
(G_ZEXT $root, $src),
[{ return Helper.matchZextOfTrunc(${root}, ${matchinfo}); }]),
(apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>;
// Precise: matches G_ZEXT of G_TRUNC with nuw flag
def zext_of_trunc_nuw : GICombineRule<
(defs root:$root),
(match (G_TRUNC $src, $x, (MIFlags NoUWrap)),
(G_ZEXT $root, $src),
[{ return Helper.matchZextOfTrunc(${root}, ${matchinfo}); }]),
(apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>;
|