我想更好地理解为什么两个非常相似的代码片段在我的计算机上表现得截然不同.这些测试是在Ryzen处理器上使用gcc-trunk和Julia 0.7-alpha(LLVM 6.0).gcc-8看似相似,而Julia 0.6.3(LLVM 3.9)略慢于v0.7.
我编写了生成函数(想想C++模板),为矩阵运算生成展开代码,以及一个简单的转换器,可以将简单的代码转换为Fortran.
对于8x8矩阵乘法,这是Fortran代码的样子:
module mul8mod
implicit none
contains
subroutine mul8x8(A, B, C)
real(8), dimension(64), intent(in) :: A, B
real(8), dimension(64), intent(out) :: C
C(1) = A(1) * B(1) + A(9) * B(2) + A(17) * B(3) + A(25) * B(4)
C(1) = C(1) + A(33) * B(5) + A(41) * B(6) + A(49) * B(7) + A(57) * B(8)
C(2) = A(2) * B(1) + A(10) * B(2) + A(18) * B(3) + A(26) * B(4) …Run Code Online (Sandbox Code Playgroud) 背景(可能有更好的方法可以做到这一点):我正在开发一个Julia库,在其中我可以手动管理内存。我mmap是一个大块,然后通常将其视为堆栈:函数将指针作为参数接收,如果分配了对象,则它们将向被调用者返回递增的指针。如果被调用方本身完全返回了指针,则该被调用方本身可能不会增加该指针,而只是返回它收到的原始指针。
每当函数返回时,就我的库而言,超出指针当前位置的任何内容都是垃圾。我希望LLVM意识到这一点,以便它可以优化所有不必要的存储。
这是一个演示该问题的测试用例:取两个长度为16的向量的点积。首先,一些初步的负载(这些是我的库,位于GitHub上:SIMDPirates,PaddedMatrices):
using SIMDPirates, PaddedMatrices
using SIMDPirates: lifetime_start, lifetime_end
b = @Mutable rand(16);
c = @Mutable rand(16);
a = FixedSizeVector{16,Float64}(undef);
b' * c # dot product
# 3.9704768664758925
Run Code Online (Sandbox Code Playgroud)
当然,如果我们手工编写一个点产品,我们将永远不会包括商店,但是当您尝试为任意模型生成代码时,要做起来就困难得多。因此,我们将编写一个存储在指针中的坏点积:
@inline function storedot!(ptr, b, c)
ptrb = pointer(b)
ptrc = pointer(c)
ptra = ptr
for _ ? 1:4
vb = vload(Vec{4,Float64}, ptrb)
vc = vload(Vec{4,Float64}, ptrc)
vstore!(ptra, vmul(vb, vc))
ptra += 32
ptrb += 32
ptrc += 32
end
ptra = ptr
out = …Run Code Online (Sandbox Code Playgroud)