{"action":"created","issue":{"url":"https://api.github.com/repos/JuliaLang/julia/issues/13104","labels_url":"https://api.github.com/repos/JuliaLang/julia/issues/13104/labels{/name}","comments_url":"https://api.github.com/repos/JuliaLang/julia/issues/13104/comments","events_url":"https://api.github.com/repos/JuliaLang/julia/issues/13104/events","html_url":"https://github.com/JuliaLang/julia/issues/13104","id":106221741,"number":13104,"title":"Abstraction penalty: Wrapper types lead to much less efficient code","user":{"login":"eschnett","id":213514,"avatar_url":"https://avatars.githubusercontent.com/u/213514?v=3","gravatar_id":"","url":"https://api.github.com/users/eschnett","html_url":"https://github.com/eschnett","followers_url":"https://api.github.com/users/eschnett/followers","following_url":"https://api.github.com/users/eschnett/following{/other_user}","gists_url":"https://api.github.com/users/eschnett/gists{/gist_id}","starred_url":"https://api.github.com/users/eschnett/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eschnett/subscriptions","organizations_url":"https://api.github.com/users/eschnett/orgs","repos_url":"https://api.github.com/users/eschnett/repos","events_url":"https://api.github.com/users/eschnett/events{/privacy}","received_events_url":"https://api.github.com/users/eschnett/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/JuliaLang/julia/labels/codegen","name":"codegen","color":"d4c5f9"},{"url":"https://api.github.com/repos/JuliaLang/julia/labels/performance","name":"performance","color":"d7e102"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":7,"created_at":"2015-09-13T14:57:17Z","updated_at":"2015-09-14T16:23:49Z","closed_at":null,"body":"(This is Julia release-0.4 with LLVM 3.6.2; LLVM 3.3 is similar but slightly worse.)\r\n\r\nI find that introducing a trivial wrapper type around `Float64` leads to much less efficient code. This is an example:\r\n```Julia\r\nimmutable F elt::Float64 end\r\nimport Base.+\r\n+(a::F, b::F) = F(a.elt+b.elt)\r\n```\r\nI would expect this type `F` to be as efficient as `Float64`. Unfortunately it isn't, as visible in this test:\r\n```Julia\r\nfunction vadd!(rs,xs,ys)\r\n    @inbounds @simd for i in eachindex(rs)\r\n        rs[i] = xs[i] + ys[i]\r\n    end\r\nend\r\n```\r\n\r\nJulia produces the following code for this example:\r\n```Julia\r\njulia> code_native(vadd!, (Vector{F}, Vector{F}, Vector{F}))\r\n[...]\r\nSource line: 3\r\nL48:\tmovq\t(%rdx), %rax\r\n\tvmovsd\t(%rax,%rdi,8), %xmm0\r\n\tmovq\t(%rsi), %rax\r\n\tvaddsd\t(%rax,%rdi,8), %xmm0, %xmm0\r\n\tmovq\t(%r8), %rax\r\n\tvmovsd\t%xmm0, (%rax,%rdi,8)\r\nSource line: 74\r\n\tincq\t%rdi\r\nSource line: 75\r\n\tcmpq\t%rdi, %rcx\r\n\tjne\tL48\r\n[...]\r\n```\r\n\r\nWhen I generated code for `Vector{Float64}` instead, then the double indirections (reloading `%rax` at every loop iteration) are not present, and the loop is vectorized. I wonder what causes this, and how it can be addressed.\r\n\r\nThe presence of the double indirections indicates that this may be an aliasing problem: Maybe LLVM cannot determine that the three arrays and the content of the new type `F` don't alias, and thus cannot hoist the respective loads out of the loop?"},"comment":{"url":"https://api.github.com/repos/JuliaLang/julia/issues/comments/140132742","html_url":"https://github.com/JuliaLang/julia/issues/13104#issuecomment-140132742","issue_url":"https://api.github.com/repos/JuliaLang/julia/issues/13104","id":140132742,"user":{"login":"eschnett","id":213514,"avatar_url":"https://avatars.githubusercontent.com/u/213514?v=3","gravatar_id":"","url":"https://api.github.com/users/eschnett","html_url":"https://github.com/eschnett","followers_url":"https://api.github.com/users/eschnett/followers","following_url":"https://api.github.com/users/eschnett/following{/other_user}","gists_url":"https://api.github.com/users/eschnett/gists{/gist_id}","starred_url":"https://api.github.com/users/eschnett/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eschnett/subscriptions","organizations_url":"https://api.github.com/users/eschnett/orgs","repos_url":"https://api.github.com/users/eschnett/repos","events_url":"https://api.github.com/users/eschnett/events{/privacy}","received_events_url":"https://api.github.com/users/eschnett/received_events","type":"User","site_admin":false},"created_at":"2015-09-14T16:23:49Z","updated_at":"2015-09-14T16:23:49Z","body":"@jrevels Okay. Well, the native code generated by `julia -O` looks harmless enough, meaning that LLVM *should* be able to vectorize the bitcode that produced it. So either the annotations added by `@simd` somehow get lost, or all that's missing is running another LLVM pass (or running them in a different order)."}}