RISC-V汇编寄存器置位计数循环终止问题求助
RISC-V汇编置位计数的循环终止问题修复
你的代码核心问题是没有循环终止条件——不管移位掩码x10怎么左移,func_b都会无条件跳回继续检查,哪怕x10溢出变成0后,还是会无限循环(因为x10为0时,x13=x9&x10也为0,依旧会进入func_b,左移x10还是0,死循环)。
下面给两种可行的修复方案:
方案1:修复原逐位检查逻辑
给循环加上明确的终止判断:当移位掩码x10左移到0时,说明所有位都检查完毕,直接结束循环。
修复后的代码:
addi x9, x0, 0xff00 # 待统计置位数量的目标数 addi x10, x0, 1 # 移位掩码,从最低位开始检查 addi x11, x0, 0 # 置位计数器,初始为0 addi x12, x0, 0 # 用于比较的0值 loop_start: and x13, x9, x10 # 检查当前掩码对应的位是否为1 bne x13, x12, count_bit # 该位为1,跳去计数 j check_terminate # 该位为0,直接检查是否终止循环 count_bit: addi x11, x11, 1 # 计数器加1 check_terminate: slli x10, x10, 1 # 掩码左移一位,检查下一位 bne x10, x0, loop_start # 掩码未溢出为0,继续循环 func_c: add x20, x0, x11 # 保存最终的置位计数
改动说明:
- 把原来分散的
func_a、func_b整合成逻辑更清晰的循环结构,避免冗余跳转 - 每次检查完一位后,先移位再判断掩码是否为0——RV32架构下x10左移32次后会溢出为0,此时所有位都已检查完毕,终止循环
方案2:用Brian Kernighan算法(更高效)
这个算法的核心是每次清除当前数的最低位1,直到数变为0,清除的次数就是置位的数量。相比逐位检查,它的循环次数等于置位的数量,效率更高。
代码实现:
addi x9, x0, 0xff00 # 待统计置位数量的目标数 addi x11, x0, 0 # 置位计数器,初始为0 addi x12, x0, 0 # 用于比较的0值 loop_start: beq x9, x0, func_c # 目标数已变为0,终止循环 addi x11, x11, 1 # 计数器加1 addi x14, x9, -1 # 计算x9-1,用于清除最低位1 and x9, x9, x14 # x9 = x9 & (x9-1),清除最低位的1 j loop_start func_c: add x20, x0, x11 # 保存最终的置位计数
逻辑说明:
- 以
0xff00(二进制16个1)为例,这个算法只会循环16次,比逐位检查的32次循环效率高一倍 - 每次
x9 & (x9-1)会精准清除当前数的最低位1,直到x9变为0,此时计数器的值就是置位的总数
内容的提问来源于stack exchange,提问作者Dev Yego
相关产品推荐
相关产品推荐

