【问题标题】:Converting C array operations to Assembly将 C 数组操作转换为汇编
【发布时间】:2017-01-08 17:16:49
【问题描述】:

我正在努力尝试将a[i+1] = a[i-1] + b[4] 转换为程序集。其中$s0a的地址,$s1b的地址,$s2是变量i。教授提到它可以分6个步骤完成。

我有:

addi $t0, $s2, 4 #i + 1

addi $t1, $s2, -4 #i - 1

lw $t2, $t1($s0) #load a[i-1] - I know this is wrong

lw $t3, 16($s1) #load b[4]

add $t4, $t2, $t3 #add a[i-1] + b[4]

sw $t4, $t0($s0) #save to a[i+1] - I know this is wrong

我知道哪里出错了,我知道我不能立即使用寄存器,但我不确定如何解决这个问题。我也可能做错了,感谢任何帮助。

【问题讨论】:

  • 如果将 I 添加到 (addi %t0, $s0, $s2) 然后使用 +/-4 立即偏移量呢?
  • 您是否尝试将i添加到a,从a - 1加载,从b + 4添加,并存储到a + 1

标签: assembly mips


【解决方案1】:

下面是一些我相信会起作用的带注释的代码:

    .text

    .globl  main
# main -- main program
#
# a[i + 1] = a[i - 1] + b[4]
#
# arguments:
#   s0 -- address of a
#   s1 -- address of b
#   s2 -- i
#
# registers:
#   t0 -- address of a[i]
#   t1 -- value of b[4]
#   t2 -- i << 2 (i.e. a byte offset)
#   t3 -- value of a[i - 1]
#   t4 -- a[i - 1] + b[4]
main:
    sll     $t2,$s2,2               # get i << 2
    add     $t0,$s0,$t2             # get &a[i]

    lw      $t3,-4($t0)             # get a[i - 1]
    lw      $t1,16($s1)             # get b[4]

    add     $t4,$t3,$t1             # sum them
    sw      $t4,4($t0)              # a[i + 1] = sum

这非常接近可以使用的 only 序列。 lw 指令的顺序可以颠倒,否则,除了使用不同的寄存器来保存不同的值之外,指令必须与所示相同。

为了清晰,每个中间术语/步骤都有自己的t 寄存器。但是,如果重新分配/重用寄存器,我们可以减少使用的寄存器数量。例如,在前两条指令中,我们可以将$t2 替换为$t0,因为之后我们不再使用$t2

优化编译器可以/会做到这一点。我们最终只需要$t0-$t2 而不是$t0-$t4

    .text

    .globl  main
# main -- main program
#
# a[i + 1] = a[i - 1] + b[4]
#
# arguments:
#   s0 -- address of a
#   s1 -- address of b
#   s2 -- i
#
# registers:
#   t0 -- i << 2
#         address of a[i]
#   t1 -- value of b[4]
#   t2 -- value of a[i - 1]
#         sum of a[i - 1] + b[4]
main:
    sll     $t0,$s2,2               # get i << 2
    add     $t0,$s0,$t0             # get &a[i]

    lw      $t2,-4($t0)             # get a[i - 1]
    lw      $t1,16($s1)             # get b[4]

    add     $t2,$t2,$t1             # sum them
    sw      $t2,4($t0)              # a[i + 1] = sum

如果代码是函数的一部分,我们可以使用 $v0, $v1, $a0 作为临时寄存器,因为如果函数愿意,可以使用 $v0-$v1$a0-$a3 作为内部临时寄存器。


更新:

cmets 绝对可以帮助我了解每条指令期间发生的情况

良好的编程风格 [因此理解] 有很多 cmets。正确的类型。这对于 asm 来说尤其很重要,因为在 C 中,像 number_of_users 这样的变量有点描述性。但是,$t0 不是。

我添加的 cmets 是我为自己编写的任何 asm 代码所做的。而且,我写 asm 已经有几十年了。

此外,“优化”版本还有一个目的:简化。通过释放$t3-$t4,它们可以用来存放其他东西。在更复杂的函数中,这可以区分简单易懂的函数和难以理解和维护的不必要的复杂函数。

有关这方面的更多信息,以及如何写好 asm 的提示,根据我自己的经验,请参阅我的回答:MIPS linked list

教授不是最擅长传递信息

在课堂环境中只能传达这么多。它可以涵盖基础知识。而且,课程作业可以帮助您学习给定语言的基础知识。而且,IMO,教授们从来都不擅长很好地评论代码[够了;-)]。

当我[在不同的架构上]学习 asm 时,除了课程作业外,我还能够在 100% 用 asm 编写的多用户分时操作系统上作为付费程序员工作。它的评论风格与上述相同。

IMO,最好的学习方法之一是分析“专家”代码。问一个问题:“他们为什么以那种方式这样做?”。这就是我所做的,我学到了很多东西。直到今天,我 [仍然] 将这种经历归功于此。

【讨论】:

  • 感谢您的回复和回答。 cmets 绝对可以帮助我了解每条指令期间发生的情况 - 教授并不是最擅长传递信息。
【解决方案2】:
temp0 = $s0 + $s2
temp2 = load -4(temp0)
temp3 = load 16($s1)
temp1 = temp2 + temp3
store +4(temp0) = temp1

【讨论】:

  • 如果我正确阅读第一部分,是不是说# $t0 = a[i],对吗?
  • 是的,获取 a[i] 的地址,然后您可以从该权利中抵消正负 4,以说明 a[i-1] 和 a[i+1] 两者都有[i] 作为公共变量偏移量(基于 i),然后是从那里开始的固定偏移量。
猜你喜欢
  • 2021-04-23
  • 2011-12-07
  • 2014-06-13
  • 2011-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-03
相关资源
最近更新 更多