RISC-V architecture, why do one add 4 bytes with no branch but shift with one when branch?

If I understand correctly, when you increment the Program Counter (PC), it needs to be increased by four bytes because all instructions are 32 bits, correct?

What confuses me is that I thought the 'Shift Left 1' operation needed to be 'Shift Left 2.' I then realized that the RISC-V ISA has an extension that supports 16-bit instructions. In that case, it makes sense to multiply the immediate value by two ('Shift Left 1'). However, now it doesn't seem logical to increment the PC by four bytes.

I don't understand, does the assembler automatically handle this? If so how? I have attached the RISC-V architecture for reference.


  • why add 4 bytes with no branch but shift by one when branch?

    Simple answer is that is how the ISA defines things; however the motivation is for all RISC V instruction sets to be compatible with variable-sized instruction capabilities.

    The encodings for RISC V allow for 32-bit, 16-bit, and larger in increments of 16 bits.  Because of this, branch offsets are encoded × 2 (instead of × 4 as is done on MIPS, which also has 4 byte instructions).

    While this means that the range/reach of a branch instruction is reduced (for no benefit on processors that only support 32-bit instructions), the advantage is in tooling and binary machine code compatibility with processors that do support instruction sizes beyond 32 bits.

    Currently, there is only one non-32-bit specification, RVC, aka the compressed instruction set profile, which defines 16-bit instructions, and can be added to base RV32 or RV64, meaning such processors have both 32-bit and 16-bit instructions.

    FYI, RVC appears quite popular, it seems to me; compilers like GCC (example on Godbolt) default to targeting a RISC-V supporting them. But for students looking at CPU internals for the first time, simpler is better, keeping only the complexity necessary to have a CPU at all, then to pipeline it.