计算机系统基础 8 循环程序

概要

        两种实现方法——分支指令实现和专门的循环语句实现以及有关循环的优化。

分支指令实现

        倒计数

       ……

       MOV  ECX,循环次数

LOOPA:……

       ……

       DEC   ECX

       JNE   LOOPA     

        正计数 

       ……

       MOV  ECX,0

LOOPA

       ……

       INC  ECX

       CMP  ECX,  n

       JNE  LOOPA              

        循环次数不固定 

        比如要求一个以0为结束符的字符串的长度,需要通过指令来测试条件是否成立,决定继续循环还是结束循环。

下面例子(AX)中 1 出现的次数 -> CL     

MOV  CL, 0

L:  AND  AX , AX

    JZ   EXIT

    SAL  AX , 1

    JNC  L

    INC  CL

    JMP  L

EXIT:

或者这样

      MOV   CL,  0

      MOV   BX, 16

L:    SAL   AX , 1

      JNC   NEXT

      INC   CL

NEXT: DEC   BX

      JNZ   L

 专门的循环指令 

LOOP    标号

LOOPE   标号

LOOPNE  标号

JECXZ   标号

LOOP 

        ① (ECX) -1 ➡  ECX,

        ②若 (ECX)  不为0, 则转标号处执行。

    基本等价于: 

                  DEC   ECX

                  JNZ   标号

  (但LOOP指令对标志位无影响!)

LOOPE / LOOPZ 

        ①(ECX) - 1 ➡ ECX,

        ② 若(ECX)不为0, 且ZF=1,则转标号处执行。

   (等于或为0循环转移指令, 本指令对标志位无影响)

        32位段用 ECX16位段用 CX 

例:判断以BUF为首址的10个字节中是否有非0字节。

    有,则置ZF为0, 否则ZF置为1。                    

      MOV    ECX, 10

      MOV    EBX, OFFSET BUF -1

L3 :  INC    EBX

      CMP    BYTE PTR [EBX], 0

      LOOPE  L3

LOOPNE  / LOOPNZ  

        ①(ECX) -1 ➡ ECX

        ②若(ECX)≠0, 且ZF=0,则转标号处执行。

例:判断以MSG为首址的10个字节中的串中是否有空格字符。无空格字符,置ZF为0,否则为1。                               

       MOV     ECX,  10

       MOV     EBX,  OFFSET MSG -1

L4 :   INC     EBX

       CMP     BYTE PTR [EBX],‘ ’

       LOOPNE  L4

JECXZ  标号

     若 (ECX) 为0, 则转标号处执行。

    (先判断,后执行循环体时,可用此语句,标号为循环结束处)

 有关循环的优化方法

         循环展开

int  i = 0, sum = 0, a[5];

    ……

for  (i = 0; i < 5; i++)       sum += a[i];

Debug版本

00D71750  mov   dword ptr [i],0 

00D71757  jmp   f+62h (0D71762h) 

00D71759  mov   eax,dword ptr [i

00D7175C  add   eax,1 

00D7175F  mov   dword ptr [i],eax 

00D71762  cmp   dword ptr [i],5    

00D71766  jge   f+77h (0D71777h) 

00D71768  mov   eax,dword ptr [i]

00D7176B  mov   ecx,dword ptr [sum] 

00D7176E  add   ecx,dword ptr a[eax*4] 

00D71772  mov   dword ptr [sum],ecx 

00D71775  jmp   f+59h (0D71759h)

00D71777  // 循环结束

Release版本:

 mov  eax,dword ptr [ebp-8] 

 add  eax,dword ptr [ebp-0Ch] 

 add  eax,dword ptr [ebp-10h] 

 add  eax,dword ptr [ebp-14h] 

 add  eax,dword ptr [ebp-18h] 

 mov  sum, eax

若循环变量从5改为n

          mov  edi, sum  ; edi来存放 和

          xor  eax, eax  ; eax 对应 i

          mov  edx, n    ; edx 对应 n

          jmp  main+0C5h (05E1145h)

005E1140  add  edi,dword ptr [ebp+eax*4-18h] 

005E1144  inc  eax 

005E1145  cmp  eax,edx 

005E1147  jl   main+0C0h (05E1140h)

变量与寄存器绑定,语句数量大幅减少,循环部分由 10 条语句减为 4 条语句

        传输优化

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

void main()
{
char  buf1[20];
char  buf2[20];
int   i;
scanf("%s", buf1); 
for (i = 0;i < 20;i++)
   buf2[i] = buf1[i];
printf("%s\n", buf2);
return;
}

for (i = 0;i < 20;i++)

buf2[i] = buf1[i];

printf("%s\n", buf2);

0025109E  mov         eax,dword ptr [ebp-8] 

002510A1  movups      xmm0,xmmword ptr [buf1] 

002510A5  mov         dword ptr [ebp-1Ch],eax 

002510A8  lea         eax,[buf2] 

002510AB  push        eax 

002510AC  push        offset string "%s\n" (0252104h) 

002510B1  movups      xmmword ptr [buf2],xmm0 

002510B5  call        printf (0251020h) 

可以看到,ebp - 8就是buf1+16

buf1 的前16个字节拷贝到 xmm0,后4个字节拷贝到 eax,再分别送到 buf2 相应位置

 但是像这种,就不好优化

void main()
{
char  buf1[20];
char  buf2[20];
int   i;
scanf("%s", buf1); 
……
printf("%s\n", buf2);
return;
}
void fcopy(char* dst, char* src)
{
    int i;
    for (i = 0;i < 20;i++)
    {
       *dst = *src;
       dst++;
       src++;
    }
}

scanf("%s", buf1);

003D1090  lea         eax,[ebp-18h] 

003D1093  push        eax 

003D1094  push        3D2100h 

003D1099  call        003D1050 

003D109E  add         esp,8 

003D10A1  xor         eax,eax 

fcopy(buf1-20, buf1);

003D10A3  mov         cl,byte ptr [ebp+eax-18h] 

003D10A7  mov         byte ptr [ebp+eax-2Ch],cl 

003D10AB  inc         eax 

003D10AC  cmp         eax,14h 

003D10AF  jl          003D10A3 

printf("%s\n", buf2);

总结

编译优化

  • 循环展开:消除了循环
  • 与寄存器绑定:减少访存操作,减少指令
  • XMM寄存器、成组运算等,减少指令
  • 16
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值