Odd type behavior
When working with an MD simulation, I need to enforce periodic boundary conditions at the particle positions. The easiest way to use mod(particle position, box dimension)
. Since I work in 3D space, I created a 3D vector type:
immutable Vec3
x::Float32
y::Float32
z::Float32
end
And the 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:
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 just returned 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 the mod in the type constructor doesn't like it, 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 that prints intermediate products:
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, each with the same result. If someone could shed some light on this, I would be very grateful. Julia's version:Version 0.3.2 (2014-10-21 20:18 UTC)
source to share
What works and what doesn't
I think it might be a bug, maybe even an LLVM bug. I was able to reproduce your bug on version 0.3.0, but not on version 0.4. Like you, I also got the correct results by inserting a print statement in the middle.
Also, I found that 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 more complex
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 next
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)
In LLVM
The LLVM source also looks correct. The different parts of each Vec3 mod input argument are loaded using the arguments (fadd, frem, fadd), and then the results are saved as 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
Internal code error?
But native instructions do not look correct, XMM2 is moved to XMM0 , and later XMM0 is used as addss operand , but XMM2 does not 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
Update:
Introduced this issue for possible LLVM error.
source to share