I dislike the lack of arithmetic instructions with built-in trap on overflow (even imprecise with a fence could be fine), but maybe that's too expensive to do in hardware.
FYI, here is the rationale section on that subject:
We did not include special instruction set support for overflow checks on integer arithmetic operations in the base instruction set, as many overflow checks can be cheaply implemented using RISC-V branches. Overflow checking for unsigned addition requires only a single additional branch instruction after the addition: add t0, t1, t2; bltu t0, t1, overflow.
For signed addition, if one operand’s sign is known, overflow checking requires only a single branch after the addition: addi t0, t1, +imm; blt t0, t1, overflow. This covers the common case of addition with an immediate operand.
For general signed addition, three additional instructions after the addition are required, leveraging the observation that the sum should be less than one of the operands if and only if the other operand is negative.
This is kind of a poor argument, since it applies equally to any request to add instructions to RISC that can be implemented by other instructions. A 4:1 increase in cost isn't brilliant either.
The problem is that few high level languages support this well either. Having an instruction that traps like division by zero isn't great, because it's quite expensive to turn a machine trap into a high-level exception.
What I would like to try is a separate "addsat" instruction which (a) provides saturating arithmetic and (b) sets a flag if saturation has applied, but does not clear it if it has not been applied. That allows you to write a bunch of arithmetic in a natural way (a1b1 + a2b2 - a3*b3) etc, and only at the end test for overflow. It would behave more like a propagating integer NaN. Since it's a flag rather than a trap a high-level language can more easily convert it to an exception, or provide other processing.
(Saturation arithmetic is useful on its own in some cases, but usually for 8 or 16 bit values)
See also these topics: macro-op fusion, compressed instructions, extensions.
RISC-V publishes (at least for some cores) the preferred order that you have to emit instructions in order for those to be recognized and fused into efficient micro ops. The compressed (C) extension means that instructions don't take up too much extra space in the I-cache.
Of course we don't know -- because very high performance RISC-V chips don't (yet) exist -- if this will really work when the silicon hits the road, but the plan makes some sense and has the (IMHO) large advantage that it keeps the standard small and easy to implement (in those cases where you don't much care about performance).
There are also extensions, which RISC-V formalizes properly. You can with relative ease add your own addsat instruction through a private extension, and (with somewhat more difficulty) propose a public extension if this is generally useful.
For an ISA whose main use will be IoT (at least in the beginning), this isn't good..
Rust didn't put integer overflow checks in release mode because current CPU don't provide "free" integer overflow detection, RISC V is even a regression over MIPS here..
> Rust didn't put integer overflow checks in release mode because current CPU don't provide "free" integer overflow detection
Not really; the main performance drawback of obligate overflow checks is excessively-constrained semantics of the resulting code making optimization harder, not the direct CPU cost of checking. There are other ways of detecting possible overflows, and Rust does check for overflow in debug mode (this is specifically in order to ensure that most Rust code will work properly even when checks are enabled, and will not simply end up relying on underspecified semantics.)