x86_64下保留零/非零状态将64位寄存器转为32位的最优方法
可选优化方案及对比
你提出的popcntq方案已经是代码体积最小的最优解之一,还有两类针对不同优化目标的更优方案可选:
方案1:最低延迟(基础指令集,无扩展依赖)
适用场景:优先追求执行速度,可接受稍大的代码体积和临时寄存器占用
# 输入为rax,输出结果在eax movq %rax, %rcx shrq $32, %rcx orl %ecx, %eax
正确性验证:将rax的高32位移到rcx的低32位,与rax原生低32位做或运算,只要原rax任意一位为1,eax就会非零,完全匹配需求。
性能参数:主流Intel平台下延迟2周期(movq支持寄存器消除,0延迟;shrq 1周期;orl 1周期),吞吐量每周期可执行2组以上,代码总大小9字节。
方案2:最高兼容性(全x86-64平台支持)
适用场景:需要兼容不支持POPCNT的老旧处理器,不需要任何扩展指令集
# 输入为rax,输出结果在eax testq %rax, %rax setnz %al movzbl %al, %eax
正确性验证:testq判断rax是否为零,通过ZF标志位导出结果到8位寄存器al,再零扩展到32位eax,最终eax为0对应原rax为0,为1对应原rax非零。
性能参数:主流Intel平台下延迟2-3周期,代码总大小9字节。
原方案补充说明
你使用的popcntq方案依然是最小代码体积的最优选择:单条指令5字节,不需要额外寄存器,只要目标平台支持POPCNT扩展(2011年之后发布的Intel/AMD处理器均默认支持,对应x86-64 v2及以上规范)就可以正常使用。
注意你提到的直接读取eax的问题确实存在:当rax的高32位非零、低32位全零时(比如你举例的2^61),eax为0但原rax非零,会出现逻辑错误,不可使用。
内容的提问来源于stack exchange,提问作者Noah
相关产品推荐
相关产品推荐

