在RISCV汇编中,“li”是伪指令。我有这个指示:
li t2, 0x1800 csrc mstatus, t2
“li”被组装成以下2个指令。
lui x7 2 addi x7 x7 -2048
我的问题是,为什么是2和-2048?为什么“离”会组合成“律”和“增”?这种行为有文件规定吗?我使用“riscv 64-unknown-elf-as”作为汇编程序。
g6baxovj1#
这种行为有文件规定吗?这不是真正考虑的行为,而是一个聪明但众所周知的代码序列,用于缩短汇编器和编译器使用的立即数的合成。处理器的唯一行为是所有I型指令中的12位立即数的符号扩展。设计师这样做的原因是两件事的结合:
addi
lw
sw
这两点合在一起意味着lui和以下之一:addi、lw、sw可以完成完整的32位地址/值,所有工作方式相同:第二指令的符号扩展可能需要递增用于lui的常数。他们不需要这样设计例如,它们可以提供另一条指令addui,该指令在加法之前清除高20位;或者,他们可能已经提供了lw和sw的版本来做同样的事情,或者定义了lw和sw来只支持12位无符号立即数。但他们选择的是一种折衷方案,既允许一般的负立即数,也允许硬件中更简单的一种。设计人员已经在一定程度上简化了硬件,同时考虑了嵌入式和其他功率/尺寸受限的处理器为什么是2和-2048?为了避免addi的符号扩展特性,你必须将立即数限制为11位无符号,这将使第12位(符号位)为零,因此在12位中不会为负,所以永远不会扩展负号。例如,0x 400适合11位,因此我们可以这样做:
lui
addui
lui x7, 1 addi x7, x7, 0x400 addi x7, x7, 0x400
实现0x 1000 + 0x 400 + 0x 400 = 0x 1800。但是,正如你所看到的,这涉及到三个指令!为了缩短代码序列,我们必须利用额外的第12位(符号),即使它将被设置为/on/true/1/negative,并且将导致addi使用前立即数的高20位的值为-1。该-1(由12位立即数的符号扩展引起的高20位)需要偏移+1(高20位)以获得所需的数字,并且该+1偏移在lui指令中完成,因此lui x7, 2而不是1,并且addi x7, x7, 0x800完成2指令序列。0x 800作为有符号的12位数是-2048,因此:2和-2048。
lui x7, 2
addi x7, x7, 0x800
1条答案
按热度按时间g6baxovj1#
这种行为有文件规定吗?
这不是真正考虑的行为,而是一个聪明但众所周知的代码序列,用于缩短汇编器和编译器使用的立即数的合成。
处理器的唯一行为是所有I型指令中的12位立即数的符号扩展。
设计师这样做的原因是两件事的结合:
addi
这样的指令的负立即数,以及lw
和sw
认为负偏移量足够有用,因为它们可以用于帧指针相对算术来访问局部变量,或者到达紧接在块之前的块的头部,等等。这两点合在一起意味着
lui
和以下之一:addi
、lw
、sw
可以完成完整的32位地址/值,所有工作方式相同:第二指令的符号扩展可能需要递增用于lui
的常数。他们不需要这样设计例如,它们可以提供另一条指令
addui
,该指令在加法之前清除高20位;或者,他们可能已经提供了lw
和sw
的版本来做同样的事情,或者定义了lw
和sw
来只支持12位无符号立即数。但他们选择的是一种折衷方案,既允许一般的负立即数,也允许硬件中更简单的一种。
设计人员已经在一定程度上简化了硬件,同时考虑了嵌入式和其他功率/尺寸受限的处理器
为什么是2和-2048?
为了避免addi的符号扩展特性,你必须将立即数限制为11位无符号,这将使第12位(符号位)为零,因此在12位中不会为负,所以永远不会扩展负号。例如,0x 400适合11位,因此我们可以这样做:
实现0x 1000 + 0x 400 + 0x 400 = 0x 1800。
但是,正如你所看到的,这涉及到三个指令!
为了缩短代码序列,我们必须利用额外的第12位(符号),即使它将被设置为/on/true/1/negative,并且将导致
addi
使用前立即数的高20位的值为-1。该-1(由12位立即数的符号扩展引起的高20位)需要偏移+1(高20位)以获得所需的数字,并且该+1偏移在
lui
指令中完成,因此lui x7, 2
而不是1,并且addi x7, x7, 0x800
完成2指令序列。0x 800作为有符号的12位数是-2048,因此:2和-2048。