在 ISA 设计的硬件/机器代码级别,MIPS 没有subi/subiu指令。 这是有道理的,因为 MIPS 没有 FLAGS 寄存器。
没有进位标志可以记录添加负数或减去正数之间的差异,就像在许多其他架构(x86、ARM 和许多其他较少 RISCy 架构)上一样。因此,花费额外的操作码(以及解码它的晶体管)是没有意义的。
添加否定立即数不会改变/的有符号溢出检测。当您将两个具有相同符号的数字相加并且结果具有相反的符号时,您会得到有符号溢出。或者在减法时,如果 x 和 y 有相反的符号,并且有相反的符号,那就是减法溢出(你想要捕获的地方。) 是直接的,所以将它实现为使' 的溢出检测工作。addisubiz = x - yzxsubiyz = x + y_negatedaddi
当然,通常您(或 C 编译器)只会使用addiu/subiu因为您不想陷入陷阱,并且宁愿将环绕作为签名溢出行为,除非您使用-fsanitize=undefined-behavior或其他东西进行编译。
在 asm 源代码级别,为方便起见,它可以实现为伪指令,正如您在 NIOS II 手册中的引用所示。(或者甚至作为一个宏,在不支持伪指令的汇编器上。)
subi硬件/保存指令的唯一时间subiu是您想要加32768/ 减-32678。(注意 NIOS II 手册指出subi支持-32767 .. 32768范围内的立即数,与正常有符号的 16 位 2 的补码相反-32768 .. 32767)
2 的补码中最负数是异常的,它的负数需要额外的位才能正确表示。即-(0x8000)溢出到0x800016 位立即数。任何subi作为伪指令实现的体面的汇编程序都应该对此发出警告,或者警告不要对addi/使用带符号的 16 位范围之外的立即数addiu。
addiu将其立即数符号扩展为 32 位,与 . 相同addi。“未签名”是用词不当。 为什么我们要使用 addiu 而不是 addi?. 对于 2 的补码机器,有符号和无符号加法是相同的二进制运算。命名类型匹配 C 有符号溢出是未定义的行为,但请注意未定义不需要故障。将addi其视为溢出检查的签名加法,并且仅在您特别需要时才使用它。
有趣的事实:ori其他布尔值对它们的立即数进行零扩展,因此可以使用或li $t0, val扩展为仅一条指令。val = -32768 .. 65535addiu $t0, $zero, signed_int16ori $t0, $zero, uint16