From 5713c2959cdd56b8d529d71a078981de1333a5f4 Mon Sep 17 00:00:00 2001 From: James Y Knight Date: Mon, 26 Sep 2022 17:56:07 -0400 Subject: [PATCH] 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 a538d1f13a13, and the deprecation of positional argument matching in 5351878ba196. --- llvm/docs/WritingAnLLVMBackend.rst | 82 +++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 24 deletions(-) diff --git a/llvm/docs/WritingAnLLVMBackend.rst b/llvm/docs/WritingAnLLVMBackend.rst index a6124bc9bcb7..79f1e5b4dea0 100644 --- a/llvm/docs/WritingAnLLVMBackend.rst +++ b/llvm/docs/WritingAnLLVMBackend.rst @@ -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 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 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^