为什么这个Risc-V二元树检查器不能用?

问题描述 投票:0回答:1

我想写一个Risc-V树检查器:每棵树的节点都是由三个字组成的。

1)要么是0,要么是1

2)左侧节点的地址

3)右边节点的地址

我的程序应该探索树,并返回以1为第一个字的节点在树的深处有多深,这是代码。

.data
tree:   .word n01
n01:    .word 0, n02, n03
n02:    .word 0, n04, n05
n03:    .word 0, n06, n07
n04:    .word 0, 0, 0
n05:    .word 0, 0, 0
n06:    .word 1, 0, 0
n07:    .word 0, 0, 0
.text
    lw a0, tree
    jal altezza
    addi a0, a0, -1
    li a7, 1
    ecall
    li a7, 10
    ecall

altezza:
    bne a0, zero, altezza_ric  
    jalr zero, ra, 0    

altezza_ric:
    addi sp, sp, -12  
    lw t1, 0(a0)
    sw ra, 0(sp)    
    bne t1, zero, skip_numb

    sw a0, 4(sp)    
    lw a0, 4(a0)    
    jal altezza
    sw a0, 8(sp)    
    lw a0, 4(sp)    
    lw a0, 8(a0)    
    jal altezza

    lw t0, 8(sp)    
    bne a0, zero, scelta
    mv a0, t0
    bne a0, zero, scelta
    jal skip
scelta:
    ble a0,t0,skip_add
    mv a0, t0


skip_add:  
    addi a0, a0, 1  #ad a0 inremento 1
skip:   lw ra, 0(sp)
    addi sp, sp, 12 
    jalr zero, ra, 0    

skip_numb:
    add a0, zero, zero
    jal skip_add
assembly binary-tree riscv
1个回答
0
投票

试着在调试器中进行单步操作,看看每条指令是否有你想要的效果。

让你的初始测试用例尽可能的小,因为调试递归函数会让人很困惑。  所以,例如,只用一个节点来尝试;然后只用两个节点(例如,一个根节点,左;一个根节点,右)。

最终你会看到这样的情况。

lw a0, 4(sp)    <------- the result of this load is discarded
lw a0, 8(a0)    

在这里,第一个负载是没有意义的,因为... ... a0 它获得的值会(立即)被第二次加载覆盖。


    bne a0, zero, scelta
    jal skip
scelta:
    ble a0,t0,skip_add
    mv a0, t0
skip_add:

不要使用 jal 对于简单的分支,使用 j 而不是。  虽然在这里并无大碍,但它确实更新了 ra在一个简单的if-then-else的上下文中,你不希望出现这种情况。  如果你有一个叶子函数,它不保存 ra 中的堆栈,这样就不好了。

由于这个序列有一个条件分支,在一个无条件分支周围跳转,因此可以简化为取消无条件分支和一个标签(scelta:)如下:

    beq a0, zero, skip  <--- reverse the condition and branch to the other target
                        <--- eliminate/omit the unconditional branch and other label
    ble a0,t0,skip_add
    mv a0, t0
skip_add:
© www.soinside.com 2019 - 2024. All rights reserved.