EDIT: Hmm, I seem to have picked a bad example. Try this one:
int get(int *base, unsigned index) {return base[index];}
Arm64:
update:
ldr w0, [x0, w1, uxtw 2]
ret
RV64GC (vanilla):
update:
slli a5,a1,32
srli a1,a5,30
add a0,a0,a1
lw a0,0(a0)
ret
RV64GC+Zba:
update:
sh2add.uw a0,a1,a0
lw a0,0(a0)
ret
Arm64 is able to do some indexed loads in a single instruction that might take two in RISC-V w/Zba (and up to 4+ in regular RISC-V). However, calling that a win for Arm64 is not so clear as the more complicated addressing modes could become a critical timing path and/or require an extra pipeline stage. However, as a first approximation, for a superscalar dynamically scheduled implementation, fewer ops is better so I would say it's a slight win.
I don't understand the obsession with bytes. 25% fewer bytes has only very marginally impact on a high-performance implementation and the variable length encoding has some horrendous complications (which is probably why Arm64 _dropped_ variable length instructions). Including compressed instruction in the Unix profile was the biggest mistake RISC-V did and I'll die on that hill.
ADD: Don't forget that every 32-bit instruction is currently wasting the lower two bits to allow for compressed, thus any gain from compress must be offset by the 6.25% tax that is forced upon it.