我将一份C代码转换为MIPS,但是我无法理解其中的某些MIPS指令:
我已经将大部分指令与代码匹配,但是我不理解
#include <inttypes.h>
#include <stdint.h>
uint16_t
chksum(uint16_t sum, const uint8_t *data, uint16_t len)
{
uint16_t t;
const uint8_t *dataptr;
const uint8_t *last_byte;
dataptr = data;
last_byte = data + len - 1;
while (dataptr < last_byte)
{
t = (dataptr[0] << 8) + dataptr[1];
sum += t;
if (sum < t)
{
sum++;
}
dataptr += 2;
}
if (dataptr == last_byte)
{
t = (dataptr[0] << 8) + 0;
sum += t;
if (sum < t)
{
sum++;
}
}
return sum;
}
我在Godbolt编译器探索器上使用了MIPS gcc5.4,并开启了-O2
优化,使用默认的经典MIPS1 -march
,没有加载互锁:
chksum(unsigned short, unsigned char const*, unsigned short):
andi $6,$6,0xffff
addiu $6,$6,-1
addu $6,$5,$6
sltu $3,$5,$6
beq $3,$0,$L2
andi $2,$4,0xffff
move $4,$5
$L4:
lbu $3,0($4)
lbu $7,1($4)
sll $3,$3,8
addu $3,$3,$7
andi $3,$3,0xffff
addu $2,$3,$2
andi $2,$2,0xffff
addiu $4,$4,2
sltu $3,$2,$3
sltu $7,$4,$6
beq $3,$0,$L3
addiu $8,$2,1
andi $2,$8,0xffff
$L3:
bne $7,$0,$L4
nor $3,$0,$5
addu $3,$3,$6
srl $3,$3,1
addiu $3,$3,1
sll $3,$3,1
addu $5,$5,$3
$L2:
beq $6,$5,$L8
nop
$L9:
j $31
nop
$L8:
lbu $3,0($6)
nop
sll $3,$3,8
addu $2,$3,$2
andi $2,$2,0xffff
sltu $3,$2,$3
beq $3,$0,$L9
nop
addiu $2,$2,1
j $31
andi $2,$2,0xffff
我已经将大部分指令与代码匹配,但是我不理解
$L3
部分从 nor
指令开始到 $L2
前的 addu
操作。
编译器浏览器显示这部分与 while
相关,但我不明白为什么要在 $L2
分支之前操作 $5
。
t = (dataptr[0] << 8) + dataptr[1];
是一个16位大端序列的加载。但不幸的是,编译器没有使用MIPS半字加载指令,可能是因为数据可能没有16位对齐。但不幸的是,x86-64 gcc和clang也没有发现这个问题(1次加载+1次16位旋转比2次加载+移位+或操作更便宜):https://godbolt.org/g/2op8FQ - Peter Cordes