October 14th 2023 update: after public feedback RISC-V ISA committee has decided to modify the behavior of Zicond instruction when Zkt is supported: they must expose data independent timing for both value (rs1
) and condition (rs2
) operands.
On April 20th 2023, the 30-day public review for a new RISC-V ISA extension, Zicond, started. We will review in this short post what Zicond, RISC-V integer conditional operations extension, contains (so an early reader of this post can participate actively to the public review).
Note: The public review constitutes one of the last steps for any new extension before ratification. It follows the submission of a frozen specification by a task group and the review of the architectural review committee. It offers an occasion to the RISC-V community to review extensions candidates for ratification and for any member to share their feedback with the task group (and the RISC-V community at large), the task group must gather and review the public feedback.
The 2nd release candidate for the specification can be found there: https://github.com/riscv/riscv-zicond/releases/download/v1.0-rc2/riscv-zicond-v1.0-rc2.pdf
New instructions
Zicond introduces two new instructions: czero.eqz
and czero.nez
czero.eqz rd, rs1, rs2
tests the value contained in the general purpose register rs2
, if it is equal to zero then it fills rd
with 0s otherwise it copies the content of rs1
to rd
.
The specification of czero.nez rd, rs1, rs2
is very similar, except that the condition to fill rd
with 0s is rs2
not equal to zero.
It was possible to write down a sequence of instructions performing a conditional operation in RISC-V ISA before the introduction of Zicond. The new extension reduces the number of instruction required to do so but it also provide more opportunity for micro-architecture to optimise the execution of such operation: its branch semantic.
Branch semantic
One of the interesting point of czero
is that it is specified as behaving as a branch instruction: the condition on rs2
is evaluated, if true the value 0 is moved to the destination rd and the execution continues with the next instruction, else it falls into a move of rs1
to rd
before continuing with the next instruction. This means that implementations do not need to evaluate rs1
to resolve the instruction, rs1
only needs to be evaluated if the condition on rs2
is false. This can be leveraged, for example by predicting the condition on rs2
, if it is predicted as being true then there is no need to wait on rs1
: rd
can be zero-ifed and the execution can continue. Eventually, the speculation needs to be resolved and may lead to backtracking if miss-speculated, but when correct this instruction could be evaluated with only one of its two operands being ready.
Building other conditionals through sequences
https://github.com/riscv/riscv-zicond/blob/main/zicondops.adoc#instruction-sequences
The specification lists 12 sequences of conditional operations which can be built with a czero
and at least one other instruction.
For example:
czero.nez rd, rs2, rc
xor rd, rs1, rd
This sequence can be used to build a conditional xor
: if rc
is non-zero then rs1
is copied to rd
else rs1^rs2
is copied to rd
.
Note: This sequence inverses the condition as it appears in the
czero.nez
instruction: if the condition is met (rc != 0
) then 0 gets copied intord
by the first instruction and the second instruction results inrd
taking the final valuers1
, whereas if the condition is false (rc == 0
) then the first instruction copiesrs2
intord
and the second instruction results inrd
taking the final valuers1^rs2.
The specification also lists 3-instruction sequences which rely on a temporary register and provide more functionalities. For example the following sequence can be used to implement a conditional select (with condition being equal-to-zero):
czero.nez rd, rs1, rc
czero.eqz rtmp, rs2, rc
or rd, rd, rtmp
Note: Besides
rc
,rs1
,rs2
andrd
this sequence requires an extra (temporary) registerrtmp
.
Zicond and Zkt
If Zkt (timing independent execution latency) is enabled, the two instructions of Zicond must enforce timing independence with respect to both their rs1
data and rs2
condition operands.
Note: in an earlier version of the specification there is was no timing constraint on the
rs2
condition operand even when Zkt was supported.
Since Zkt is part of the RVA application profile, this constant timing behavior is going to be the default behavior for most Zicond implementations.
Conclusion
Zicond introduces two instructions bringing more way to generate conditional operations in RISC-V programs while providing branch semantic (useful to allow micro-architectural optimization and eventually faster execution).
At the time of writing, the public review period is still open. Feel free to join the discussion and share your feedback (either by opening an issue on github: https://github.com/riscv/riscv-zicond/issues, or in the group mailing list: https://lists.riscv.org/g/tech-announce/message/218).
October 14th 2023 update: adding mention of change of specification when Zkt is supported.
Resources:
Zicond specification v1.0-rc2 pdf
Zicond standard repository: Zicond github repo
Mailing list announcement of the change of Zicond spec when Zkt is enforced.