【问题标题】:Converting MIPs instruction to C and reducing the execution将 MIP 指令转换为 C 并减少执行
【发布时间】:2014-02-27 22:56:57
【问题描述】:

假设c级整数j保存在寄存器$t1中,$s2保存名为total的c级整数,$s0保存整数数组vArray的基地址。

    addi $t1, $0, $0
LOOP:
    lw $s1, 0($s0)
    add $s2, $s2, $s1
    addi $s0, $s0, 4 
    addi $t1, $t1, 1
    slti $t2, $t1, 100
    bne $t2, $s0, LOOP

我的解决方案:

我想我已经弄清楚了C代码,应该是:

for (j = 0; j < 100; j++) {

    total = total + vArray[j];

}

然后问题问:重写循环以减少执行的MIPS指令的数量。

但是,我无法减少执行的 MIP 指令的数量。对我来说,我认为 MIPs 指令已经很基础了,我无法想出少于七个执行步骤的其他解决方案。

在阅读了递减的建议后,我想出了这个,可能有点笨拙的逻辑。

addi $t1, $zero, 404
LOOP: 
subi $t1, $t1, 4
add $s0, $s0, $t1
lw $t2, 0($s0)
add $s2, $s2, $t2
bne $t1, $zero, LOOP 

【问题讨论】:

  • 您的 C 代码在两个地方有误:您在 for 循环中使用 , 而不是 ; 并使用 i 而不是 j 作为索引。你能向我们展示一个适当的 C 等价物和编译器汇编输出吗?这可能是一个简单的优化级别问题。
  • 我很抱歉错别字。我把它固定在上面。我刚开始在这门课上学习 MIP,所以我还不确定在哪里可以看到汇编语言代码。
  • 由于它只是对数组求和,因此您可以向下计数而不是向上计数。这样你就不需要slti 指令了。

标签: c assembly mips


【解决方案1】:

如果您想要尽可能小的代码,我想可能是这样的:

       add $s2, $0, $0     ; initialize sum to 0
       addi $t1, $s0, $400 ; compute pointer limit
LOOP:  lw $s1, 0($s0)      ; load one element
       addi $s0, $s0, 4    ; point to next element
       add $s2, $s2, $s1   ; cumulate result (away from lw to skip delay slot)
       bne $t2, $t1, LOOP  ; loop until pointer reaches limit
       nop                 ; delay slot of the branch

基本上,您使用指针值作为循环退出条件,而不是在单独的寄存器中计算迭代次数。

如果你想利用延迟槽:

       add $s2, $0, $0     ; initialize sum to 0
       addi $t1, $s0, $400 ; compute pointer limit
LOOP:  lw $s1, 0($s0)      ; load one element
       addi $s0, $s0, 4    ; point to next element
       bne $t2, $t1, LOOP  ; loop until pointer reaches limit
       add $s2, $s2, $s1   ; cumulate result (in delay slot)

循环展开:

       add $s2, $0, $0     ; initialize sum to 0
       addi $t1, $s0, $400 ; compute pointer limit
LOOP:  lw $s1, 0($s0)      ; load first element
       addi $s0, $s0, 8    ; compute next block address
       add $s2, $s2, $s1   ; cumulate first element
       lw $s1, -4($s0)     ; load second element
       bne $t2, $t1, LOOP  ; loop until pointer reaches limit
       add $s2, $s2, $s1   ; cumulate second element

现在每个加载和累积需要 3 个周期,而上面的一步循环中需要 4 个周期。

进一步展开循环没有意义,因为您无法在少于 3 个指令周期(一个内存加载、一个延迟槽、一个累积)内执行加载和累积步骤。

【讨论】:

  • 非常感谢!我还没有进入延迟槽,你能简单解释一下延迟槽或指向一些网站吗?
【解决方案2】:

在最小化指令方面,这是我能做的最好的:

  addi $t1, $s0, 400
LOOP:
  lw $s1, 0($s0)
  add $s2, $s2, $s1
  addi $s0, $s0, 4
  bne $s0, $t1, LOOP

【讨论】:

  • 您的逻辑比我提出的解决方案(见上文)要清晰得多。谢谢。
【解决方案3】:

也循环展开。 IE。忘记整个循环增量的事情,只需执行 100 次添加和 100 次内存获取操作。

【讨论】:

  • OP 的目标似乎是最小的代码,而不是最快的。此外,加载延迟槽会掩盖循环执行时间,因此展开可能没有任何区别。
  • OP 明确指出“执行的 MIP 指令数”。这是最低限度。
  • 好吧,如果你计算延迟槽插入的 nop,它的指令周期并不比利用加载和跳转延迟的循环少。每次加载和累加你会写更少的指令,但汇编器会在你背后插入 nop。
【解决方案4】:

寄存器 $t1 实际上不需要增加或检查。它用于知道您何时执行了 100 次,但您也可以计算出 $s0 何时增加了 400。

【讨论】:

  • 如果您尝试最小化周期数,还有一些其他优化,例如分支延迟槽,尽管您已经说过最小化指令数。
猜你喜欢
  • 1970-01-01
  • 2013-05-31
  • 1970-01-01
  • 1970-01-01
  • 2012-03-20
  • 2021-01-29
  • 1970-01-01
  • 2021-09-17
  • 1970-01-01
相关资源
最近更新 更多