由MIPS指令想到数组与指针
对程序员来说,最重要的莫过于掌握指针的用法了。
先来看下面两个程序:
程序1 程序2
clear1(int array[], int size) clear2(int *array[0]; int size)
{ {
int i; int *p;
for (i=0;i<size;i=i+1) for(p=&array[0];p<&array[size];p=p+1)
array=0; *p=0;
} }
先分析程序1,根据我们的约定,一般用$4,$5,$6,$7来保存子程序的参数。所以我们假设两个参数array和size被保存在寄存器$4,$5中,i被保存在寄存器$2中。
1. 初始化i,for 循环的第一部分
move $2,$0 # i=0 (register $0=0)
2. 为将array赋为0,我们要做三步工作
loop1 muli $14,$2,4 # $14=i*4
add $3,#4,$14 # $3=address of array
sw $0,0($3) # array=0
3. 将i自加1,即i=i+1;
addi $2,$2,1 # i=i+1
4. 程序判断i是否还是小于size,如果是的话,再开始下一轮循环。
slt $6,$2,$5
bne $6,$0,loop1
总结如下:
move $2,$0 # i=0
loop1 : muli $14,$2,4 # $14=i*4
add $3,$4,$14 # $3=address of array
sw $0,0($3) # array=0
addi $2,$2,1 # i=i+1
slt $6,$2,$5 # $6=1(i<size)
bne $6,$0,loop1 # if(i<size) go to loop1
分析程序2:
第一步也是用$4,$5保存两个参数array 和size,把p分派到寄存器$2中。
1. 将指针p指向数组的第一个元素array[0]
move $2,$4 # p=address of array[0]
2. 将指针p赋为0
loop2 sw $0,0($2) # Memory[0]=0
3. 将指针指向下一个字
addi $2,$2,4 # p=p+4
4. 得到数组的最后一个元素array[size]的地址值:
muli $14,$5,4 # $14=size*4
add $3,$4,$14 # $3=address of array[size]
5. 判断并跳转
slt $6,$2,$3 # $6=(p<array[size])
bne $6,$0,loop2 # if(p<array[size]) go to loop2
总结如下:
move $2,$4 # p=address of array[0]
loop2 : sw $0,0($2) # Memory[p]=0
addi $2,$2,4 # p=p+4
muli $14,$5,4 # $14=size*4
add $3,$4,$14 # $3=address of array[size]
slt $6,$2,$3 # $6=(p<array[size])
bne $6,$0,loop2 # if (p<array[size]) go to loop2
我们注意到在每一个循环中,数组的末地址是不变的,所以程序二又可以写成下面的代码:
move $2,$4 # p=address of array[0]
muli $14,$5,4 # $14=size*4
add $3,$4,$14 # $3=address of array[size]
loop2: sw $0,0($2) # Memory[p]=0
addi $2,$2,4 # p=p+4
slt $6,$2,$3 # $6=(p<array[size])
bne $6,$0,loop2 # if (p<array[size]) go to loop2
让我们来比较两个程序的代码:
move $2,$0 move $2,$4
loop1: muli $14,$2,4 muli $14,$5,4
add $3,$4,$14 add $3,$4,$14
addi $2,$2,1 loop2: sw $0,0($2)
sw $0,0($3) addi $2,$2,4
slt $6,$2,$5 slt $6,$2,$3
bne $6,$0,loop1 bne $6,$0,loop2
现在我们从对两个程序的分析中,发现指针给我们的程序运行带来的不可多得的优化,使程序的循环变得更为简洁,所以在一般的现代的编译器中会将程序1优化成程序2。 |