-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inverted marking of vector tuple type #15244
Conversation
The type could be called 🍌. |
But. This change has only about 20 lines of code! Amazing. Thanks a lot! 👍 |
this would be analogous to the way we treat Float64, Float32, Complex versions of the same, and Signed specially in codegen, so i think there's reasonable precedence for going this route |
Per @StefanKarpinski's suggestion, I tried using
It certainly has the advantage of being unlikely to conflict with user identifiers. I only wish the font wasn't monochrome. |
I see it in spectacular yellow 😁 |
Apple really knows how to sell computers. |
Wow. I'm home and now see the full color on my MacBook. I'm open to replacement names less high up in Unicode. Perhaps |
I'd call it |
The main problem I see with this is that people are likely to encounter mysterious disappearances of data if they use the |
Just load |
This conversation certainly gives new meaning to the phrase "the Julia ecosystem." |
To the substance of this PR: it's certainly not the first approach I would have thought of, but often good ideas aren't. This is probably in the domain of "fiendishly clever." Would we need some kind of promotion to permit operations like The name |
I tried to clean up the use of name comparison but did something wrong. With the second commit, I get an infinite recursion when compiling
@yuyichao 's suggestion looks like what I want to do anyway. (Thanks!) |
With respect to getting values in/out of |
I'm not understanding some point of the boot process. With the latest three commits, I'm getting a failure during the build process. Here's an excerpt:
See here for what I defined in |
Move it below the constructor of |
Thanks! That solved the problem. |
683723d
to
30fb043
Compare
Marking the elements would make SIMD optimization seamlessly compatible with Julia packages which are based on wrapped homogeneous tuple types like FixedSizeArrays . |
FWIW I don't get any packed instructions using this branch, Here is LLVM and generated code: https://gist.github.com/KristofferC/4be0fea644ef22a4b773 |
@KristofferC : It's my fault for updating the pull request and not commenting on a functional change. The update cleaned up the hacky test for Next update will change the name to |
Thanks, it is working now. Experimenting with something like this: import Base.Banana
typealias Vec{N, T} NTuple{N,Base.Banana{T}}
@generated function add{N}(u::Vec{N}, v::Vec{N})
Expr(:tuple, [:(Banana(u[$i].value + v[$i].value)) for i in 1:N]...)
end
code_llvm(add,(Vec{4,Float32},Vec{4,Float32})) it seems a bit brittle. For example code_llvm(add,(Vec{8,Float32},Vec{8,Float32})) does not produce two It would be nice if it "just worked" without having to match the exact register size but maybe it is out of scope for this PR. |
Actually creating a @generated function Base.rand{N, T}(::Type{Vec{N,T}})
Expr(:tuple, [:(Banana(rand(T))) for i in 1:N]...)
end
a = rand(Vec{8,Float32})
signal (11): Segmentation fault
while loading no file, in expression starting on line 0
indexed_next at ./tuple.jl:33
unknown function (ip: 0x7eff2c7b4188)
[inline] at /home/kristoffer/julia/src/julia_internal.h:69
jl_call_method_internal at /home/kristoffer/julia/src/gf.c:1906
send_to_backend at ./REPL.jl:613
unknown function (ip: 0x7f013f4a8655)
.
.
.
Allocations: 4703615 (Pool: 4700646; Big: 2969); GC: 10
Segmentation fault (core dumped) |
30fb043
to
f82117e
Compare
PR updated to use I can replicate the optimization and crash fragility that @KristofferC observes. On the optimization front, I think we'll have to rely on I'll look into the crash problem. The following example works past the
|
Do we (edit: use) |
I personally like |
I was wondering if there was prior art for the Anyone else have a preference? |
CI failure was #15294, restarted
|
Small update, this crashes: julia> ((VecElement(1.0), VecElement(2.0), VecElement(2.0), VecElement(2.0)))
signal (11): Segmentation fault
while loading no file, in expression starting on line 0
[inline] at ./array.jl:391
put! at ./channels.jl:41
unknown function (ip: 0x7fdb3570f2d7)
[inline] at /home/kristoffer/juliacxx/src/julia_internal.h:69 |
b008838
to
5230671
Compare
Today's commits (up to "Allow more sizes...") fix all the crashes that I'm aware of. So feel free to increase my awareness. I have not tackled fixing LLVM for all vector sixes like @eschnett's PR does, though my PR does allow the non-power-of-two sizes that seem to work. |
Given that there are no known crashes, this seems like it may be at a good point to merge and allow additional issues to be fixed in future PRs. If the participants don't object to that, I suggest merging. |
This uses some c++11 features ( |
I'll try to knock it back to C++03. I didn't realize LLVM 3.3 was still in On Thu, Apr 7, 2016 at 1:44 PM, Yichao Yu [email protected] wrote:
|
} | ||
return (Type*)jst->struct_decl; | ||
} | ||
return julia_type_to_llvm(jt, isboxed); | ||
} | ||
|
||
// Returns 0 if no special rule applies | ||
unsigned jl_llvm_special_tuple_alignment(jl_tupletype_t *st) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will probably break AOT compilation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain why? (I'm clueless on what ahead of time compilation involves for Julia.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC it allows you to build julia without llvm at runtime.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is part of the run time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the info. Basically I need to add an oracle to the run-time that determines whether LLVM uses a vector, using only Julia type information and not it's mapping to LLVM types. If I call this oracle from the Julia-to-LLVM mapping logic where it decides whether to use an LLVM vector, then there will always be agreement on the answer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How complicated/platform-dependent is the LLVM logic used here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tricky part is that currently the tuple type is used if all the elements have the same LLVM type and the LLVM type is a scalar type. I'll have to cut that back to using a tuple only if all the elements have the same Julia type, or all are pointers. And make an estimate on whether the Julia element type maps to an LLVM scalar type (seems straightforward).
I suspect the pointer case isn't interesting, though AVX-512 and a creative mind will prove me wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have to cut that back to using a tuple only if all the elements have the same Julia type, or all are pointers. And make an estimate on whether the Julia element type maps to an LLVM scalar type (seems straightforward).
I think it is better to do that anyway since it will be easier to describe what our ABI is. If it matters, we can treat non floating point bitstype
with the same size as the same scalar integer type when deciding whether it is a homogeneous vectorizable tuple.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Latest revision fixes the AOT issue per discussion. test/vecelement.jl
tests all the types of interest, and there's an assertion in cgutils.cpp
to catch disagreements between Julia and LLVM about the alignment of a struct.
I tried compiling with:
and got lots of errors in |
I did a few days ago but it required manually adding |
Since @tkelman's remarks indicate that we've bought into using C++11 even when compiling with LLVM 3.3, there seems to be no point in changing |
Should be fine.... Supplying |
it still works on clang / osx, so i hadn't noticed any llvm3.3 breakage. i haven't had a reason to test on linux recently. but iirc, using |
Something went astray with my last pull/merge. Please ignore latest update until I straighten it out. |
b208328
to
1388b2a
Compare
Commits squashed. If the checks pass, I suggest giving the changes a final review and merging if it looks good. |
// It is currently unused, but might be used in the future for a more precise answer. | ||
static unsigned julia_alignment(Value* /*ptr*/, jl_value_t *jltype, unsigned alignment) { | ||
if (!alignment && ((jl_datatype_t*)jltype)->alignment > MAX_ALIGN) { | ||
// Type's natural alignment exceeds strictess alignment promised in heap, so return the heap alignment. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strictest?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. Now fixed.
lgtm. Can I ask that you also write a NEWS entry and some documentation on VecElement to the stdlib, mention it in the Julia-to-C mapping table (http://docs.julialang.org/en/latest/manual/calling-c-and-fortran-code/#bits-types), and perhaps put some usage examples somewhere in the manual (maybe in http://docs.julialang.org/en/latest/manual/performance-tips/?). I don't think that needs to hold up merging this though. Thanks for your persistence in making this happen. |
A VecElement{T} is represented same as a T in LLVM. Furthermore, a homogenous tuple of VecElement{T} is represented as an LLVM vector if allowed by LLVM and number of elements the tuple is 16 or fewer, *and* can be correctly handled as a vector. Adds an assertion and test to check if LLVM and Julia agree on alignment. Feature is designed to work with Ahead-Of-Time compilation too.
Yes, I'll next work on the items that @vtnash suggested. |
This is PR is intended to generate a discussion about a solution to a problem that @eschnett and I were discussing. See here for start of discussion chain. The problem is how to get access to LLVM vector types from Julia. The intent of the PR is to get feedback on whether the inverted approach (5 below) is something we should take forward.
Some approaches to the general problem are:
Approach 5, which sounds upside-down, seems to be the simplest solution. This PR implements it. [Updated 2016-3-1 to reflect update in PR. Original PR called the marked type
Banana
and used "pre-peeled" metaphor. Now marked type isVecElement
. Updated example usestypealias
to retain discussion context.] Example:The PR causes two special mappings for the example:
Banana{T}
maps to the LLVM type for a T, not an LLVM struct containing the LLVM representation of T. In other words, bananas are pre-peeled in LLVM.Banana{T}
maps to an LLVM vector of T. I.e., an LLVM vector is used instead of an array.The pre-peeling rule ensures that a
Banana{T}
is mapped consistently regardless of surrounding context.Below is an example that uses the definitions above:
At -O3, the code is:
A library such as SIMD.jl could presumably obtain similar effect without -O via
llvmcall
.