opened
chuanhua
username_0
In order to manipulate RVV stack (prologue, epilogue, stack reference, register alignment, function argument in stack) efficiently, we need a scalar "addvl" instruction to add an integer multiple of vlenb value to stack pointer. Without this instruction, we need several instructions to calculate the stack pointer value and need to allocate several scalar tmp registers for this calculation which may lead to extra register save/restore code.

Example 1: allocate RVV stack in prologue:
`csrr  t0, vlenb`
`addi  t1, zero, 7`
`mul t0, t0, t1`
`sub sp, sp, t0`

Example 2: reference vector stack object, offset #7
`addi a0,sp,#unscaled_offset`
`csrr  a1, vlenb`
`addi  a2, zero, 7`
`mul a2, a1, a2`
`add a0, a0, a2`
`vl1r.v  v24, (a0)`

Is it possible to add such an instruction for efficient RVV stack support?
Adding "addvl" instruction for efficient stack pointer calculation
issue
created
kito-cheng
username_1
+1, that will significantly simplify the code gen for spilling vector register.
comment
created
chuanhua
username_0
The basic form of "addvl" instruction should use the vlenb CSR as an implied source operand. And I think whether LMUL needs to be considered as another implied source operand can be discussed.
comment
created
David-Horner
username_2
Adding to sp does not help with Example 2.

The problem you are stating is the difficulty deriving a multiple of vlenb to add/subtract from a register, especially sp.

Since vlenb is a Read Only CSR, the csrrw and csrrwi are unused.

These variants could be used to request a multiplier for vlenb.


Thus examples 1 and 2 become.

Example 1: allocate RVV stack in prologue:
csrrwi t0, vlenb, 7
sub sp, sp, t0

Example 2: reference vector stack object, offset #7
csrrwi a0, vlenb, 7
addi a0,a0,#unscaled_offset
add a0,a0,sp,
vl1r.v v24, (a0)

Note: csrrwi on vlenb will likely be assigned an alias (maybe vlenxi and vlenx?)

Some may object to this unorthodox use of csrrw, however, such use is planned for fast interrupt TG and been floated for other uses as well.
comment
created
chuanhua
username_0
I am sorry that I did not describe the "addvl" instruction envisioned clearly. What I am actually thinking about the addvl instruction has the following syntax and functionality.

"addvl  rd, rs1, signed_imm_6bit"
"rd = rs1 + (signed_imm_6bit * vlenb)"

So it should be useful for example 2 as well. But it seems that I cannot find an existing instruction format with 6-bits of immediate values.

Your proposal of using "csrrwi rd, vlenb, unsigned_imm_5bit" with the function of "rd = unsigned_imm_5bit * vlenb" is a good idea.
comment
created
aswaterman
username_3
I'm not much of a fan of the "magic CSR" approach.  It creates an awkward special case, since many styles of implementation perform CSR accesses at commit, whereas here we want to execute the instruction earlier in the pipeline.  It also adds a special case to the illegal-instruction detection logic, since currently all CSRs with address bits 11:10=3 trap on writes.
comment
created
chuanhua
username_0
Then we can define 2 instructions in the OP opcode space as follows:

"addvl rd, rs1, uimm5" --> "rd = rs1 + (uimm5 * vlenb_const)" // when rs1=x0, rd = uimm5 * vlenb_const
"subvl rd, rs1, uimm5" --> "rd = rs1 - (uimm5 * vlenb_const)" // when rs1=x0, rd = - (uimm5 * vlenb_const)
comment
created
aswaterman
username_3
TG should discuss whether to add such instructions, but if they are approved, I think your signed-immediate version is fine.
comment
created
David-Horner
username_2
comment
created
vbx-glemieux
username_4
Have you worked out what this would look like with a larger example?

This code snippet is to save or load a single vector register. Normally,
the code would be saving/restoring multiple registers. This takes a long
time to execute. For each vector register saved/loaded, a new base address
needs to be computed. I don't think you would use addvl to compute the
address from scratch each time, when you can simply do a subi/addi to
modify sp each time.

Instead, perhaps we need vload/vstore instructions that compute the
required effective address using the register number? For example:

vl1r.v vX,(a0)

where EffectiveAddress = a0 + (vlenb * X)

The "*X" is a variable shift.

Guy
comment
created
kasanovic
username_5
Moved to post v1.0.
comment