GCC生成的RISC-V汇编中为何会出现冗余mv指令?
la Pseudo-Instruction: Redundant mv Explanation Let's break down this behavior of the RISC-V GNU toolchain clearly:
Why is the redundant mv a4,a4 instruction generated?
The la (load address) pseudo-instruction exists to simplify loading a symbol's absolute address into a register. On RISC-V, this usually requires two instructions:
auipc: Sets the upper 20 bits of the register using the current PC plus the symbol's upper address bitsaddi: Fills in the lower 12 bits of the address to get the full absolute value
In your scenario, the offset between the auipc instruction (at 0x1018) and L2 (at 0x2018) is exactly 0x1000 — meaning the lower 12 bits of the offset are 0. The auipc a4, 0x1 instruction already computes the full correct address:
0x1018 (current PC) + (0x1 << 12) = 0x1018 + 0x1000 = 0x2018
The redundant mv a4,a4 (which is a stand-in for addi a4,a4,0) comes from the GNU Assembler's (GAS) default expansion logic. Instead of adding extra checks to see if the lower 12 bits are zero and skip the second instruction, GAS uses a consistent two-instruction template for all la expansions. This simplifies the pseudo-instruction handler and keeps instruction sequences uniform, which can help with pipeline predictability in some cases.
Can I safely remove this redundant instruction?
Yes, completely safely. The auipc instruction already loads the exact address of L2 into a4 — the mv instruction is a no-op (it does nothing to the register's value). Removing it won't change the behavior of your code: the sw a3,0(a4) instruction will still write a3's value to 0x2018, just as intended.
Does GCC require la to expand to two instructions?
No, there's no mandatory requirement. Modern versions of the RISC-V GNU toolchain (with optimizations enabled, even -O1 or above) will detect when the lower 12 bits of the offset are zero and optimize out the redundant addi/mv instruction, leaving only the auipc.
The redundant instruction you're seeing is likely caused by one of these:
- An older toolchain version that doesn't include this small optimization
- Compiling with
-O0(no optimizations), where the assembler prioritizes strict template expansion over eliminating no-ops - Custom compiler/assembler flags that disable this specific optimization
内容的提问来源于stack exchange,提问作者Plasty Grove

