riscv/riscv-isa-manual

Clarification on syntactic dependencies for vector instructions

Opened this issue · 5 comments

Section 18.1.2. states:

In general, a register r other than x0 is a source register for an instruction i if any of the following hold:
In the opcode of i, rs1, rs2, or rs3 is set to r

For a vector instruction, if LMUL is to m with m larger than 1, then the effective source vector registers will be r, r+1, ... r + m - 1. If we only consider r, we would not be capturing all the dependencies of a vector instruction.

As the V extension spec tersely notes: NOTE: More formal definitions required.

But yes, dependencies on vector register operands need to include the entire vector register group, as specified by LMUL (or, more precisely, ceil(LMUL), since when LMUL < 1, the entire vector register is treated as part of the tail).

Must dependence tracking be based on LMUL, or could finer-grained tracking based on vl be used instead?

Yeah, I was only talking about what the definition of a syntactic dependency on a vector register would be. I don't think it's the right tool for this job.

We want to propagate dependencies at the element level, not at the vector register level. (Of course, "element level" ends up meaning "byte level", since different EEWs may be used by the producer and consumer.) Otherwise, it becomes impractical to implement temporal vector machines.

Informally, for arithmetic ops, we want the same dependency behavior as in this scalar pseudocode:

for each i in [vstart, vl-1]:
  if (!masked || v0.mask[i])
    vd[i] = vs2[i] op vs1[i]

IOW, data dependencies only propagate through active elements, and the dependency on vstart/vl and the mask is a reconvergent control dependency [1].

[1] riscvarchive/riscv-zicond#5 (comment)

I think that extensions like Zilsd have a similar problem.

Yes, though the right answer is fortunately clear-cut in that case.