我正在阅读有关ALU设计和Booth's algorithm的信息,它们用于优化二进制乘法。令我好奇的是,像gcc这样的编译器将如何优化乘法,因为乘法运算的速度不如ARM 32bit这样的移位快。这是尝试将变量乘以0xaaa
(这是Booth算法的最坏情况)时获得的ASM:
mov r2, r3 // r3 is an arbitrary variable
lsl r2, r2, #1
add r2, r2, r3
lsl r3, r2, #3
sub r3, r3, r2
lsl r2, r3, #6
add r3, r3, r2
lsl r3, r3, #1
我似乎无法掌握产生以下输出的任何模式或规则。我想看一下gcc的源代码,但我不知道在哪里查找。有人可以阐明什么是算法,以及如何将其推广到任何乘数?
答案 0 :(得分:3)
您发布的程序集不是广义乘数-编译器已离线执行了一些算法,并对固定f(X) = X * 0xaaa
计算所需的常数和算术运算进行了硬编码。
mov r2, r3 // r2 = X, r3 = X
lsl r2, r2, #1 // r2 = 2 * X
add r2, r2, r3 // r2 = 2X + X = 3X
lsl r3, r2, #3 // r3 = 8 * 3X = 24X
sub r3, r3, r2 // r3 = 24X - 3X = 21X
lsl r2, r3, #6 // r2 = 64 * 21X = 1344X
add r3, r3, r2 // r3 = 21X + 1344X = 1365X
lsl r3, r3, #1 // r3 = 2 * 1365 = 2730X = 0xAAA * X
在这种情况下,编译器不需要使用通用的乘法算法,例如Booth的算法。它知道它要达到的目标值,因此它只是预先确定通过0xAAA
使用移位,加法和减法来生成恒定缩放的最佳方法。
一般的问题是“单常数乘法”问题-在线有论文(针对任意位数的最佳解决方案是“硬”问题,因此有很多研究论文)。
答案 1 :(得分:1)
基本乘法,并非您发现的所有内容都将使用某人将其名字放在上面的算法。
十进制
33 * 12
33
* 12
=====
66 ((33*2)<<0)
+33 ((33*1)<<1)
========
base 2具有第二个操作数可以包含零或一的特征
0b110 * 0b101
110
* 101
=========
110 ((110*1)<<0)
000 ((110*0)<<1)
+ 110 ((110*1)<<2)
===========
重要的是非零位。所以乘以五就是
x * 5 =(x * 4)+(x * 1)=(x << 2)+ x =((x + x)<< 1)+ x =((x << 1)<< 1)+ x
x * 10只是再左移一次。 x * 10 =(x * 8)+(x * 2)=((x + x)<< 1)+ x)<< 1
依此类推,您可以玩游戏,但是您希望针对目标架构进行优化。
0xAAA =(0x5 << 9)+(0x5 << 5)+(0x5 << 1)或(1 << 11)+(1 << 9)+(1 << 7)+(1 < <5)+(1 << 3)+(1 << 1)
从那里进行优化的各种方法。