[[insns-vclmul, Vector Carry-less Multiply]]
= vclmul.[vv,vx]

Synopsis::
Vector Carry-less Multiply by vector or scalar - returning low half of product.

Mnemonic::
vclmul.vv vd, vs2, vs1, vm +
vclmul.vx vd, vs2, rs1, vm

Encoding (Vector-Vector)::
[wavedrom, , svg]
....
{reg:[
{bits: 7, name: 'OP-V'},
{bits: 5, name: 'vd'},
{bits: 3, name: 'OPMVV'},
{bits: 5, name: 'vs1'},
{bits: 5, name: 'vs2'},
{bits: 1, name: 'vm'},
{bits: 6, name: '001100'},
]}
....

Encoding (Vector-Scalar)::
[wavedrom, , svg]
....
{reg:[
{bits: 7, name: 'OP-V'},
{bits: 5, name: 'vd'},
{bits: 3, name: 'OPMVX'},
{bits: 5, name: 'rs1'},
{bits: 5, name: 'vs2'},
{bits: 1, name: 'vm'},
{bits: 6, name: '001100'},
]}
....
Reserved Encodings::
* `SEW` is any value other than 64

Arguments::

[%autowidth]
[%header,cols="4,2,2"]
|===
|Register
|Direction
|Definition

| Vs1/Rs1 | input  |  multiplier
| Vs2 | input  |  multiplicand
| Vd  | output | carry-less product low
|===

Description::
Produces the low half of 128-bit carry-less product.

Each 64-bit element in the `vs2` vector register is carry-less multiplied by 
either each 64-bit element in `vs1` (vector-vector), or the 64-bit value
from integer register `rs1` (vector-scalar). The result is the least
significant 64 bits of the carry-less product.

[NOTE]
====
The 64-bit carryless multiply instructions can be used for implementing GCM in the absence of the `zvkg` extension.
We do not make these instructions exclusive as the 64-bit carryless multiply is readily derived from the
instructions in the `zvkg` extension and can have utility in other areas.
Likewise, we treat other SEW values as reserved so as not to preclude
future extensions from using this opcode with different element widths.
For example, a future extension might define an `SEW`=32 version of this instruction to enable `Zve32*` implementations to have
vector carryless multiplication instructions.
====

Operation::
[source,sail]
--


function clause execute (VCLMUL(vs2, vs1, vd, suffix)) = {

  foreach (i from vstart to vl-1) {
    let op1 : bits (64) = if suffix =="vv" then get_velem(vs1,i)
                          else zext_or_truncate_to_sew(X(vs1));
    let op2 : bits (64) = get_velem(vs2,i);
    let product : bits (64) = clmul(op1,op2,SEW);
    set_velem(vd, i, product);
  }
  RETIRE_SUCCESS
}

function clmul(x, y, width) = {
  let result : bits(width) = zeros();
  foreach (i from 0 to (width - 1)) {
    if y[i] == 1 then result = result ^ (x << i);
  }
  result
}
--

Included in::
<<zvbc>>, <<zvknc>>, <<zvksc>>
