解析C转MIPS汇编中while循环关联的nor指令段逻辑
解析MIPS汇编中while循环后的那段优化代码
你提到的从nor到addu $5,$5,$3的指令,是GCC在-O2优化下生成的循环后位置计算逻辑,目的是直接算出C代码中dataptr循环结束后的最终位置,简化后续的单字节判断。我们一步步拆解:
先明确寄存器对应关系(MIPS O32调用约定)
$4:第一个参数sum$5:第二个参数data(初始指针)$6:第三个参数len,后续被计算为last_byte = data + len -1$2:返回值寄存器,用来存储sum
代码逐行解析
我们把这段指令和对应的数学计算对应起来:
nor $3,$0,$5 # $3 = ~$5 → 补码中等价于 -$5 -1 addu $3,$3,$6 # $3 = (~$5) + $6 = ($6 - $5) -1 → 也就是 (last_byte - data) -1 = len-2 srl $3,$3,1 # 逻辑右移1位 → 无符号整数除法,$3 = (len-2) // 2 addiu $3,$3,1 # $3 = (len-2)//2 + 1 sll $3,$3,1 # 左移1位 → 乘以2,$3 = 2 * [(len-2)//2 + 1] addu $5,$5,$3 # $5 = data + $3 → 得到循环结束后dataptr的最终位置
为什么要这么计算?
回到你的C代码逻辑:
- 循环
while (dataptr < last_byte)每次处理2字节,dataptr +=2 - 循环结束后,
dataptr的位置只有两种可能:- 当
len是奇数:dataptr最终等于last_byte(需要处理剩余的1字节) - 当
len是偶数:dataptr最终等于last_byte +1(无剩余字节)
- 当
这段汇编就是用位运算高效计算出这个最终位置:
- 举个奇数长度的例子:
len=5,计算得$3=4,$5=data+4=last_byte(符合情况1) - 举个偶数长度的例子:
len=4,计算得$3=4,$5=data+4=last_byte+1(符合情况2)
编译器的优化意图
在-O2优化下,GCC会尽量避免依赖循环中寄存器的状态(比如原来的dataptr存在$4),而是通过数学计算直接得到目标位置,这样:
- 可以消除循环后对
$4寄存器的依赖,减少寄存器冲突 - 把后续
dataptr == last_byte的判断简化为$5 == $6(对应汇编里的beq $6,$5,$L8),逻辑更直接高效
对应C代码的等价逻辑
这段汇编可以翻译成如下C代码,你就能更直观理解:
// 计算循环结束后dataptr的最终位置 const uint8_t *final_dataptr = data + 2 * ((len - 2)/2 + 1); // 后续判断final_dataptr == last_byte,决定是否处理剩余单字节
现在你应该明白这段代码操作$5寄存器的原因了——它把$5从初始的data指针,改成了循环结束后dataptr的最终位置,为后续的单字节判断做准备。
内容的提问来源于stack exchange,提问作者I know nothing
相关产品推荐
相关产品推荐

