出于教育目的,我使用https://godbolt.org/z/7F-Lhm进行翻译
// C++ code
char i = 3;
char A[] = {0,1,2,3,4,5};
int myfunction() {
return A[i];
}
Run Code Online (Sandbox Code Playgroud)
进入
# RISC-V instructions
myfunction(): # @myfunction()
lui a0, %hi(i)
lbu a0, %lo(i)(a0)
lui a1, %hi(A)
addi a1, a1, %lo(A)
add a0, a0, a1
lbu a0, 0(a0)
ret
i:
.byte 3 # 0x3
A:
.ascii "\000\001\002\003\004\005"
Run Code Online (Sandbox Code Playgroud)
但为什么是A[i]“装载” add a0, a0, a1,lbu a0, 0(a0)而不是“仅仅装载” lbu a0, a0(a1)?
lbu dest, offset(baseAdress)如果仅允许dest和baseAdresse为寄存器地址,而offset是指令字本身中的硬编码数字,则这是有意义的。但在上面的相同代码中我看到lbu a0, %lo(i)(a0)所以offset显然也可以是“有些变量”?
也许我不明白这一点的原因是因为我$hi $lo一开始就不太明白为什么这个东西是必要的。我们为什么要做lui a0, %hi(i),lbu a0, %lo(i)(a0)而不是仅仅lbu a0, 0(i)?
\n\n不仅仅是 lbu a0, a0(a1)?
\n
RISC V(和MIPS)没有基址寄存器+索引寄存器寻址模式\xe2\x80\x94,它们都只有一种,那就是基址寄存器+立即数。
\n因此A+i所需的寄存器+寄存器操作必须用单独的加法指令来完成。
\n\n\n而不是 lbu a0, 0(i)?
\n
32 位指令中没有足够的空间来保存全局地址,因此使用了多个指令。
\n您已将变量声明为全局变量,因此其中一些代码是关于访问全局变量的。
\nmyfunction(): # @myfunction()\n lui a0, %hi(i) <--- 1st part of 2 instructions for the char i global\n lbu a0, %lo(i)(a0) <--- 2nd instruction for fetching the char i global\n lui a1, %hi(A) <--- 1st part of 2 instructions for A global array\n addi a1, a1, %lo(A) <--- 2nd instruction for fetching addr of A global\n\n add a0, a0, a1 <--- the array indexing A + i\n lbu a0, 0(a0) <--- the dereference *(A+i)\n ret\ni:\n .byte 3 # 0x3\n\nA:\n .ascii "\\000\\001\\002\\003\\004\\005"\nRun Code Online (Sandbox Code Playgroud)\n如果您尝试不同的方法,您会看到其中一些消失,这样您就可以更直接地看到数组引用:
\nint myfunction(char A [], int i) {\n return A[i];\n}\nRun Code Online (Sandbox Code Playgroud)\nmyfunction(char*, int): # @myfunction(char*, int)\n add a0, a0, a1\n lbu a0, 0(a0)\n ret\nRun Code Online (Sandbox Code Playgroud)\n