Working with MD simulations, I need to enforce periodic boundary conditions on particle positions. The simplest way of which is using mod(particle position, box dimension). Since I'm working in 3D space, I made a 3D vector type:
immutable Vec3
x::Float32
y::Float32
z::Float32
end
And a mod function:
f1(a::Vec3, b::Vec3) = Vec3(mod(a.x, b.x), mod(a.y, b.y), mod(a.z, b.z))
However, when using this, it fails horribly:
julia> a = Vec3(11,-2,5)
Vec3(11.0f0,-2.0f0,5.0f0)
julia> b = Vec3(10,10,10)
Vec3(10.0f0,10.0f0,10.0f0)
julia> f1(a,b)
Vec3(5.0f0,10.0f0,NaN32)
If I simply return a tuple, it works fine:
f2(a::Vec3, b::Vec3) = mod(a.x,b.x), mod(a.y,b.y), mod(a.z,b.z)
julia> f2(a,b)
(1.0f0,8.0f0,5.0f0)
As a test to see if it was not liking the mod inside the type constructor, I tried a more verbose method:
function f3(a::Vec3, b::Vec3)
x = mod(a.x,b.x)
y = mod(a.y,b.y)
z = mod(a.z,b.z)
return Vec3(x,y,z)
end
julia> f3(a,b)
Vec3(5.0f0,10.0f0,NaN32)
And then, a version printing the intermediates:
function f4(a::Vec3, b::Vec3)
x = mod(a.x,b.x)
y = mod(a.y,b.y)
z = mod(a.z,b.z)
println(x, " ", y, " ", z)
return Vec3(x,y,z)
end
julia> f4(a,b)
1.0 8.0 5.0
Vec3(1.0f0,8.0f0,5.0f0)
Which for some reason now works. I've tried this on multiple computers now, each with the same result. If someone could shed some light on this, I would be most thankful. Julia version is: Version 0.3.2 (2014-10-21 20:18 UTC)
I think this may be a bug, perhaps even an LLVM bug. I was able to reproduce your error on version 0.3.0, but not on version 0.4. Like you, I also obtained correct results by inserting a print statement in the middle.
Furthermore, I found that both the simpler
f1(a::Vec3, b::Vec3) = Vec3(mod(a.x,b.x),mod(a.y,b.y),1)
julia> f1(a,b)
Vec3(1.0f0,8.0f0,1.0f0)
AND the more complicated
julia> f1(a::Vec3, b::Vec3) = Vec3(mod(a.x,b.x),mod(a.y,b.y),mod(a.z,b.z) + 1)
f1 (generic function with 1 method)
julia> f1(a,b)
Vec3(1.0f0,8.0f0,6.0f0)
both work, but the following one doesn't
julia> f1(a::Vec3, b::Vec3) = Vec3(mod(a.x,b.x),mod(a.y,b.y),mod(a.z,b.z))
f1 (generic function with 1 method)
julia> f1(a,b)
Vec3(5.0f0,10.0f0,NaN32)
The LLVM source also looks correct. The various parts of each of the input Vec3 arguments are loaded mod is taken of the arguments using (fadd,frem,fadd) and then the results are stored in the result.
julia> code_llvm(f1,(Vec3,Vec3))
define %Vec3 @"julia_f1;20242"(%Vec3, %Vec3) {
top:
%2 = extractvalue %Vec3 %1, 0, !dbg !1733
%3 = extractvalue %Vec3 %1, 1, !dbg !1733
%4 = extractvalue %Vec3 %1, 2, !dbg !1733
%5 = extractvalue %Vec3 %0, 0, !dbg !1733
%6 = frem float %5, %2, !dbg !1733
%7 = fadd float %2, %6, !dbg !1733
%8 = frem float %7, %2, !dbg !1733
%9 = insertvalue %Vec3 undef, float %8, 0, !dbg !1733
%10 = extractvalue %Vec3 %0, 1, !dbg !1733
%11 = frem float %10, %3, !dbg !1733
%12 = fadd float %3, %11, !dbg !1733
%13 = frem float %12, %3, !dbg !1733
%14 = insertvalue %Vec3 %9, float %13, 1, !dbg !1733
%15 = extractvalue %Vec3 %0, 2, !dbg !1733
%16 = frem float %15, %4, !dbg !1733
%17 = fadd float %4, %16, !dbg !1733
%18 = frem float %17, %4, !dbg !1733
%19 = insertvalue %Vec3 %14, float %18, 2, !dbg !1733, !julia_type !1734
ret %Vec3 %19, !dbg !1733
But the native instructions look incorrect, XMM2 is moved to XMM0, and later XMM0 is used as an operand to addss, but XMM2 doesn't appear to be initialized.
julia> code_native(f1,(Vec3,Vec3))
.section __TEXT,__text,regular,pure_instructions
Filename: none
Source line: 1
push RBP
mov RBP, RSP
sub RSP, 16
movss DWORD PTR [RBP - 4], XMM5
Source line: 1
movaps XMM0, XMM2
movaps XMM1, XMM5
movabs RAX, 140735600044048
call RAX
movss XMM1, DWORD PTR [RBP - 4]
addss XMM0, XMM1
movabs RAX, 140735600044048
add RSP, 16
pop RBP
jmp RAX
Submitted this issue for possible LLVM error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With