Update "Writing a Backend" doc to use named operand matching.

This brings it in line with recommended practice after the
introduction of sub-operand naming in a538d1f13a, and the
deprecation of positional argument matching in 5351878ba1.
This commit is contained in:
James Y Knight 2022-09-26 17:56:07 -04:00
parent 1bd856fbe5
commit 5713c2959c
1 changed files with 58 additions and 24 deletions

View File

@ -762,7 +762,7 @@ target description file (``IntRegs``).
.. code-block:: text
def LDrr : F3_1 <3, 0b000000, (outs IntRegs:$dst), (ins MEMrr:$addr),
def LDrr : F3_1 <3, 0b000000, (outs IntRegs:$rd), (ins (MEMrr $rs1, $rs2):$addr),
"ld [$addr], $dst",
[(set i32:$dst, (load ADDRrr:$addr))]>;
@ -790,9 +790,9 @@ class is defined:
.. code-block:: text
def LDri : F3_2 <3, 0b000000, (outs IntRegs:$dst), (ins MEMri:$addr),
def LDri : F3_2 <3, 0b000000, (outs IntRegs:$rd), (ins (MEMri $rs1, $simm13):$addr),
"ld [$addr], $dst",
[(set i32:$dst, (load ADDRri:$addr))]>;
[(set i32:$rd, (load ADDRri:$addr))]>;
Writing these definitions for so many similar instructions can involve a lot of
cut and paste. In ``.td`` files, the ``multiclass`` directive enables the
@ -805,13 +805,13 @@ pattern ``F3_12`` is defined to create 2 instruction classes each time
multiclass F3_12 <string OpcStr, bits<6> Op3Val, SDNode OpNode> {
def rr : F3_1 <2, Op3Val,
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
!strconcat(OpcStr, " $b, $c, $dst"),
[(set i32:$dst, (OpNode i32:$b, i32:$c))]>;
(outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs1),
!strconcat(OpcStr, " $rs1, $rs2, $rd"),
[(set i32:$rd, (OpNode i32:$rs1, i32:$rs2))]>;
def ri : F3_2 <2, Op3Val,
(outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c),
!strconcat(OpcStr, " $b, $c, $dst"),
[(set i32:$dst, (OpNode i32:$b, simm13:$c))]>;
(outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$simm13),
!strconcat(OpcStr, " $rs1, $simm13, $rd"),
[(set i32:$rd, (OpNode i32:$rs1, simm13:$simm13))]>;
}
So when the ``defm`` directive is used for the ``XOR`` and ``ADD``
@ -850,17 +850,19 @@ Instruction Operand Mapping
---------------------------
The code generator backend maps instruction operands to fields in the
instruction. Operands are assigned to unbound fields in the instruction in the
order they are defined. Fields are bound when they are assigned a value. For
example, the Sparc target defines the ``XNORrr`` instruction as a ``F3_1``
format instruction having three operands.
instruction. Whenever a bit in the instruction encoding ``Inst`` is assigned
to field without a concrete value, an operand from the ``outs`` or ``ins`` list
is expected to have a matching name. This operand then populates that undefined
field. For example, the Sparc target defines the ``XNORrr`` instruction as a
``F3_1`` format instruction having three operands: the output ``$rd``, and the
inputs ``$rs1``, and ``$rs2``.
.. code-block:: text
def XNORrr : F3_1<2, 0b000111,
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
"xnor $b, $c, $dst",
[(set i32:$dst, (not (xor i32:$b, i32:$c)))]>;
(outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2),
"xnor $rs1, $rs2, $rd",
[(set i32:$rd, (not (xor i32:$rs1, i32:$rs2)))]>;
The instruction templates in ``SparcInstrFormats.td`` show the base class for
``F3_1`` is ``InstSP``.
@ -878,7 +880,8 @@ The instruction templates in ``SparcInstrFormats.td`` show the base class for
let Pattern = pattern;
}
``InstSP`` leaves the ``op`` field unbound.
``InstSP`` defines the ``op`` field, and uses it to define bits 30 and 31 of the
instruction, but does not assign a value to it.
.. code-block:: text
@ -893,9 +896,8 @@ The instruction templates in ``SparcInstrFormats.td`` show the base class for
let Inst{18-14} = rs1;
}
``F3`` binds the ``op`` field and defines the ``rd``, ``op3``, and ``rs1``
fields. ``F3`` format instructions will bind the operands ``rd``, ``op3``, and
``rs1`` fields.
``F3`` defines the ``rd``, ``op3``, and ``rs1`` fields, and uses them in the
instruction, and again does not assign values.
.. code-block:: text
@ -910,10 +912,42 @@ fields. ``F3`` format instructions will bind the operands ``rd``, ``op3``, and
let Inst{4-0} = rs2;
}
``F3_1`` binds the ``op3`` field and defines the ``rs2`` fields. ``F3_1``
format instructions will bind the operands to the ``rd``, ``rs1``, and ``rs2``
fields. This results in the ``XNORrr`` instruction binding ``$dst``, ``$b``,
and ``$c`` operands to the ``rd``, ``rs1``, and ``rs2`` fields respectively.
``F3_1`` assigns a value to ``op`` and ``op3`` fields, and defines the ``rs2``
field. Therefore, a ``F3_1`` format instruction will require a definition for
``rd``, ``rs1``, and ``rs2`` in order to fully specify the instruction encoding.
The ``XNORrr`` instruction then provides those three operands in its
OutOperandList and InOperandList, which bind to the corresponding fields, and
thus complete the instruction encoding.
For some instructions, a single operand may contain sub-operands. As shown
earlier, the instruction ``LDrr`` uses an input operand of type ``MEMrr``. This
operand type contains two register sub-operands, defined by the
``MIOperandInfo`` value to be ``(ops IntRegs, IntRegs)``.
.. code-block:: text
def LDrr : F3_1 <3, 0b000000, (outs IntRegs:$rd), (ins (MEMrr $rs1, $rs2):$addr),
"ld [$addr], $dst",
[(set i32:$dst, (load ADDRrr:$addr))]>;
As this instruction is also the ``F3_1`` format, it will expect operands named
``rd``, ``rs1``, and ``rs2`` as well. In order to allow this, a complex operand
can optionally give names to each of its sub-operands. In this example
``MEMrr``'s first sub-operand is named ``$rs1``, the second ``$rs2``, and the
operand as a whole is also given the name ``$addr``.
When a particular instruction doesn't use all the operands that the instruction
format defines, a constant value may instead be bound to one or all. For
example, the ``RDASR`` instruction only takes a single register operand, so we
assign a constant zero to ``rs2``:
.. code-block:: text
let rs2 = 0 in
def RDASR : F3_1<2, 0b101000,
(outs IntRegs:$rd), (ins ASRRegs:$rs1),
"rd $rs1, $rd", []>;
Instruction Operand Name Mapping
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^