【问题标题】:What is the simplest way to iterate through a mips assembly array? [duplicate]迭代 mips 程序集数组的最简单方法是什么? [复制]
【发布时间】:2021-03-27 11:52:45
【问题描述】:

我想以最干净的方式复制它

在python中

A = [0,0,0,0,0]
i = 0
while(i != 5):
    A[i] = 10
    i++

也就是说,我想遍历一个数组并将其所有值设置为 [10,10,10,10,10]

这就是我在 mips 汇编中所做的

.data 
    array:  .word   0:5
    
.text
    
main:
    li $t1, 0       # i = 0
    la $t9, array       # $t9 = addr(array)
    li $t8, 10      # $t8 = 10
    

    
start_loop:
    beq $t1, 5, end_loop # if i == 5 jump to end loop
    
    sll $t2, $t1, 2     # $t2 = i x 4
    add $t2, $t9, $t2   # $t3 = addr(array[i])
    sw $t8, 0($t2)      # array[i] = $t8
    addi $t1, $t1, 1    # i = i + 1
    j start_loop

end_loop:

    li $v0, 10    # end program
    syscall

我觉得我使用了很多寄存器,这不是最干净的方法。任何帮助表示赞赏

(还要确保使用循环,我可以在没有循环的情况下对其进行硬编码,但我只是想找出使用​​循环的其他方法)

【问题讨论】:

标签: assembly mips


【解决方案1】:
.data 
    array:  .word   0:5
    array_end:
.text
    
main:
    la     $t2, array
    addiu  $t1, $t2, 20   # one-past-end address for loop condition
                 # or  la $t1, array_end  to avoid hard-coding length
    li     $v0, 10

start_loop:                  # do{
    sw     $v0, 0($t2)          # array[i] = $t8
    addiu  $t2,$t2,4            #increment pointer after
   beq $t1, $t2, start_loop  # }while(p != endp);

#end_loop:
    #li $v0, 10         # exit call number happens to be the same value we wanted to store
    syscall             # exit

改动(在彼得的帮助下)

所以要做的第一件事就是删除 i 变量。相反,我们可以将$t2 的地址(指向数组的指针)与我们在循环外设置的结束指针($t1)进行比较,这将告诉我们完成了。如果没有,则分支到 start_loop。

指针增量而不是每次都重做索引在 MIPS 等没有索引寻址模式的机器上特别好。

在循环底部使用条件分支循环意味着您不需要j 指令,并且对于所有(?)ISA(例如Why are loops always compiled into "do...while" style (tail jump)?)的汇编语言都是惯用的。当您知道循环肯定会至少运行一次时,这尤其好,因此您不需要循环前面的分支来跳过它。

【讨论】:

  • 这是一个改进,但循环内不需要i,因此您可以通过指针递增来保存循环中的指令。 (bne $t1, $t2, start_loop 在底部作为循环分支。)请参阅此问题的链接副本以获得更好的示例。请注意,beq $t1, 5 需要一个内部临时寄存器来加载5,因此实际上效率很低。如果你打算使用单独的计数器寄存器,你会在底部做addiu $t1, $t1, -1 / bnez $t1, start_loop
  • 是的,这是正确的想法,但您仍然需要将t2 初始化为起始指针。所以你不妨做la $t2, array/addiu $t1, $t2, 20。 (或者在数组末尾贴一个标签和la $t1, array_end,这样你就不必在任何地方硬编码大小,即使MARS有限的内置汇编器不允许你做.equ arrlen, . - array之类的事情让它为你计算一个长度。)
  • 另外,有趣的优化:你可以使用$v0 来保持10 所以你需要它保持10 后退出系统调用。
  • @PeterCordes 再次感谢您。赞赏。
  • 我编辑了你的 asm 风格,例如删除不添加任何内容的 cmets,并整理缩进。还添加了更多解释。当然,您可以随意将其中的任何内容编辑成您自己的话;这是你的答案,这只是我的建议。
【解决方案2】:
  .data
  array: .word 0:5

  .text
  main:
  li $t1, 0     #initialize i = 0
  la $t2, array #load address of array[0]
  li $t3, 10    #save 10 in a register 

  loop:
  beq $t1, 5, end       #if i == 5, end
  sw $t3, ($t2)     #array[i] = 10

  add $t2, $t2, 4   #increment array address pointer by 4
  add $t1, $t1, 1       #i = i + 1

  j loop


  end:
  li $v0, 10
  syscall

【讨论】:

    猜你喜欢
    • 2022-01-21
    • 2019-04-18
    • 2019-08-17
    • 1970-01-01
    • 2017-04-05
    • 1970-01-01
    • 2017-03-28
    • 2016-09-04
    • 1970-01-01
    相关资源
    最近更新 更多