function - function Power(x,y) in assembly ia32 max 32 bit
问题描述
i using IA32 assembly,
I would like to create a function which, given the two input numbers, rests the value of the power, the result must be maximum in 32 bits. The base is unsigned int base always positive while the exponent is int. so both negative and 0. thanks in advance
解决方案
结果也应该是整数吗? x^-n
is just ,对于除 之外1/x^n
的任何值都舍入为零。例如是。x
1
pow(16, -2)
1/256
对于整数返回值,只需检查正数n
或返回1
或0
。对于 FP 返回值,您可以使用绝对值的无符号实现,并有条件地取倒数。
对于较大的n
量级,您可能希望使用基于 FP exp/log 的实现(请参阅我对问题的评论,以及我如何自己编写幂函数?)而不是循环位实现。
对于具有无符号指数(或有符号正数)的纯整数,一个不错的无分支实现是可能的,使用通常的算法右移指数并在当前位被设置的情况下将结果相乘。(有关算法背后的数学和 Python 代码,请参见https://eli.thegreenplace.net/2009/03/21/efficient-integer-exponentiation-algorithms 。)
我们可以shr
对移出的位使用右移和 CMOV,并对剩余的值使用循环分支。
这个版本在 x86-64 System V 相同的寄存器中传递 args,但它可以在 32 位模式下进行组装。您当然可以将其调整为您喜欢的任何调用约定;它需要 4 个寄存器,因此您可能需要在 32 位调用约定中保存/恢复调用保留的 reg。
它类似于但比从 x86-64 C 编译器获得的 Python 实现的直接端口更好。(https://godbolt.org/z/L9Kb98 gcc / clang 用test sil,1
/cmov` 构造循环,与 shr 结果上的循环分支分开。)
;; untested
; integer power
; args in EDI,ESI (like the x86-64 System V calling convention)
; returns in EAX
; clobbers: EDX, EDI, ESI
ipown: ; (int a (EDI), unsigned n (ESI))
mov eax, 1 ; res = 1
test edi,edi
jz .zero_exponent
.loop:
mov edx, eax ; tmp = res
imul eax, edi ; res *= a (will be overwritten with old res if n&1 == 0)
imul edi, edi ; a*=a
shr esi, 1 ; n>>=1 setting ZF according to result, and CF= bit shifted out (old_n&1)
cmovnc eax, edx ; res = tmp if the bit was zero so we don't do res *= a this time
jnz .loop
.zero_exponent:
ret
在 Broadwell 或更高版本的 Intel CPU 或 AMD Ryzen 上,我们有 1 个周期 CMOV 和 3 个周期延迟imul
,这有望在每次迭代中运行 4 个周期(通过 EAX 的 imul -> cmov 依赖链)。
imul
在现代 x86 上完全流水线化(或至少在 AMD Bulldozer 系列上充分流水线化),但每个时钟的吞吐量仅为 1,因此imul
可能都在等待edi
准备就绪的两条指令之间存在潜在的资源冲突。但是通过 EDI 的 3 周期 dep 链应该领先于 4 周期 imul/cmov 链,因此在 animul eax,edi
和 animul edi,edi
都准备好启动的任何周期中,最旧的就绪优先调度应该做出正确的选择并启动imul eax,edi
.
请注意,mov edx,eax
不在关键路径上:它可以与imul
. 如果我这样做了tmp *= edi
,那mov
将是关键路径,并且会损害 CPU 的延迟,而无需对整数寄存器进行移动消除。
当然,最大循环跳数只有 32(如果设置了指数的高位),所以乱序执行可以看穿这个直到循环结束(并希望解决循环退出错误预测在乘法到达那里之前)。
循环中的指令很少(与其吞吐量相比),因此它应该能够与之前/之后的独立指令显着重叠。
预期延迟大约4 cycles *trip_count
为 = 4 * log2(n)
,即 4 * 指数中最高设置位的位置。
对于 FP 版本,x87 实际上可能对fcmov
. 否则,您可以使用移位和 SSE4blendvps
根据另一个寄存器的高位进行混合。 0.0
是加法恒等式,而不是乘法恒等式,因此与比较结果进行与运算不仅有效。
推荐阅读
- javascript - 如何在组中播放精灵动画?
- css - 更改新闻稿字段、边框和按钮大小
- c# - C# 无法将十六进制转换为可读字符串
- python-3.x - Matplotlib 箱线图与 groupby
- go - 如何使用“内部”导入运行核心库测试?
- c++ - 了解 C++ constexpr 性能
- javascript - 如何编辑数据表中的一行
- c - 如何在 Eclipse 中将库从子模块添加到项目
- python - Python Dataframe 条件 If 语句使用 pd.np.where 出错
- java - 错误 MVN 全新安装。未能发布模拟。除非您使用第三方模拟制造商,否则不应发生这种情况