brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.5 KiB · 6f64ddb Raw
355 lines · plain
1=========================2 RISC-V Vector Extension3=========================4 5.. contents::6   :local:7 8The RISC-V target supports the 1.0 version of the `RISC-V Vector Extension (RVV) <https://github.com/riscv/riscv-v-spec/blob/v1.0/v-spec.adoc>`_.9This guide gives an overview of how it's modelled in LLVM IR and how the backend generates code for it.10 11Mapping to LLVM IR types12========================13 14RVV adds 32 VLEN sized registers, where VLEN is an unknown constant to the compiler. To be able to represent VLEN sized values, the RISC-V backend takes the same approach as AArch64's SVE and uses `scalable vector types <https://llvm.org/docs/LangRef.html#t-vector>`_.15 16Scalable vector types are of the form ``<vscale x n x ty>``, which indicates a vector with a multiple of ``n`` elements of type ``ty``.17On RISC-V ``n`` and ``ty`` control LMUL and SEW respectively.18 19LLVM only supports ELEN=32 or ELEN=64, so ``vscale`` is defined as VLEN/64 (see ``RISCV::RVVBitsPerBlock``).20Note this means that VLEN must be at least 64, so VLEN=32 isn't currently supported.21 22+-------------------+---------------+------------------+------------------+-------------------+-------------------+-------------------+-------------------+23|                   | LMUL=⅛        | LMUL=¼           | LMUL=½           | LMUL=1            | LMUL=2            | LMUL=4            | LMUL=8            |24+===================+===============+==================+==================+===================+===================+===================+===================+25| i64 (ELEN=64)     | N/A           | N/A              | N/A              | <v x 1 x i64>     | <v x 2 x i64>     | <v x 4 x i64>     | <v x 8 x i64>     |26+-------------------+---------------+------------------+------------------+-------------------+-------------------+-------------------+-------------------+27| i32               | N/A           | N/A              | <v x 1 x i32>    | <v x 2 x i32>     | <v x 4 x i32>     | <v x 8 x i32>     | <v x 16 x i32>    |28+-------------------+---------------+------------------+------------------+-------------------+-------------------+-------------------+-------------------+29| i16               | N/A           | <v x 1 x i16>    | <v x 2 x i16>    | <v x 4 x i16>     | <v x 8 x i16>     | <v x 16 x i16>    | <v x 32 x i16>    |30+-------------------+---------------+------------------+------------------+-------------------+-------------------+-------------------+-------------------+31| i8                | <v x 1 x i8>  | <v x 2 x i8>     | <v x 4 x i8>     | <v x 8 x i8>      | <v x 16 x i8>     | <v x 32 x i8>     | <v x 64 x i8>     |32+-------------------+---------------+------------------+------------------+-------------------+-------------------+-------------------+-------------------+33| double (ELEN=64)  | N/A           | N/A              | N/A              | <v x 1 x double>  | <v x 2 x double>  | <v x 4 x double>  | <v x 8 x double>  |34+-------------------+---------------+------------------+------------------+-------------------+-------------------+-------------------+-------------------+35| float             | N/A           | N/A              | <v x 1 x float>  | <v x 2 x float>   | <v x 4 x float>   | <v x 8 x float>   | <v x 16 x float>  |36+-------------------+---------------+------------------+------------------+-------------------+-------------------+-------------------+-------------------+37| half              | N/A           | <v x 1 x half>   | <v x 2 x half>   | <v x 4 x half>    | <v x 8 x half>    | <v x 16 x half>   | <v x 32 x half>   |38+-------------------+---------------+------------------+------------------+-------------------+-------------------+-------------------+-------------------+39| bfloat            | N/A           | <v x 1 x bfloat> | <v x 2 x bfloat> | <v x 4 x bfloat>  | <v x 8 x bfloat>  | <v x 16 x bfloat> | <v x 32 x bfloat> |40+-------------------+---------------+------------------+------------------+-------------------+-------------------+-------------------+-------------------+41 42(Read ``<v x k x ty>`` as ``<vscale x k x ty>``)43 44 45Mask vector types46-----------------47 48Mask vectors are physically represented using a layout of densely packed bits in a vector register.49They are mapped to the following LLVM IR types:50 51- ``<vscale x 1 x i1>``52- ``<vscale x 2 x i1>``53- ``<vscale x 4 x i1>``54- ``<vscale x 8 x i1>``55- ``<vscale x 16 x i1>``56- ``<vscale x 32 x i1>``57- ``<vscale x 64 x i1>``58 59Two types with the same SEW/LMUL ratio will have the same related mask type.60For instance, two different comparisons one under SEW=64, LMUL=2 and the other under SEW=32, LMUL=1 will both generate a mask ``<vscale x 2 x i1>``.61 62Representation in LLVM IR63=========================64 65Vector instructions can be represented in three main ways in LLVM IR:66 671. Regular instructions on both scalable and fixed-length vector types68 69   .. code-block:: llvm70 71       %c = add <vscale x 4 x i32> %a, %b72       %f = add <4 x i32> %d, %e73 742. RISC-V vector intrinsics, which mirror the `C intrinsics specification <https://github.com/riscv-non-isa/rvv-intrinsic-doc>`_75 76   These come in unmasked variants:77 78   .. code-block:: llvm79 80       %c = call @llvm.riscv.vadd.nxv4i32.nxv4i32(81              <vscale x 4 x i32> %passthru,82	      <vscale x 4 x i32> %a,83	      <vscale x 4 x i32> %b,84	      i64 %avl85	    )86 87   As well as masked variants:88 89   .. code-block:: llvm90 91       %c = call @llvm.riscv.vadd.mask.nxv4i32.nxv4i32(92              <vscale x 4 x i32> %passthru,93	      <vscale x 4 x i32> %a,94	      <vscale x 4 x i32> %b,95	      <vscale x 4 x i1> %mask,96	      i64 %avl,97	      i64 0 ; policy (must be an immediate)98	    )99 100   Both allow setting the AVL as well as controlling the inactive/tail elements via the passthru operand, but the masked variant also provides operands for the mask and ``vta``/``vma`` policy bits.101 102   The only valid types are scalable vector types.103 1043. :ref:`Vector predication (VP) intrinsics <int_vp>`105 106   .. code-block:: llvm107 108       %c = call @llvm.vp.add.nxv4i32(109	      <vscale x 4 x i32> %a,110	      <vscale x 4 x i32> %b,111	      <vscale x 4 x i1> %m112	      i32 %evl113	    )114 115   Unlike RISC-V intrinsics, VP intrinsics are target agnostic so they can be emitted from other optimisation passes in the middle-end (like the loop vectorizer). They also support fixed-length vector types.116 117   VP intrinsics also don't have passthru operands, but tail/mask undisturbed behaviour can be emulated by using the output in a ``@llvm.vp.merge``.118   It will get lowered as a ``vmerge``, but will be merged back into the underlying instruction's mask via ``RISCVDAGToDAGISel::performCombineVMergeAndVOps``.119 120 121The different properties of the above representations are summarized below:122 123+----------------------+--------------+-----------------+----------+------------------+----------------------+-----------------+124|                      | AVL          | Masking         | Passthru | Scalable vectors | Fixed-length vectors | Target agnostic |125+======================+==============+=================+==========+==================+======================+=================+126| LLVM IR instructions | Always VLMAX | No              | None     | Yes              | Yes                  | Yes             |127+----------------------+--------------+-----------------+----------+------------------+----------------------+-----------------+128| RVV intrinsics       | Yes          | Yes             | Yes      | Yes              | No                   | No              |129+----------------------+--------------+-----------------+----------+------------------+----------------------+-----------------+130| VP intrinsics        | Yes (EVL)    | Yes             | No       | Yes              | Yes                  | Yes             |131+----------------------+--------------+-----------------+----------+------------------+----------------------+-----------------+132 133SelectionDAG lowering134=====================135 136For most regular **scalable** vector LLVM IR instructions, their corresponding SelectionDAG nodes are legal on RISC-V and don't require any custom lowering.137 138.. code-block::139 140   t5: nxv4i32 = add t2, t4141 142RISC-V vector intrinsics also don't require any custom lowering.143 144.. code-block::145 146   t12: nxv4i32 = llvm.riscv.vadd TargetConstant:i64<10056>, undef:nxv4i32, t2, t4, t6147 148Fixed-length vectors149--------------------150 151Because there are no fixed-length vector patterns, fixed-length vectors need to be custom lowered and performed in a scalable "container" type:152 1531. The fixed-length vector operands are inserted into scalable containers with ``insert_subvector`` nodes. The container type is chosen such that its minimum size will fit the fixed-length vector (see ``getContainerForFixedLengthVector``).1542. The operation is then performed on the container type via a **VL (vector length) node**. These are custom nodes defined in ``RISCVInstrInfoVVLPatterns.td`` that mirror target agnostic SelectionDAG nodes, as well as some RVV instructions. They contain an AVL operand, which is set to the number of elements in the fixed-length vector.155   Some nodes also have a passthru or mask operand, which will usually be set to ``undef`` and all ones when lowering fixed-length vectors.1563. The result is put back into a fixed-length vector via ``extract_subvector``.157 158.. code-block::159 160       t2: nxv2i32,ch = CopyFromReg t0, Register:nxv2i32 %0161       t6: nxv2i32,ch = CopyFromReg t0, Register:nxv2i32 %1162     t4: v4i32 = extract_subvector t2, Constant:i64<0>163     t7: v4i32 = extract_subvector t6, Constant:i64<0>164   t8: v4i32 = add t4, t7165 166   // is custom lowered to:167 168       t2: nxv2i32,ch = CopyFromReg t0, Register:nxv2i32 %0169       t6: nxv2i32,ch = CopyFromReg t0, Register:nxv2i32 %1170       t15: nxv2i1 = RISCVISD::VMSET_VL Constant:i64<4>171     t16: nxv2i32 = RISCVISD::ADD_VL t2, t6, undef:nxv2i32, t15, Constant:i64<4>172   t17: v4i32 = extract_subvector t16, Constant:i64<0>173 174VL nodes often have a passthru or mask operand, which are usually set to ``undef`` and all ones for fixed-length vectors.175 176The ``insert_subvector`` and ``extract_subvector`` nodes responsible for wrapping and unwrapping will get combined away, and eventually we will lower all fixed-length vector types to scalable. Note that fixed-length vectors at the interface of a function are passed in a scalable vector container.177 178.. note::179 180   The only ``insert_subvector`` and ``extract_subvector`` nodes that make it through lowering are those that can be performed as an exact subregister insert or extract. This means that any fixed-length vector ``insert_subvector`` and ``extract_subvector`` nodes that aren't legalized must lie on a register group boundary, so the exact VLEN must be known at compile time (i.e., compiled with ``-mrvv-vector-bits=zvl`` or ``-mllvm -riscv-v-vector-bits-max=VLEN``, or have an exact ``vscale_range`` attribute).181 182Vector predication intrinsics183-----------------------------184 185VP intrinsics also get custom lowered via VL nodes.186 187.. code-block::188 189   t12: nxv2i32 = vp_add t2, t4, t6, Constant:i64<8>190 191   // is custom lowered to:192 193   t18: nxv2i32 = RISCVISD::ADD_VL t2, t4, undef:nxv2i32, t6, Constant:i64<8>194 195The VP EVL and mask are used for the VL node's AVL and mask respectively, whilst the passthru is set to ``undef``.196 197Instruction selection198=====================199 200``vl`` and ``vtype`` need to be configured correctly, so we can't just directly select the underlying vector ``MachineInstr``. Instead pseudo instructions are selected, which carry the extra information needed to emit the necessary ``vsetvli``\s later.201 202.. code-block::203 204   %c:vrm2 = PseudoVADD_VV_M2 %passthru:vrm2(tied-def 0), %a:vrm2, %b:vrm2, %vl:gpr, 5 /*sew*/, 3 /*policy*/205 206Each vector instruction has multiple pseudo instructions defined in ``RISCVInstrInfoVPseudos.td``.207There is a variant of each pseudo for each possible LMUL, as well as a masked variant. So a typical instruction like ``vadd.vv`` would have the following pseudos:208 209.. code-block::210 211   %rd:vr = PseudoVADD_VV_MF8 %passthru:vr(tied-def 0), %rs2:vr, %rs1:vr, %avl:gpr, sew:imm, policy:imm212   %rd:vr = PseudoVADD_VV_MF4 %passthru:vr(tied-def 0), %rs2:vr, %rs1:vr, %avl:gpr, sew:imm, policy:imm213   %rd:vr = PseudoVADD_VV_MF2 %passthru:vr(tied-def 0), %rs2:vr, %rs1:vr, %avl:gpr, sew:imm, policy:imm214   %rd:vr = PseudoVADD_VV_M1 %passthru:vr(tied-def 0), %rs2:vr, %rs1:vr, %avl:gpr, sew:imm, policy:imm215   %rd:vrm2 = PseudoVADD_VV_M2 %passthru:vrm2(tied-def 0), %rs2:vrm2, %rs1:vrm2, %avl:gpr, sew:imm, policy:imm216   %rd:vrm4 = PseudoVADD_VV_M4 %passthru:vrm4(tied-def 0), %rs2:vrm4, %rs1:vrm4, %avl:gpr, sew:imm, policy:imm217   %rd:vrm8 = PseudoVADD_VV_M8 %passthru:vrm8(tied-def 0), %rs2:vrm8, %rs1:vrm8, %avl:gpr, sew:imm, policy:imm218   %rd:vr = PseudoVADD_VV_MF8_MASK %passthru:vr(tied-def 0), %rs2:vr, %rs1:vr, mask:$v0, %avl:gpr, sew:imm, policy:imm219   %rd:vr = PseudoVADD_VV_MF4_MASK %passthru:vr(tied-def 0), %rs2:vr, %rs1:vr, mask:$v0, %avl:gpr, sew:imm, policy:imm220   %rd:vr = PseudoVADD_VV_MF2_MASK %passthru:vr(tied-def 0), %rs2:vr, %rs1:vr, mask:$v0, %avl:gpr, sew:imm, policy:imm221   %rd:vr = PseudoVADD_VV_M1_MASK %passthru:vr(tied-def 0), %rs2:vr, %rs1:vr, mask:$v0, %avl:gpr, sew:imm, policy:imm222   %rd:vrm2 = PseudoVADD_VV_M2_MASK %passthru:vrm2(tied-def 0), %rs2:vrm2, %%rs1:vrm2, mask:$v0, %avl:gpr, sew:imm, policy:imm223   %rd:vrm4 = PseudoVADD_VV_M4_MASK %passthru:vrm4(tied-def 0), %rs2:vrm4, %rs1:vrm4, mask:$v0, %avl:gpr, sew:imm, policy:imm224   %rd:vrm8 = PseudoVADD_VV_M8_MASK %passthru:vrm8(tied-def 0), %rs2:vrm8, %rs1:vrm8, mask:$v0, %avl:gpr, sew:imm, policy:imm225 226.. note::227 228   Whilst the SEW can be encoded in an operand, we need to use separate pseudos for each LMUL since different register groups will require different register classes: see :ref:`rvv_register_allocation`.229 230 231Pseudos have operands for the AVL and SEW (encoded as a power of 2), as well as potentially the mask, policy or rounding mode if applicable.232The passthru operand is tied to the destination register which will determine the inactive/tail elements.233 234For scalable vectors that should use VLMAX, the AVL is set to a sentinel value of ``-1``.235 236There are patterns for target agnostic SelectionDAG nodes in ``RISCVInstrInfoVSDPatterns.td``, VL nodes in ``RISCVInstrInfoVVLPatterns.td`` and RVV intrinsics in ``RISCVInstrInfoVPseudos.td``.237 238Instructions that operate only on masks like VMAND or VMSBF uses pseudo instructions suffixed with B1, B2, B4, B8, B16, B32, or B64 where the number is SEW/LMUL representing239the ratio between SEW and LMUL needed in vtype. These instructions always operate as if EEW=1 and always use a value of 0 as their SEW operand.240 241Mask patterns242-------------243 244The patterns in ``RISCVInstrInfoVVLPatterns.td`` only match masked pseudos to reduce the size of the match table, even if the node's mask is all ones and could be an unmasked pseudo.245``RISCVVectorPeephole::convertToUnmasked`` will detect if the mask is all ones and convert it into its unmasked form.246 247.. code-block::248 249   %mask:vmv0 = PseudoVMSET_M_B16 -1, 32250   %rd:vrm2 = PseudoVADD_VV_M2_MASK %passthru:vrm2(tied-def 0), %rs2:vrm2, %rs1:vrm2, %mask:vmv0, %avl:gpr, sew:imm, policy:imm251 252   // gets optimized to:253 254   %rd:vrm2 = PseudoVADD_VV_M2 %passthru:vrm2(tied-def 0), %rs2:vrm2, %rs1:vrm2, %avl:gpr, sew:imm, policy:imm255 256.. note::257 258   Any ``vmset.m`` can be treated as an all ones mask since the tail elements past AVL are ``undef`` and can be replaced with ones.259 260VMV0 elimination261=================262 263Because masked instructions must have the mask register in ``v0``, a specific register class ``vmv0`` is used that contains only one register, ``v0``.264 265However register coalescing may end up coalescing copies into ``vmv0``, resulting in instructions with multiple uses of ``vmv0`` that the register allocator can't allocate:266 267.. code-block::268 269   %x:vrnov0 = PseudoVADD_VV_M1_MASK %0:vrnov0, %1:vr, %2:vmv0, %3:vmv0, ...270 271To avoid this, ``RISCVVMV0Elimination`` replaces any uses of ``vmv0`` with physical copies to ``v0`` before register coalescing and allocation:272 273.. code-block::274   275  %x:vrnov0 = PseudoVADD_VV_M1_MASK %0:vrnov0, %1:vr, %2:vr, %3:vmv0, ...276 277  // vmv0 gets eliminated to:278 279  $v0 = COPY %3:vr280  %x:vrnov0 = PseudoVADD_VV_M1_MASK %0:vrnov0, %1:vr, %2:vr, $v0, ...281 282.. _rvv_register_allocation:283 284Register allocation285===================286 287Register allocation is split between vector and scalar registers, with vector allocation running first:288 289.. code-block::290 291  $v8m2 = PseudoVADD_VV_M2 $v8m2(tied-def 0), $v8m2, $v10m2, %vl:gpr, 5, 3292 293.. note::294 295   Register allocation is split so that :ref:`RISCVInsertVSETVLI` can run after vector register allocation, but before scalar register allocation. It needs to be run before scalar register allocation as it may need to create a new virtual register to set the AVL to VLMAX.296 297   Performing ``RISCVInsertVSETVLI`` after vector register allocation imposes fewer constraints on the machine scheduler since it cannot schedule instructions past ``vsetvli``\s, and it allows us to emit further vector pseudos during spilling or constant rematerialization.298 299There are four register classes for vectors:300 301- ``VR`` for vector registers (``v0``, ``v1,``, ..., ``v31``). Used when :math:`\text{LMUL} \leq 1` and mask registers.302- ``VRM2`` for vector groups of length 2 i.e., :math:`\text{LMUL}=2` (``v0m2``, ``v2m2``, ..., ``v30m2``)303- ``VRM4`` for vector groups of length 4 i.e., :math:`\text{LMUL}=4` (``v0m4``, ``v4m4``, ..., ``v28m4``)304- ``VRM8`` for vector groups of length 8 i.e., :math:`\text{LMUL}=8` (``v0m8``, ``v8m8``, ..., ``v24m8``)305 306:math:`\text{LMUL} \lt 1` types and mask types do not benefit from having a dedicated class, so ``VR`` is used in their case.307 308Some instructions have a constraint that a register operand cannot be ``V0`` or overlap with ``V0``, so for these cases we also have ``VRNoV0`` variants.309 310.. _RISCVInsertVSETVLI:311 312RISCVInsertVSETVLI313==================314 315After vector registers are allocated, the ``RISCVInsertVSETVLI`` pass will insert the necessary ``vsetvli``\s for the pseudos.316 317.. code-block::318 319  dead $x0 = PseudoVSETVLI %vl:gpr, 209, implicit-def $vl, implicit-def $vtype320  $v8m2 = PseudoVADD_VV_M2 $v8m2(tied-def 0), $v8m2, $v10m2, $noreg, 5, implicit $vl, implicit $vtype321 322The physical ``$vl`` and ``$vtype`` registers are implicitly defined by the ``PseudoVSETVLI``, and are implicitly used by the ``PseudoVADD``.323The ``vtype`` operand (``209`` in this example) is encoded as per the specification via ``RISCVVType::encodeVTYPE``.324 325``RISCVInsertVSETVLI`` performs dataflow analysis to emit as few ``vsetvli``\s as possible. It will also try to minimize the number of ``vsetvli``\s that set VL, i.e., it will emit ``vsetvli x0, x0`` if only ``vtype`` needs changed but ``vl`` doesn't.326 327Pseudo expansion and printing328=============================329 330After scalar register allocation, the ``RISCVExpandPseudoInsts.cpp`` pass expands the ``PseudoVSETVLI`` instructions.331 332.. code-block::333 334   dead $x0 = VSETVLI $x1, 209, implicit-def $vtype, implicit-def $vl335   renamable $v8m2 = PseudoVADD_VV_M2 $v8m2(tied-def 0), $v8m2, $v10m2, $noreg, 5, implicit $vl, implicit $vtype336 337Note that the vector pseudo remains as it's needed to encode the register class for the LMUL. Its AVL and SEW operands are no longer used.338 339``RISCVAsmPrinter`` will then lower the pseudo instructions into real ``MCInst``\s.340 341.. code-block:: nasm342 343   vsetvli a0, zero, e32, m2, ta, ma344   vadd.vv v8, v8, v10345 346 347 348See also349========350 351- `[llvm-dev] [RFC] Code generation for RISC-V V-extension <https://lists.llvm.org/pipermail/llvm-dev/2020-October/145850.html>`_352- `2023 LLVM Dev Mtg - Vector codegen in the RISC-V backend <https://youtu.be/-ox8iJmbp0c?feature=shared>`_353- `2023 LLVM Dev Mtg - How to add an C intrinsic and code-gen it, using the RISC-V vector C intrinsics <https://youtu.be/t17O_bU1jks?feature=shared>`_354- `2021 LLVM Dev Mtg “Optimizing code for scalable vector architectures” <https://youtu.be/daWLCyhwrZ8?feature=shared>`_355