1

交流回路是

  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

4 回答 4

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 或switch 指令。您应该查看最终代码的反汇编以及中间汇编程序输出。

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

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

于 2012-12-11T13:30:59.897 回答
1

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

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

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

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

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

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

于 2012-12-11T13:36:55.783 回答
1

看起来正确。

似乎有很多冗余的负载和存储 - 优化是否完全关闭?

于 2012-12-11T13:21:48.570 回答
1

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

于 2012-12-11T13:21:51.250 回答