在RISCV汇编中,“li”是伪指令。我有这个指令:
li t2, 0x1800
csrc mstatus, t2
Run Code Online (Sandbox Code Playgroud)
“li”被组装成以下2条指令。
lui x7 2
addi x7 x7 -2048
Run Code Online (Sandbox Code Playgroud)
我的问题是,为什么是 2 和 -2048?为什么“li”会组合成lui和addi?有针对这种行为的文档吗?
我使用“riscv64-unknown-elf-as”作为汇编器。
\n\n有针对这种行为的文档吗?
\n
这并不是真正经过考虑的行为,而是一个聪明但众所周知的代码序列,用于缩短汇编器和编译器使用的立即数的组合。
\n处理器的唯一行为是所有 I 类型指令中 12 位立即数的符号扩展。
\n设计师这样做的原因有两点:
\n他们希望允许负立即数addi,例如 、 以及 forlw和sw认为负偏移量足够有用,因为它们可以用于帧指针相对算术来访问局部变量,或者到达紧邻其前面的块的标头除其他外,该块。
更进一步,他们希望硬件只有一种12位扩展,即签名扩展。
\n这两点放在一起意味着 和lui之一:addi、lw、sw、 可以完成完整的 32 位地址/值,所有工作方式相同:第二条指令的符号扩展可能需要递增用于 的常量lui。
他们不必以这种方式构建它;他们可以这样做。例如,他们可以提供另一条指令addui,在相加之前清除高 20 位;或者,他们可以提供lw和的版本sw来执行相同的操作,或者定义lw和sw来仅支持 12 位无符号立即数。
但他们选择的是一种折衷方案,既允许一般的负立即数,又使用更简单的硬件替代方案。
\n设计人员竭尽全力简化硬件,同时考虑到嵌入式处理器和其他功率/尺寸有限的处理器
\n\n\n为什么是2和-2048?
\n
为了避免 addi 具有负 12 位数字的符号扩展功能,您必须将立即数限制为 11 位无符号,这将使第 12 位(符号位)为零,因此在 12 位中不会为负,因此永远不会扩展负号。\xc2\xa0 例如,0x400 适合 11 位,因此我们可以这样做:
\nlui x7, 1\naddi x7, x7, 0x400\naddi x7, x7, 0x400\nRun Code Online (Sandbox Code Playgroud)\n实现 0x1000 + 0x400 + 0x400 = 0x1800。
\n然而,正如您所看到的,这涉及三个指令!
\n为了缩短代码序列,我们必须利用额外的第 12 位(符号),即使它将被设置/开启/真/1/负,并且会导致立即数的高 20 位为 -1 值在使用之前由addi.
-1(由 12 位立即数的符号扩展引起的高 20 位)需要偏移 +1(高 20 位)才能获得所需的数字,并且 +1 偏移是在指令中完成的lui,因此lui x7, 2代替 1,并addi x7, x7, 0x800完成 2 指令序列。\xc2\xa0 0x800 作为有符号 12 位数字是 -2048,所以: 2 和 -2048:0x2000=8192;8192+-2048=6144;6144=0x1800。