cb424d7448
verify-patch-sanity.py validates every active recipe .patch has internally- consistent hunk line counts — catching the 'malformed patch at line N' failure at commit/CI/preflight time instead of hours into a cook. This cycle hit that class three times (qtwaylandscanner, sddm, xwayland), each only discovered when cookbook tried to apply the patch. Running it across the repo found 29 latent malformed patches (validated against GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22'). They were harmless only because they sit in vendored recipes (baked, not re- applied) — but would fail on any version-bump re-derivation. --fix recounts the hunk headers (body untouched) and repaired all 29. Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test (test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats (empty placeholders, bare-@@ git hunks).
686 lines
21 KiB
ReStructuredText
686 lines
21 KiB
ReStructuredText
|
|
.. _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``, ``combine`` 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.
|
|
|
|
Type Parameters:
|
|
|
|
* 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))>;
|
|
|
|
GIVariadic
|
|
~~~~~~~~~~
|
|
|
|
``GIVariadic<>`` is a ``GISpecialType`` that allows for matching 1 or
|
|
more operands remaining on an instruction.
|
|
|
|
Type Parameters:
|
|
|
|
* The minimum number of additional operands to match. Must be greater than zero.
|
|
|
|
* Default is 1.
|
|
|
|
* The maximum number of additional operands to match. Must be strictly greater
|
|
than the minimum.
|
|
|
|
* 0 can be used to indicate there is no upper limit.
|
|
* Default is 0.
|
|
|
|
Semantics:
|
|
|
|
* ``GIVariadic<>`` operands can only appear on variadic instructions.
|
|
* ``GIVariadic<>`` operands cannot be defs.
|
|
* ``GIVariadic<>`` operands can only appear as the last operand in a 'match' pattern.
|
|
* Each instance within a 'match' pattern must be uniquely named.
|
|
* Re-using a ``GIVariadic<>`` operand in an 'apply' pattern will result in all
|
|
the matched operands being copied from the original instruction.
|
|
* The min/max operands will result in the matcher checking that the number of operands
|
|
falls within that range.
|
|
* ``GIVariadic<>`` operands can be used in C++ code within a rule, which will
|
|
result in the operand name being expanded to a value of type ``ArrayRef<MachineOperand>``.
|
|
|
|
.. code-block:: text
|
|
|
|
// bool checkBuildVectorToUnmerge(ArrayRef<MachineOperand>);
|
|
|
|
def build_vector_to_unmerge: GICombineRule <
|
|
(defs root:$root),
|
|
(match (G_BUILD_VECTOR $root, GIVariadic<>:$args),
|
|
[{ return checkBuildVectorToUnmerge(${args}); }]),
|
|
(apply (G_UNMERGE_VALUES $root, $args))
|
|
>;
|
|
|
|
.. code-block:: text
|
|
|
|
// Will additionally check the number of operands is >= 3 and <= 5.
|
|
// ($root is one operand, then 2 to 4 variadic operands).
|
|
def build_vector_to_unmerge: GICombineRule <
|
|
(defs root:$root),
|
|
(match (G_BUILD_VECTOR $root, GIVariadic<2, 4>:$two_to_four),
|
|
[{ return checkBuildVectorToUnmerge(${two_to_four}); }]),
|
|
(apply (G_UNMERGE_VALUES $root, $two_to_four))
|
|
>;
|
|
|
|
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.
|
|
* ``GISpecialType`` operands are not allowed within a ``GICombinePatFrag``.
|
|
* ``GIVariadic<>`` matched operands must each have a unique name.
|
|
|
|
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())")>;
|
|
|
|
``combine`` Operator
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
``GICombineRule`` also supports a single ``combine`` pattern, which is a shorter way to
|
|
declare patterns that just match one or more instructions, then defer all remaining matching
|
|
and rewriting logic to C++ code.
|
|
|
|
.. code-block:: text
|
|
:caption: Example usage of the combine operator.
|
|
|
|
// match + apply
|
|
def FooLong : GICombineRule<
|
|
(defs root:$root),
|
|
(match (G_ZEXT $root, $src):$mi, "return matchFoo(${mi});"),
|
|
(apply "applyFoo(${mi});")>;
|
|
|
|
// combine
|
|
def FooShort : GICombineRule<
|
|
(defs root:$root),
|
|
(combine (G_ZEXT $root, $src):$mi, "return combineFoo(${mi});")>;
|
|
|
|
This has a couple of advantages:
|
|
|
|
* We only need one C++ function, not two.
|
|
* We no longer need to use ``GIDefMatchData`` to pass information between the match/apply functions.
|
|
|
|
As described above, this is syntactic sugar for the match+apply form. In a ``combine`` pattern:
|
|
|
|
* Everything except C++ code is considered the ``match`` part.
|
|
* The C++ code is the ``apply`` part. C++ code is emitted in order of appearance.
|
|
|
|
.. note::
|
|
|
|
The C++ code **must** return true if it changed any instruction. Returning false when changing
|
|
instructions is undefined behavior.
|
|
|
|
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. It can lead to imprecise 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}); }])>;
|
|
|
|
|
|
// Precise: lists all combine combinations
|
|
class ext_of_ext_opcodes<Instruction ext1Opcode, Instruction ext2Opcode> : GICombineRule <
|
|
(defs root:$root, build_fn_matchinfo:$matchinfo),
|
|
(match (ext2Opcode $second, $src):$Second,
|
|
(ext1Opcode $root, $second):$First,
|
|
[{ return Helper.matchExtOfExt(*${First}, *${Second}, ${matchinfo}); }]),
|
|
(apply [{ Helper.applyBuildFn(*${First}, ${matchinfo}); }])>;
|
|
|
|
def zext_of_zext : ext_of_ext_opcodes<G_ZEXT, G_ZEXT>;
|
|
def zext_of_anyext : ext_of_ext_opcodes<G_ZEXT, G_ANYEXT>;
|
|
def sext_of_sext : ext_of_ext_opcodes<G_SEXT, G_SEXT>;
|
|
def sext_of_anyext : ext_of_ext_opcodes<G_SEXT, G_ANYEXT>;
|
|
def anyext_of_anyext : ext_of_ext_opcodes<G_ANYEXT, G_ANYEXT>;
|
|
def anyext_of_zext : ext_of_ext_opcodes<G_ANYEXT, G_ZEXT>;
|
|
def anyext_of_sext : ext_of_ext_opcodes<G_ANYEXT, G_SEXT>;
|