MIPS 中 ori 操作和 lui 之后的 add 操作有什么区别?

What is the difference between an ori operation and an add operation after lui in MIPS?

我想将 3*2^16 + 9 存储在 $t0 中。我做了 lui $t0,3addi $t0,$t0,3 。顺便说一句,在教科书中,值是通过lui之后的ori操作创建的。我这样做的方式有问题吗?两者有什么区别?

What is the difference between the two?

oriaddi 都允许 16 位立即数。

但是,ori会将立即数扩展为零,也就是说,立即数总是被视为正数,因此在32位中,扩展立即数的高16位将为零。

addi 将对立即数进行符号扩展,因此它被视为 16 位有符号值,可以是正数也可以是负数。

两者都可以,但是在使用addi时我们必须注意以下几点:如果低16位设置了符号位,那么根据符号扩展和加法的性质,它会产生效果要减少上部,所以需要在上部立即数上加一。例如,假设我们要加载一个常量 0x23458765。 lui 应该被赋予 0x2346 而不是 0x2345,然后 addi 得到 0x8765,这是负的 16 位有符号立即数,因此将从 [=15= 提供的 0x23460000 中减去 1 ], 使其成为 0x23458765.

另一个区别是 addi 会在溢出时陷入困境,这在这里是非常不受欢迎的副作用。 ori 不会陷入溢出。但是,我们可以改用 addiu,因为它也不会陷入溢出并使用与 addi.

相同的 16 位有符号立即数

注意:汇编程序通常会按照您的意图进行操作,而不是完全按照您指定的方式进行操作。在某些汇编程序中将 0x8765 与 addiaddiu 一起使用将生成多条指令以将该数字容纳为正数。例如,如果你想用 MARS 测试上述序列,我们必须使用 -30875(10) 而不是 0x8765 来让汇编器生成立即数 0x8765,否则它将使用多条指令构建+34661(10)。 (将 -30875 与 ori 一起使用也会生成多条指令,因此我们必须使用 0x8765 或 34661 在一条指令中获得立即数。)

Is there something wrong with the way I did it?

总而言之,您可以使用任何您喜欢的代码序列来构建您的常量。虽然有些文本只会显示一种方式,但其他方式当然是可能的,而且没有“正确”的方式。

话虽这么说,但是,如果您使用的是汇编程序伪函数 %hi%lo,它们是为与 addiu 一起使用而设计的——这意味着 %hi 将如果低 16 位显示为负立即数,则执行 +1。这些函数的用法如下: lui $t0, %hi(label); addiu $t0, $t0, %lo(label) — 其中 label 是(代码或数据)标签,但也可以是 32 位常量。 (MARS 不支持这些功能,所以对于 MARS,我们使用 lila 伪指令代替,它会根据需要生成一两个指令。)

%hi%lo 以这种方式工作的原因是有时序列使用加载(例如 lw)或存储(例如 swaddiu,并且所有加载和存储也使用相同的 16 位带符号立即数(因此当低 16 位变为负数时,也会产生递减上部的潜在影响)。 (那些序列 (lui;lw/sw) 可以在这里和那里保存指令,例如,如果意图是访问全局变量。)