RV64汇编find_smallest函数错误排查:无法正确返回数组最小元素地址
RV64汇编函数find_smallest问题排查
需求说明
需在find_smallest.s中实现RV64汇编函数find_smallest:
- 输入:数组起始地址
begin_address、结束地址end_address(end_address为有效元素后的首个地址) - 输出:数组中最小64位元素的首次出现地址
我编写的汇编代码
.global find_smallest .text # find_smallest(begin_address, end_address) -> address_of_smallest find_smallest: bge a0, a1, 4f # 如果a0 == a1(数组为空),退出 ld t0, 0(a0) # 当前最小地址对应的值 addi t1, a0, 0 # 存储当前最小元素的地址 li t4, 1 # 索引值 #addi t5, a1, -8 1: addi t4, t4, 1 bge t1, a1, 4f slli t2, t4, 3 add t2, a0, t2 # t2现在是元素地址 bge t2, a1, 4f ld t3, 0(t2) # t3是该地址中的值 blt t3, t0, 3f 2: j 1b 3: mv t0, t3 mv t1, t2 j 1b 4: mv a0, t1 ret
测试失败输出对比
提交rv64-selection-sort步骤1进行评分 步骤1解决方案失败 报告卡:解析单元测试结果出错:第104行XML语法错误:非法字符编码U+001B $ make grade riscv64-alpine-linux-musl-as -g --warn --fatal-warnings -march=rv64im start.s -o start.o riscv64-alpine-linux-musl-as -g --warn --fatal-warnings -march=rv64im find_smallest.s -o find_smallest.o riscv64-alpine-linux-musl-as -g --warn --fatal-warnings -march=rv64im print.s -o print.o riscv64-alpine-linux-musl-ld --fatal-warnings start.o find_smallest.o print.o rm -f test_details.xml inputs/*.actual python3 lib/grader $ python3 lib/rv64sim -m run < inputs/test.input !!! 输出不正确: $ icdiff inputs/test.actual inputs/test.expected inputs/test.actual inputs/test.expected 查找11370到11410之间最小元素的地址 ===> 11370 查找11378到11410之间最小元素的地址 ===> 11380 查找11380到11410之间最小元素的地址 ===> 11380 查找11388到11428之间最小元素的地址 查找11388到11410之间最小元素的地址 ===> 11388 查找11390到11428之间最小元素的地址 ===> 113b0 查找11398到11428之间最小元素的地址 ===> 11398 ===> 11398 查找11390到11410之间最小元素的地址 ===> 11398 查找11398到11410之间最小元素的地址 ===> 11398 查找113a0到11428之间最小元素的地址 查找113a0到11410之间最小元素的地址 ===> 113b0 ===> 113d8 查找113a8到11428之间最小元素的地址 查找113a8到11410之间最小元素的地址 ===> 113d8 查找113b0到11410之间最小元素的地址 ===> 113d8 查找113b8到11410之间最小元素的地址 ===> 113d8 查找113c0到11410之间最小元素的地址 ===> 113d8 查找113c8到11410之间最小元素的地址 ===> 113d8 查找113d0到11410之间最小元素的地址 ===> 113d8 查找113d8到11410之间最小元素的地址 ===> 113d8 查找113e0到11410之间最小元素的地址 ===> 113f0 ===> 113f0 查找113b0到11428之间最小元素的地址 ===> 113b0 查找113b8到11428之间最小元素的地址 查找113e8到11410之间最小元素的地址 ===> 113f0 ===> 113f0 查找113c0到11428之间最小元素的地址 查找113f0到11410之间最小元素的地址 ===> 113f0 ===> 113f0 查找113c8到11428之间最小元素的地址 查找113f8到11410之间最小元素的地址 ===> 113f0 ===> 11400 查找113d0到11428之间最小元素的地址 查找11400到11410之间最小元素的地址 ===> 113f0 ===> 11400 查找113d8到11428之间最小元素的地址 查找11408到11410之间最小元素的地址 ===> 113f0 查找113e0到11428之间最小元素的地址 ===> 113f0 查找113e8到11428之间最小元素的地址 ===> 11408 ===> 11408 查找113f0到11428之间最小元素的地址 ===> 113f0 查找113f8到11428之间最小元素的地址 ===> 11408 查找11400到11428之间最小元素的地址 ===> 11418 查找11408到11428之间最小元素的地址 ===> 11408 查找11410到11428之间最小元素的地址 ===> 11420 查找11418到11428之间最小元素的地址 ===> 11418 查找11420到11428之间最小元素的地址 ===> 11420 0/1测试通过,耗时0.72秒
代码问题分析
- 索引逻辑错误:初始
t4设为1,第一次循环直接addi t4, t4, 1变成2,跳过了数组的第二个元素(索引1对应的地址),导致部分元素未被遍历。 - 终止条件错误:用当前最小元素地址
t1判断bge t1, a1, 4f完全不合理,t1是最小元素的地址,和结束地址a1没有直接的遍历终止关系,会导致提前退出或者越界。 - 地址计算冗余且易出错:通过索引左移3位(乘8)计算地址的方式,不如直接用地址递增的方式可靠,容易出现索引和地址不匹配的问题。
修正后的代码
.global find_smallest .text # find_smallest(begin_address, end_address) -> address_of_smallest find_smallest: bge a0, a1, 4f # 空数组直接返回起始地址 ld t0, 0(a0) # 初始化当前最小值为第一个元素的值 mv t1, a0 # 初始化当前最小值地址为起始地址 addi t2, a0, 8 # 从第二个元素开始遍历 1: bge t2, a1, 4f # 遍历到结束地址则退出循环 ld t3, 0(t2) # 读取当前遍历元素的值 blt t3, t0, 3f # 如果当前元素更小,跳转到更新逻辑 addi t2, t2, 8 # 否则,地址加8,继续下一个元素 j 1b 3: mv t0, t3 # 更新当前最小值 mv t1, t2 # 更新当前最小值地址 addi t2, t2, 8 # 地址加8,继续下一个元素 j 1b 4: mv a0, t1 # 返回最小元素的首次出现地址 ret
修正说明
- 直接用地址遍历:从起始地址+8开始,每次地址加8,避免索引计算的错误,确保遍历所有有效元素。
- 正确的终止条件:判断当前遍历地址
t2是否大于等于结束地址a1,符合数组的边界定义。 - 简化逻辑:去掉冗余的索引变量,减少出错点,代码更易读。
内容的提问来源于stack exchange,提问作者Aaron Valentine
相关产品推荐
相关产品推荐

