最佳情况8个循环,最坏情况12个循环
由于问题尚不清楚,因此我将其基于“常春藤桥”延迟。
这里的方法是将bsr
(位反向扫描)指令用作穷人的log2()。结果用作跳转表的索引,该跳转表包含位0到42的条目。我假设假设隐式需要对64位数据进行操作,那么使用该bsr
指令就可以了。
在最佳情况下,跳转表条目可以将bsr
结果直接映射到幅度。例如,对于32-63范围内的输入,bsr
结果将为5,其映射为1的大小。在这种情况下,指令路径为:
Instruction Latency
bsrq 3
jmp 2
movl 1
jmp 2
total 8
在最坏的情况下,输入bsr
结果将映射到两个可能的幅度,因此,跳转表项会另外cmp
检查输入是否大于10 n。例如,对于64-127范围内的输入,bsr
结果将为6。然后,相应的跳转表条目将检查输入> 100并相应地设置输出幅度。
除最坏情况的路径外,我们还有一条附加的mov指令来加载64位立即数以供在中使用cmp
,因此最坏情况的指令路径为:
Instruction Latency
bsrq 3
jmp 2
movabsq 1
cmpq 1
ja 2
movl 1
jmp 2
total 12
这是代码:
/* Input is loaded in %rdi */
bsrq %rdi, %rax
jmp *jumptable(,%rax,8)
.m0:
movl $0, %ecx
jmp .end
.m0_1:
cmpq $9, %rdi
ja .m1
movl $0, %ecx
jmp .end
.m1:
movl $1, %ecx
jmp .end
.m1_2:
cmpq $99, %rdi
ja .m2
movl $1, %ecx
jmp .end
.m2:
movl $2, %ecx
jmp .end
.m2_3:
cmpq $999, %rdi
ja .m3
movl $2, %ecx
jmp .end
.m3:
movl $3, %ecx
jmp .end
.m3_4:
cmpq $9999, %rdi
ja .m4
movl $3, %ecx
jmp .end
.m4:
movl $4, %ecx
jmp .end
.m4_5:
cmpq $99999, %rdi
ja .m5
movl $4, %ecx
jmp .end
.m5:
movl $5, %ecx
jmp .end
.m5_6:
cmpq $999999, %rdi
ja .m6
movl $5, %ecx
jmp .end
.m6:
movl $6, %ecx
jmp .end
.m6_7:
cmpq $9999999, %rdi
ja .m7
movl $6, %ecx
jmp .end
.m7:
movl $7, %ecx
jmp .end
.m7_8:
cmpq $99999999, %rdi
ja .m8
movl $7, %ecx
jmp .end
.m8:
movl $8, %ecx
jmp .end
.m8_9:
cmpq $999999999, %rdi
ja .m9
movl $8, %ecx
jmp .end
.m9:
movl $9, %ecx
jmp .end
.m9_10:
movabsq $9999999999, %rax
cmpq %rax, %rdi
ja .m10
movl $9, %ecx
jmp .end
.m10:
movl $10, %ecx
jmp .end
.m10_11:
movabsq $99999999999, %rax
cmpq %rax, %rdi
ja .m11
movl $10, %ecx
jmp .end
.m11:
movl $11, %ecx
jmp .end
.m11_12:
movabsq $999999999999, %rax
cmpq %rax, %rdi
ja .m12
movl $11, %ecx
jmp .end
.m12:
movl $12, %ecx
jmp .end
jumptable:
.quad .m0
.quad .m0
.quad .m0
.quad .m0_1
.quad .m1
.quad .m1
.quad .m1_2
.quad .m2
.quad .m2
.quad .m2_3
.quad .m3
.quad .m3
.quad .m3
.quad .m3_4
.quad .m4
.quad .m4
.quad .m4_5
.quad .m5
.quad .m5
.quad .m5_6
.quad .m6
.quad .m6
.quad .m6
.quad .m6_7
.quad .m7
.quad .m7
.quad .m7_8
.quad .m8
.quad .m8
.quad .m8_9
.quad .m9
.quad .m9
.quad .m9
.quad .m9_10
.quad .m10
.quad .m10
.quad .m10_11
.quad .m11
.quad .m11
.quad .m11_12
.quad .m12
.quad .m12
.quad .m12
.end:
/* output is given in %ecx */
这主要是由gcc汇编程序输出生成的,用于我编写的概念验证C代码。请注意,C代码使用可计算的goto来实现跳转表。它还使用__builtin_clzll()
gcc内置函数,该函数可编译为bsr
指令(加上xor
)。
在达到这一目的之前,我考虑了几种解决方案:
FYL2X
计算自然对数,然后FMUL
通过必要的常数。如果这是一次[tag:instruction:golf]竞赛,那么大概可以赢得比赛。但是FYL2X
对于常春藤桥,延迟时间为90-106。
硬编码的二进制搜索。这实际上可能具有竞争力-我将其留给其他人实施:)。
完成结果查询表。我敢肯定,这在理论上是最快的,但是如果摩尔定律继续保持下去,可能需要几年才能使用1TB的查找表-尚不实用。