在一个循环中在此循环中执行了多少条指令?

时间:2012-12-11 13:14:01

标签: c assembly mips

C循环是

  while( *from)
  {
    *to++ = *from++;
  }

我想我基本上想知道*to++ = *from++;转换为哪些MIPS指令。我的结果是指令是14:

$L2:
   lw    $2,12($fp)
   lb    $3,0($2)
   bne    $3,$0,$L4
   j    $L3
$L4:
   lw    $2,8($fp)
   addu    $3,$fp,12
   lw    $4,0($3)
   lbu    $5,0($4)
   sb    $5,0($2)
   addu    $4,$4,1
   sw    $4,0($3)
   addu    $2,$2,1
   sw    $2,8($fp)
   j    $L2

通过查看完整的C程序,我得出了这个结论:

/* strcpy.c */

#include <stdio.h>
#include <idt_entrypt.h>

/* C stringcopy */

static void str_cpy( char *to, const char *from)
{
  while( *from)
  {
    *to++ = *from++;
  }
  *to = '\0';
}

int main()
{
  static char* hello = "Hello World!";
  static char to[4711] = "blaha blaj blurk bletch";
  int Time;

  printf("Strangen hello ser ut sa har: %s\n", hello);
  flush_cache();          /* toem cache-minnet */
  timer_start();          /* nollstall tidmatning */

  str_cpy( to, hello);

  Time = timer_stop();            /* las av tiden */
  printf("Time to copy: %d\n",Time);
  printf("Och kopian sa har: %s\n", to);
}

将其编译为MIPS程序集,结果如下:

    .file   1 "strcpy.c"

 # -G value = 8, Cpu = 3000, ISA = 1
 # GNU C version cygnus-2.7.2-970404 (mips-mips-ecoff) compiled by GNU C version cygnus-2.7.2-970404.
 # options passed:  -msoft-float
 # options enabled:  -fpeephole -ffunction-cse -fkeep-static-consts
 # -fpcc-struct-return -fcommon -fverbose-asm -fgnu-linker -msoft-float
 # -meb -mcpu=3000

gcc2_compiled.:
__gnu_compiled_c:
    .text
    .align  2
    .ent    str_cpy
str_cpy:
    .frame  $fp,8,$31       # vars= 0, regs= 1/0, args= 0, extra= 0
    .mask   0x40000000,-8
    .fmask  0x00000000,0
    subu    $sp,$sp,8
    sw  $fp,0($sp)
    move    $fp,$sp
    sw  $4,8($fp)
    sw  $5,12($fp)
$L2:
    lw  $2,12($fp)
    lb  $3,0($2)
    bne $3,$0,$L4
    j   $L3
$L4:
    lw  $2,8($fp)
    addu    $3,$fp,12
    lw  $4,0($3)
    lbu $5,0($4)
    sb  $5,0($2)
    addu    $4,$4,1
    sw  $4,0($3)
    addu    $2,$2,1
    sw  $2,8($fp)
    j   $L2
$L3:
    lw  $2,8($fp)
    sb  $0,0($2)
$L1:
    move    $sp,$fp         # sp not trusted here
    lw  $fp,0($sp)
    addu    $sp,$sp,8
    j   $31
    .end    str_cpy
    .rdata
    .align  2
$LC0:
    .ascii  "Hello World!\000"
    .sdata
    .align  2
hello.4:
    .word   $LC0
    .data
    .align  2
to.5:
    .ascii  "blaha blaj blurk bletch\000"
    .space  4687
    .rdata
    .align  2
$LC1:
    .ascii  "Strangen hello ser ut sa har: %s\n\000"
    .align  2
$LC2:
    .ascii  "Time to copy: %d\n\000"
    .align  2
$LC3:
    .ascii  "Och kopian sa har: %s\n\000"
    .text
    .align  2
    .globl  main
    .ent    main
main:
    .frame  $fp,32,$31      # vars= 8, regs= 2/0, args= 16, extra= 0
    .mask   0xc0000000,-4
    .fmask  0x00000000,0
    subu    $sp,$sp,32
    sw  $31,28($sp)
    sw  $fp,24($sp)
    move    $fp,$sp
    jal __main
    la  $4,$LC1
    lw  $5,hello.4
    jal printf
    jal flush_cache
    jal timer_start
    la  $4,to.5
    lw  $5,hello.4
    jal str_cpy
    jal timer_stop
    sw  $2,16($fp)
    la  $4,$LC2
    lw  $5,16($fp)
    jal printf
    la  $4,$LC3
    la  $5,to.5
    jal printf
$L5:
    move    $sp,$fp         # sp not trusted here
    lw  $31,28($sp)
    lw  $fp,24($sp)
    addu    $sp,$sp,32
    j   $31
    .end    main

所以我分析了上面的内容,发现在while循环的一个循环中执行的指令数是14.我的推理是否正确?

4 个答案:

答案 0 :(得分:2)

$L2:
 lw    $2,12($fp)  ;  12($fp) is 'from' - load it in to $2
 lb    $3,0($2)    ; read a byte
 bne    $3,$0,$L4  ; if it's non-zero, jump into the main loop
 j    $L3          ; otherwise exit (this is the while clause)
$L4:
 lw    $2,8($fp)   ; 8($fp) is 'to' - load it into $2
 addu    $3,$fp,12 ; Load the address of 'from' into $3
 lw    $4,0($3)    ; Load 'from' into $4
 lbu    $5,0($4)   ; Read the byte again (this is the = *from)
 sb    $5,0($2)    ; Store the byte (*to = )
 addu    $4,$4,1   ; increment from (from++)
 sw    $4,0($3)    ; store it back
 addu    $2,$2,1   ; increment to (to++)
 sw    $2,8($fp)   ; store it back
 j    $L2          ; do it all again

循环中有13个操作,因为j $ L3被跳过。

然而,正如markgz指出的那样,MIPS具有分支延迟槽,这可能需要编译器或汇编器添加nops或切换指令。您应该查看最终代码的反汇编以及中间汇编程序输出。

在这种情况下很可能在初始bne指令之后至少会有一个额外的nop,但汇编程序可能会重新排序最后的跳转而不是用nop填充。因此,如果你查看最终输出,那么14条指令可能就是总数。

那里有很多冗余 - 一半的指令只是加载/存储回局部变量,而不仅仅是将东西保存在寄存器中。这是典型的调试/未优化构建。

答案 1 :(得分:1)

看起来不错。

似乎有很多冗余负载&amp;商店 - 优化完全关闭了吗?

答案 2 :(得分:1)

实际上在执行while循环时只有13个操作(操作j $L3仅在while结束时执行)。

答案 3 :(得分:1)

您在计算中包含测试和条件跳转说明,这对我来说似乎不合适。

您的代码中已经有一个分支太多了。尝试

  while ((*to++ = *from++));

我的编译器(g86 for x86)生成更好的代码,只有一个条件跳转。在那个架构(似乎有更好的寻址模式),一个编译到

    xorl    %eax, %eax
.L8:
    movzbl  (%rsi,%rax), %edx
    movb    %dl, (%rdi,%rax)
    addq    $1, %rax
    testb   %dl, %dl
    jne .L8
    ret

所以这里内部只有三个指令加一个初始化,因为增量只在循环内完成一次而不是两次。一般来说,在提出这样的问题时你必须要小心,(*to++ = *from++)本身并没有真正的成本,而只是嵌入到周围的代码中。